In CSS, we can have control over an element when its content is too big to fit in. The property for that is overflow
, which is a shorthand for overflow-x
and overflow-y
properties.
For this article, I will give an introduction to those properties, and then we will dive together into some concepts and use-cases that are related to overflow. Are you ready? Let’s dive in!
Introduction
To use the overflow property, we need to be sure that the element we’re applying it to has the following:
- Block-level element (eg:
div
,section
) with a height set viaheight
ormax-height
. By set height, I mean that the item should have content (not empty), not to add an explicit height. - Or an element with
white-space
set tonowrap
.
Possible Keywords For Overflow
The overflow
property can accept the following possible values:
visible, hidden, scroll, auto
.element {
height: 200px;
overflow: [overflow-x] [overflow-y];
}
Since overflow
is a short hand property, it can accept one or two values. The first value is for the horizontal axis, and the second one is for the vertical axis.
Visible
The default value, where the content can extend beyond its parent. It can be set like:
.element {
height: 200px;
overflow: visible;
}
An interesting fact that you should know is that when one axis is set to visible
, and another axis is set to auto
, the axis with visible
will compute to the auto
keyword.
According to Mozilla Developer Network MDN:
Setting one axis to visible (the default) while setting the other to a different value results in visible behaving as auto.
For example, if we set an element with the following:
.element {
height: 200px;
overflow: visible auto;
}
The overflow
property computed value will be auto auto
.
Hidden
When content is longer than its parent, it will be clipped. However, the content can be scrolled by using Javascript.
Scroll
The scroll value Allows scrolling to reveal the clipped content, and it can be horizontal or vertical.
In the figure above, the scrollbar is always visible regardless if the content is long or not. Note that this depends on the operating system.
Auto
I consider this a smart keyword! It shows the scrollbar only if the content is longer than its container.
Notice that in the figure, the scrollbar is only visible in case the content is longer than its container. Next, we will go through the longhand properties that are related to overflow
.
overflow-x
This is responsible for the x-axis, or the horizontal sides of an element.
overflow-y
This is responsible for the y-axis, or the vertical sides of an element.
Use Cases and Examples
Simple Slider
We can create a quick and simple slider by clipping the content horizontally and allowing it to scroll.
In the mockup above, we have cards that laid out horizontally, and there is a scrollbar that allows us to scroll and reveal more content. To implement that, we will need to do the following:
- Display the cards in the same line. I will use
flexbox
for that. - Add
overflow-x
to the container.
.wrapper {
display: flex;
overflow-x: auto;
}
And it works on desktop browsers. However, while testing this on Safari for iOS (12.4.1), the scrolling didn’t work. After some trial and error, the scrolling worked when I added width to the child items. It works without issues for iOS (13.3).
Modal Content
When the modal content is too long, we can easily make the area scrollable. To accomplish that, we should have the following:
- Maximum height for the modal.
- The modal body should take the full available space.
.modal {
display: flex;
flex-direction: column;
max-height: 400px;
max-width: 450px;
}
/* 1. Letting the modal body take the remaining available space */
/* 2. Allow scrolling if the content is long. I used auto because it won't show a scrollbar until the content is long enough. */
.modal__content {
flex-grow: 1; /* [1] */
overflow-y: auto; /* [1] */
}
A Card With Rounded Edges
When we have a card and we want its corners to be rounded, we tend to do add border-radius
for the top and bottom corners as below:
.card-image {
border-top-right-radius: 7px;
border-top-left-radius: 7px;
}
.card-content {
border-bottom-right-radius: 7px;
border-bottom-left-radius: 7px;
}
This could be a lot of work, especially if the card has a different design on mobile. For example, instead of stacking its child items, they will be next to each other.
For that case, it’s good to use overflow: hidden
on the wrapper, and then add border-radius
to it. See below:
.card {
overflow: hidden;
border-radius: 7px;
}
However, this solution has some caveats that might make it perfect for all cases. Please test properly.
Text Truncation
To account for long content, we can truncate the text by using text-overflow
property.
On the element we want it to truncate, I added the following:
.user__name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
And that’s it! Notice that overflow: hidden
is important for that to work.
Animations
When it comes to animation, the benefit of overflow: hidden
lies in clipping hidden elements that can be shown on hover. Consider the figure below:
In CSS, it will look like this:
.button.slide-left {
overflow: hidden;
}
.button.slide-left:after {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #000;
opacity: 0.25;
border-radius: 100px;
transform: translateX(-100%);
transition: 0.2s ease-in;
}
We have two buttons and each one has a pseudo-element that is translated to the left and bottom, accordingly. See the video below:
Common Issues With Overflow
Scrolling On Mobile
When we have a slider, for example, it’s not enough to add overflow-x
and call it a day. On Chrome iOS, we need to keep scrolling and moving the content manually. See the video below:
Luckily, there is a property that can enhance the scrolling experience.
.wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
This is called momentum-based scrolling. According to MDN:
where the content continues to scroll for a while after finishing the scroll gesture and removing your finger from the touchscreen.
Here is how the result looks with the momentum-based scrolling.
Inline Block Elements
As per the CSS spec:
The baseline of an ‘inline-block’ is the baseline of its last line box in the normal flow unless it has either no in-flow line boxes or if its ‘overflow’ property has a computed value other than ‘visible’, in which case the baseline is the bottom margin edge.
When an inline-block
element has overflow
value other than visible
, this will cause the bottom edge of the element to be aligned based on the text baseline of its siblings.
Consider the following example.
To solve that issue, we should change the alignment of the button that has overflow: hidden
.
.button {
vertical-align: top;
}
Horizontal Scrolling Issues
Often times, we face the issue of horizontal scrolling and it gets harder when the reason is unknown. In this section, I will list some common causes for horizontal scrolling so you can account for them while building layouts.
Elements That Are Absolutely/Fixed Positioned
When there is an element that has a position value of absolute
or fixed
, there is a possibility for it to cause horizontal scrolling. This can happen when one of the left
, right
values is positioning the element outside the body element.
To solve that, you need to check why this element is positioned outside the viewport in the first place. If it’s not necessary, then it has to be removed or the position value should be edited.
Grid Items
CSS grid has three cases that can lead to horizontal scrolling. Let’s see them.
Using Pixel Values For Columns
When using pixel values, this will cause issues when the viewport width is small. See below:
.wrapper {
display: grid;
grid-template-columns: 200px 1fr;
grid-gap: 1rem;
}
The solution is to reset the columns and only use the one above on viewports that have enough space.
.wrapper {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}
@media (min-width: 400px) {
grid-template-columns: 200px 1fr;
}
Using minmax()
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-gap: 1rem;
}
It might be tempting to forget about testing this for mobile, as it will cause horizontal scrolling at some point since the minimum width is 300px
.
A simple fix for that is to reset the grid-template-columns
to 1fr
and on changing it when the viewport is larger.
.wrapper {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}
@media (min-width: 400px) {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
Using Percentages Instead of The Fraction Unit
As per this tweet by Jake Archibald, if we used a percentage for the grid columns, and then added a grid-gap
, this will cause horizontal scrolling. The reason is that the grid-gap
value is added to the width of the container.
.wrapper {
display: grid;
grid-template-columns: repeat(4, 25%);
grid-gap: 10px;
}
To fix that, avoid using percentages for the grid columns, and use 1fr
instead. When used, the grid-gap
will deduct from the available space.
Flex Wrap
For flex items, it’s important to add flex-wrap
to the container or things might get messy for smaller viewports.
.wrapper {
display: flex;
}
The above is not enough. Make sure to add flex-wrap
to avoid any unexpected overflows.
.wrapper {
display: flex;
flex-wrap: wrap;
}
Long Words or Links
When dealing with long words or links that are placed within content, it should break to a new line or otherwise, you guessed it! There will be a horizontal scrolling.
To fix that, we need to break long words and links. Here is how we can do it:
.post-content a {
word-wrap: break-word;
}
Or we can use text-overflow
:
.post-content a {
overflow: hidden;
text-overflow: ellipsis;
}
Images Without max-width: 100%
Set on Them
If you’re someone who doesn’t use a CSS reset, you might accidentally forget to use max-width: 100%
for all img
s as this will make them responsive on mobile. If not, this will cause issues. Please test well.
Using Fixed Width
A fixed width can cause problems if used and generally, I try to avoid it as much as I can. If it’s really necessary, then it’s better to use it with max-width
, so if space is not enough for the width
value, then the max-width
will do the work.
.element {
width: 800px;
}
Adding max-width
will avoid any horizontal scrolling.
.element {
width: 800px;
max-width: 100%;
}
How To Debug Horizontal Scrolling Issues
Now that we know the causes of horizontal scrolling, I will explain some ways that can help us identify those issues and solve them.
Use CSS Outline
This is the first thing that I usually do to debug.
*,
*:before,
*:after {
outline: solid 1px #000;
}
By adding that, we can notice which elements that have a big width so we can solve the issue. Addy Osmani took this further with his simple script:
;[].forEach.call(document.querySelectorAll("*"), function (a) {
a.style.outline =
"1px solid #" + (~~(Math.random() * (1 << 24))).toString(16)
})
What this script does is that it randomizes the outline colors, which will make it easier instead of having all the outlines with a single color.
Firefox scroll
Label
In Firefox, there is a little label added to elements that cause horizontal scrolling. Isn’t that awesome?
Deleting Elements
Sometimes, the techniques above don’t work. What I do in that case is to open up the DevTools, and then I start deleting elements and notice. Once the horizontal scrolling is gone, I can identify the element that is causing the issue.
Please Make overflow-x: hidden
Your Last Solution
Lastly, you can use overflow-x: hidden
to solve the issue of horizontal scrolling, but please make that your last option.
Related Articles
- Handling Long and Unexpected Content in CSS
- Handling Long Words and URLs (Forcing Breaks, Hyphenation, Ellipsis, etc)
- Finding/Fixing Unintended Body Overflow
The End
That’s a wrap. Do you have a comment or a suggestion? Please feel free to ping me on @shadeed9.