I just saw that my previous article on magical kittencorns and CSS animations worked out to an 18 minute read. Which is apparently terrible for getting people to read the whole thing. Good thing I’m the one reading my own articles, huh?
Anyway, this is a really short one, which was borne out of a discussion with my mate, Wei, about use of padding in a flex formatting context. Because that’s what friends talk about in casual conversation.
But I think it is a fairly common problem which people may run into so here’s a write-up.
Scenario
If you have tried to apply padding to a flex container with an horizontal overflow behaviour of scroll, you might notice that the padding is not applied to the flex end side of your container.
This is because the available space allocated to flex items by the browser under such circumstances is: the width of flex container’s containing block minus its margin, border and padding in the horizontal direction.
The relevant section of the specification is CSS Flexible Box Layout Module Level 1: 9.2 Line Sizing
Update:
Konstantin Rouda and Šime Vidas raised the point that my original explanation didn't really explain why there is start padding but no end padding. And upon further digging, I found a long standing dispute about how overflow content should be handled while considering the constraints of Web-compat.
This is not an issue that only affects Flexbox layouts, it affects scroll containers with block and inline children differently as well. CSS2.1 was not clear about overflow, and that probably resulted in different browser vendors implementing different behaviour. For example, Webkit had (has?) different policies for block children and inline children.
From the GitHub issue [css-overflow-3] Clarify padding-bottom in overflow content, fantasai commented that:
I think historically the issue is that browsers didn't want to trigger scrollbars for overflow: auto unless visible content was overflowing the inner border edge, so they didn't count padding.
Things have not been resolved yet, and anyone who is interested can read through the following relevant links:
- Bug 748518 padding-bottom/right(block-end/inline-end) is ignored with overflow:auto/scroll because it extends in from the border-box rather than out from the scrollable area
- [css-grid-1] Include padding in scrollable overflow area
- [css-overflow-3] Clarify padding-bottom in overflow content
- CSS Overflow Module Level 3
- Bug 1527949 Implement whatever more-interoperable behavior the CSSWG comes up with, for making "end" padding scrollable on scrollable elements
However, having items in a scrolling container with padding is a relatively common situation and there are a couple of workarounds to achieve the desired effect. Both workarounds are sort of hacks though. Here’s the markup for a basic flex container with some items in it.
<div class="flex">
<div class="flex__item card">
<img src="http://placekitten.com/150/150">
<div class="card__txt">
<h3>Sleep more</h3>
</div>
</div>
<div class="flex__item card">
<img src="http://placekitten.com/150/150">
<div class="card__txt">
<h3>Sleep more</h3>
</div>
</div>
<!–– repeat for like 10 more cards ––>
</div>
Using border
One option is to style up the border so it looks like padding around the items in the container.
.border {
border: 1em #4abc41 solid;
}
A potential downside to this solution is the position of the scrollbar. Depending on the operating system, this may or may not be an issue. For example, on Windows (screenshot shown below), it is fairly obvious. On Android, the scrollbar is barely noticeable.
I’d like to take this opportunity to talk about the CSS Scrollbars Module Level 1 specification which is currently an Editor’s Draft. It introduces 2 new CSS properties for scrollbar styling, scrollbar-color
and scrollbar-width
. Firefox has supported them since version 64.
More information written up in Issue № 1022 of Web Platform News.
Using the ::after
pseudo-element
Another option is to utilise the ::after
pseudo-element on the flex container. ::before
and ::after
are generated content, and are inserted just inside their associated element. In other words, it will be rendered as a child element inside the flex container.
.pseudo-elem {
padding: 1em;
&::after {
content: '';
padding: 0.5em;
}
}
You do have to make sure that the padding on the ::after
pseudo-element is half that of the padding used on the flex container.
Wrapping up
I promised this would be short. Anyway, if you want to take a look at the code and mess around with it. Or even better, add to the list of workarounds, please feel free to do so. And ping me with your solution!