The problem
I was recently asked: "Show the percentage on the progress bar, but only if it's at least 30 pixels tall." In other words, I was tasked to hide some content if the the container wasn't tall enough.
Now, the first thing that I thought was: "Shoot, it would be the perfect task for element queries..." But we're not going to get those anytime soon.
Alternatively, I could use a library like this one or good ol' eq.js, but I wondered if that could be achieved with just CSS.
I found out it could be done.
The solution
I don't want to bore you, so here you go:
Why it works
This is basically the same principle of breaking lines of text: the container isn't wide enough, so the rest of the text goes on a new line.
But if we limit the height of the paragraph to just the first line (with something like height: 1lh
- what's lh
?) and hide the overflown content, we can hide the content if the container isn't wide enough:
Flexing the layout
But we're not dealing with just text. Fortunately, we can use the same logic in a flex container:
<div>
<span>Lorem</span>
<span>ipsum</span>
</div>
div {
display: flex;
flex-wrap: wrap;
}
So, if the second <span>
can't fit the first line, it's placed in the row below.
Shift the axis
We've talked about width so far, but the initial problem had a height costraint. That's where flex-direction: column
comes into play: this way, if the second <span>
can't fit the first column, it's moved on the right.
In the end, the second <span>
contains the content we want to hide. We don't care about the first one, so it could also be empty. Even better, we can avoid using a <span>
altogether and use a pseudo-element instead:
div {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
div::before {
content: '';
width: 100%;
}
Note that we need that first, empty content, or else the content we want to hide would just sit on the top. And we also need to declare width: 100%
because without any size on the cross axis it'd like the element isn't even there.
Wrapping up
What happens when the height isn't enough, then? Our content is pushed outside of our container, as it's clear in this screenshot (I painted the pseudo-element yellow to highlight its role - but normally its height is zero):
Now all we have to do is to declare overflow: hidden
and we're golden.
Hidden ≠ not rendered
My final warning is that you should be aware that hidden content isn't the same as not rendered or inert. Which means that it's not the same as display: none
or <template>
elements. In a nutshell, images and other media still get downloaded.
Conclusions
My good friend Giacomo Zinetti has pushed this kind of tricks to another level to mimic media and element queries. For example:
The previous warning still applies, but it's impressive how we can go far without using expensive queries.
Have a nice CSS, folks! 👋
Top comments (0)