A CSS-Only Overflow Indicator for Multiline Text
When building archive.observer, a page for browsing the AskHistorians subreddit archives, I wanted to preview the text for each post in a list:
Posts in that subreddit can be quite long, so I wanted to truncate the preview to a fixed number of lines. If that happened, I needed an indicator showing that there was more text available to read. I settled for a “fadeout” effect:
In this post, I’ll show you how to implement this indicator, along with a little trick that makes sure it works in all of these cases:
- The indicator is only shown if the text actually overflows its container.
- It works for multiple lines of text (many techniques documented elsewhere don’t).
- If the text needs less space than the maximum height, the container shrinks to fit the text.
The Code
This is the code we’ll produce:
.hide-overflow {
position: relative;
max-height: 15.75rem;
overflow: hidden;
}
.hide-overflow::after {
position: absolute;
height: 5.25rem;
left: 0;
right: 0;
background: linear-gradient(transparent, white);
content: " ";
pointer-events: none;
/* If text is shorter than max-height, push the
overflow indicator down so it's hidden by the overflow. */
bottom: calc((100% - 15.75rem) * 20);
}
It assumes a HTML structure like this:
<div class="hide-overflow">
<p>
Lorem Ipsum dolor sit amet...
</p>
</div>
Walkthrough
The CSS is mostly a standard affair. We give the container a class, set a max-height and hide the overflow:
.hide-overflow {
position: relative;
max-height: 15rem;
overflow: hidden;
}
Using position: relative
allows us to position the ::after
pseudo-element relative to the bottom edges of our container:
.hide-overflow::after {
position: absolute;
height: 5rem;
left: 0;
right: 0;
bottom: 0;
/* ... */
}
So far, so good. Let’s make the indicator visible using a simple gradient:
.hide-overflow::after {
/* ... */
background: linear-gradient(transparent, white);
content: " ";
pointer-events: none;
/* ... */
}
pointer-events: none
ensures that users can still select text below the indicator.
Here’s the trick. We change the bottom
style to actually hide this indicator when the text fits inside the containers max-height
:
.hide-overflow::after {
/* ... */
bottom: calc((100% - 15rem) * 20);
}
100% - 15rem
is the key: This expression is lower than zero if the actual height of the container (100%
) is smaller than its maximum height (15rem
), meaning the text didn’t overflow the container. If it is lower than zero, we multiply it by an arbitrarily large number (in this example it’s 20) to move the indicator below the bottom edge of the container, effectively hiding it. The whole thing is basically a roundabout way of using calc
to “detect” if there’s any text overflow.
Here’s an example showing the position of the hidden indicator in green. In this case, the bottom
property has a computed value of -160px
:
Conclusion
It took me a little while to work out this trick and I found no alternatives with similar features on the web; Even though it’s a hackish workaround, I’m quite fond of its simplicity, and I think other websites might profit from it as well. Reddit, for example, seems to use JS to determine whether the overflow indicator should be visible or not.
I tried to implement the indicator using container queries, but couldn’t get around some of their limitations.