You get a nice-looking design handed to you and it has this good huge hero part, adopted by a kind of three-up columns proper beneath it. You recognize, like virtually each different web site you’ve ever labored on.
You bang by means of the hero part and get to work on the three-column part. It’s time to drag out our trusty good friend flexbox! Besides, you write show: flex and also you get this mess as a substitute of getting the three equal columns you’d anticipate.
This occurs due to how flexbox calculates the bottom measurement of a component. You’ve in all probability learn a lot of flexbox tutorials, and plenty of of them (together with my very own) are an excessively simplistic instance of what flexbox does with out actually digging into the complicated issues that flexbox does for us that we take as a right.
I’m constructive you’ve seen examples and tutorials that have a look at one thing like this, the place three divs shrink down across the content material that’s inside them:
In different phrases, we get some block-level parts shrinking down and slotting subsequent to at least one one other. It appears like flex desires issues to be as small as attainable. However in actuality, flexbox really desires issues to be as huge as attainable.
Wait, what? Flex shrinks issues by default — that may’t be proper! Proper?
As superior as flexbox is, what it’s doing beneath the hood is definitely just a little unusual as a result of, by default, it’s doing two issues directly. It first appears on the content material measurement which is what we’d get if by declaring width: max-content on a component. However on prime of that, flex-shrink can also be doing a little work permitting the gadgets to be smaller, however solely if wanted.
To essentially perceive what’s happening, let’s break these two down and see how they work collectively.
Diving into max-content
max-content is a reasonably helpful property worth in sure conditions, however we need to perceive the way it works on this explicit state of affairs the place we try to get three seemingly easy equal columns. So let’s strip away flexbox for a second and have a look at what max-content does by itself.
MDN does a great job of explaining it:
The max-content sizing key phrase represents the intrinsic most width of the content material. For textual content content material because of this the content material won’t wrap in any respect even when it causes overflows.
Intrinsic may throw you off right here, but it surely mainly means we’re letting the content material resolve on the width, somewhat than us explicitly setting a set width. Uri Shaked aptly describes the habits by saying “the browser pretends it has infinite house, and lays all of the textual content in a single line whereas measuring its width.”
So, backside line, max-content permits the content material itself to outline the width of the aspect. When you have a paragraph, the width of that paragraph would be the textual content inside it with none line breaks. If it’s an extended sufficient paragraph, then you find yourself with some horizontal scrolling.
Let’s revisit that overly-simplistic instance of three block-level parts that shrink down and slot subsequent to at least one one other. That isn’t taking place due to flex-shrink; it’s taking place as a result of that’s the scale of these parts when their declared width is max-content. That’s actually as huge as they go as a result of that’s as huge because the mixed content material inside every aspect.
Right here, check out these parts with out flexbox doing it’s flexbox stuff, however with a width: max-content on there as a substitute:
So, when there’s only a small quantity of textual content, the intrinsic max-content shrinks issues down as a substitute of flex-shrink. After all, flexbox additionally is available in with it’s default flex-direction: row habits which turns the flex gadgets into columns, placing them proper subsequent to at least one one other. Right here’s one other look however with the free house highlighted.
Including flex-shrink to the equation
So we see that declaring show: flex pushes that max-content intrinsic measurement on flex gadgets. These gadgets need to be as huge as their content material. However there’s one other default that is available in right here as nicely, which is flex-shrink.
flex-shrink is mainly all of the flex gadgets in a versatile container to make positive they don’t overflow the mother or father. If the flex gadgets can all match subsequent to one another with out overflowing the versatile container, then flex-shrink gained’t do something in any respect… it’s job is already completed.
But when the flex gadgets do overflow the container (due to that max-content intrinsic width factor), the flex gadgets are allowed to shrink to forestall that overflow as a result of flex-shrink is searching for that.
That is why flex-shrink has a default worth of 1. With out it, issues would get messy fairly shortly.
Right here’s why the columns aren’t equal
Going again to our design state of affairs the place we want three equal columns beneath a hero, we noticed that the columns aren’t equal widths. That’s as a result of flexbox begins by trying on the content material measurement of every flex merchandise earlier than even fascinated about shrinking them.
Utilizing Firefox’s DevTools (as a result of it’s bought some distinctive flexbox visualizations that others don’t), we will really see how flexbox is calculating all the things.
For simplicity’s sake, as we dive deeper into this, let’s work with some good spherical numbers. We will do that by declaring widths on our flex gadgets. After we declare a width on a flex merchandise, we throw that intrinsic measurement out the window, as we’ve now declared an express worth as a substitute. This makes determining what’s actually happening loads simpler.
Within the Pen beneath, now we have a mother or father that’s a 600px huge versatile container (show: flex). I’ve eliminated something that may affect the numbers, so no hole or padding. I’ve additionally switched out the border for a top level view so we will nonetheless visualize all the things simply.
The primary and third flex gadgets have a width: 300px and the center one a width: 600px. If we add that each one up, it’s a complete of 1200px. That’s larger than the the 600px obtainable inside the mother or father, so flex-shrink kicks in.
flex-shrink is a ratio. If all the things has the identical flex-shrink (which is 1 by default), all of them shrink on the identical price. That doesn’t imply all of them shrink to the identical measurement or by the identical quantity, however all of them shrink on the identical price.
If we leap again into Firefox DevTools, we will see the bottom measurement, the flex-shrink and the ultimate measurement. On this case, the 2 300px parts at the moment are 150px, and the 600px one is now 300px.
If we add up all the bottom sizes of all three flex gadgets (the precise widths we declared on them), the whole comes out to 1200px. Our flex container is 600px huge. If we divide all the things by 2, it suits! They’re all shrinking by the identical price, dividing their very own widths by 2.
It’s not typically that now we have good spherical numbers like that in the actual world, however I believe this does a pleasant job illustrating how flexbox does what it does when determining how huge to make issues.
Getting the columns to be equal
There are just a few other ways to get the three columns we need to be equal in width, however some are higher than others. For all of the approaches, the fundamental thought is that we need to get all of the columns base measurement to be the identical. If they’ve an equal base measurement, then they may shrink (or develop, if we use flex-grow) at an equal price when flexbox does it’s flex issues, and in principle, that ought to make them the identical measurement.
There are just a few frequent methods to do that, however as I found whereas diving into all of this, I’ve come to consider these approaches are flawed. Let’s have a look at two of the most typical options that I see used within the wild, and I’ll clarify why they don’t work.
Methodology 1: Utilizing flex: 1
A technique we will attempt to get all of the flex gadgets to have the identical base measurement is by declaring flex: 1 on all of them:
.flex-parent { show: flex; }
.flex-parent > * { flex: 1; }
In a tutorial I made as soon as, I used a special method, and I should have had 100 folks asking why I wasn’t utilizing flex: 1 as a substitute. I replied by saying I didn’t need to dive into the flex shorthand property. However then I used flex: 1 in a brand new demo, and to my shock, it didn’t work.
The columns weren’t equal.
The center column right here is bigger than the opposite two. It’s not by a ton, however the entire design sample I’m creating is simply so you’ve got completely equal columns each single time, whatever the content material.
So why didn’t it work on this state of affairs? The perpetrator right here is the padding on the element within the center column.
And perhaps you’ll say it’s foolish so as to add padding to one of many gadgets and never the others, or that we will nest issues (we’ll get to that). In my view, although, I ought to be capable of have a structure that works whatever the content material that we’re placing in it. The net is all about parts that we will plug and play nowadays, in any case.
After I first set this up, I used to be positive it might work, and seeing this challenge pop up made me need to study what was actually happening right here.
The flex shorthand does extra than simply set the flex-grow: 1. In case you don’t already know, flex is shorthand for flex-grow, flex-shrink, and flex-basis.
The default values for these constituent properties are:
.selector {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
I’m not going to deep dive flex-basis on this article, as that’s one thing Robin has already completed nicely. For now, we will consider it like width to maintain issues easy since we aren’t enjoying with flex-direction.
We’ve already seen how flex-shrink works. flex-grow is the other. If the scale of all of the flex gadgets alongside the principle axis is smaller than the mother or father, they’ll develop to fill that house.
So by default, flex gadgets:
don’t develop;if they might in any other case overflow the mother or father, they’re allowed to shrink;their width acts like max-content.
Placing that each one collectively, the flex shorthand defaults to:
.selector {
flex: 0 1 auto;
}
The enjoyable factor with the flex shorthand is you possibly can omit values. So, after we declare flex: 1, it’s setting the primary worth, flex-grow, to 1, which mainly activates flex-grow.
The unusual factor here’s what occurs to the values that you just omit. You’d anticipate them to remain at their defaults, however they don’t. Earlier than we get to what occurs, although, let’s first dive into what flex-grow even does.
As we’ve seen, flex-shrink permits parts to shrink if their base sizes add as much as a computed worth that’s larger than the obtainable width of the mother or father container. flex-grow is the other. If the grand complete of the aspect base sizes is smaller than the worth of the mother or father container’s width, then they may develop to fill the obtainable house.
If we take that tremendous fundamental instance the place now we have three small divs subsequent to at least one one other and add flex-grow: 1, they develop to fill that leftover house.
But when now we have three divs with unequal widths — like these ones we began with — including flex-grow to them gained’t do something in any respect. They gained’t develop as a result of they’re already taking over all of the obtainable house —a lot house, in reality, that flex-shrink must kick in and shrink them down to suit!
However, as people have identified to me, setting flex: 1 can work to create equal columns. Effectively, kind of, as we noticed above! In easy conditions it does work although, as you possibly can see beneath.
After we declare flex: 1 it really works as a result of, not solely does this set the flex-grow to 1, but it surely additionally adjustments the flex-basis!
.selector {
flex: 1;
/* flex-grow: 1; */
/* flex-shrink: 1; */
/* flex-basis: 0%; Wait what? */
}
Yup, setting flex: 1 units the flex-basis to 0%. This overwrites that intrinsic sizing we had earlier than that behaved like max-content. All of our flex-items now need to have a base measurement of 0!
Wanting on the expanded view of the flex: 1 shorthand in DevTools reveals us that the flex-basis has modified to 0
So their base sizes are 0 now, however due to the flex-grow, they’ll all develop to refill the empty house. And actually, on this case, flex-shrink is not doing something, as all of the flex gadgets now have a width of 0, and are rising to fill the obtainable house.
FireFox’s DevTools exhibiting a component with flex: 1 has a content material measurement of 0 and is rising to fill the obtainable house.
Identical to the shrink instance earlier than, we’re taking the house that’s obtainable, and letting all of the flex gadgets develop at an equal price. Since they’re all a base width of 0, rising at an equal price means the obtainable house is equally divided between them and so they all have the identical closing measurement!
Besides, as we noticed, that’s not at all times the case…
The rationale for it is because, when flexbox does all these items and distributes the house, whether or not it’s shrinking or rising a flex merchandise, it’s trying on the content material measurement of the aspect. In case you bear in mind again to the field mannequin, now we have the content material measurement itself, then the padding, border, and margin outdoors of that.
And no, I didn’t neglect * { box-sizing: border-box; }.
That is a kind of unusual quirks of CSS but it surely does make sense. If the browser appeared on the width of these parts and included their padding and borders within the calculations, how may it shrink issues down? Both the padding would additionally should shrink or issues are going to overflow the house. Each of these conditions are horrible, so as a substitute of trying on the box-size of parts when calculating the bottom measurement of them, it solely appears on the content-box!
So, setting flex: 1 causes an issue in instances the place you’ve got borders or padding on a few of your parts. I now have three parts which have a content-size of 0, however my center one has padding on it. If we didn’t have that padding, we’d have the identical math we did after we checked out how flex-shrink works.
A mother or father that’s 600px and three flex gadgets with a width of 0px. All of them have a flex-grow: 1 in order that they develop at an equal price, and so they every find yourself 200px huge. However the padding mucks all of it up. As an alternative, I find yourself with three divs with a content material measurement of 0, however the center one has padding: 1rem. Which means it has a content material measurement of 0, plus 32px padding as nicely.
Now we have 600 – 32 = 568px to divide equally, as a substitute of 600px. All of the divs need to develop at an equal price, so 568 / 3 = 189.3333px.
And that’s what occurs!
However… bear in mind, that’s their content material measurement, not the whole width! That leaves us with two divs with a width of 189.333px, and one other with a which of 189.333px + 32 = 221.333px. That’s a reasonably substantial distinction!
Methodology 2: flex-basis: 100%
I’ve at all times dealt with this like this:
.flex-parent {
show: flex;
}
.flex-parent > * {
flex-basis: 100%;
}
I believed this labored for the longest time. Truly, this was purported to be my closing resolution after exhibiting that flex: 1 doesn’t work. However whereas I used to be writing this text, I noticed it additionally falls into the identical drawback, but it surely’s loads much less apparent. Sufficient in order that I didn’t discover it with my eyes.
The weather are all attempting to be 100% width, that means all of them need to match the width of the mother or father, which, once more, is 600px (and in regular circumstances, is commonly a lot larger, which additional reduces the perceivable distinction).
The factor is that 100% consists of the padding within the computed values (due to * { box-size: border-box; }, which for the sake of this text, I’m assuming everyone seems to be utilizing). So, the outer divs find yourself with a content material measurement of 600px, whereas the center div finally ends up with a content material measurement of 600 – 32 = 568px.
When the browser is understanding methods to evenly divide the house, it isn’t methods to evenly squish 1800px right into a 600px house, however somewhat it’s methods to squish 1768px. Plus, as we noticed earlier, flex gadgets don’t shrink by the identical quantity, however at an equal tempo! So, the aspect with padding shrinks barely much less in complete than the others do.
This leads to the .card having a closing width of 214.483px whereas the others clock in at 192.75px. Once more, this results in unequal width values, although the distinction is smaller than we noticed with the flex: 1 resolution.
Why CSS Grid is the higher selection right here
Whereas all this can be a little irritating (and even just a little complicated), all of it occurs for a great purpose. If margins, padding, or borders modified sizes when flex will get concerned, it might be a nightmare.
And perhaps because of this CSS Grid may be a greater resolution to this actually frequent design sample.
I’ve lengthy thought that flexbox was simpler to select up and begin utilizing than grid, however grid offers you extra final management in the long term, however that it’s loads more durable to determine. I’ve modified my thoughts on that not too long ago although, and I believe not solely does grid give us higher management in the sort of state of affairs, but it surely’s really extra intuitive as nicely.
Usually, after we use grid, we explicitly declare our columns utilizing grid-template-columns. We don’t have to try this although. We will make it behave loads like flexbox does by utilizing grid-auto-flow: column.
.grid-container {
show: grid;
grid-auto-flow: column;
}
Identical to that, we find yourself with the identical sort of habits as throwing show: flex on there. Like flex, the columns can doubtlessly be unbalanced, however the benefit with grid is that the mother or father has complete management over all the things. So, somewhat than the content material of the gadgets having an influence like they might in flexbox, we solely want yet one more line of code and we will resolve the issue:
.grid-container {
show: grid;
grid-auto-flow: column;
grid-auto-columns: 1fr;
}
I really like that that is all on the mother or father selector, and that we don’t have to pick the kids to assist get the structure that we’re after!
The fascinating factor right here is how fr items work. They’re actually known as “flex items” within the spec, and so they work similar to flexbox does in dividing up house;. The massive distinction: they’re trying on the different tracks to find out how a lot house they’ve, paying no consideration to the content material inside these tracks.
That’s the actual magic right here. By declaring grid-auto-columns: 1fr, we’re in essence saying, “by default, all my columns ought to have an equal width,” which is what we’ve been after from the beginning!
However what about at small screens?
What I really like with this method is we will hold it tremendous easy:
.grid-container {
show: grid;
hole: 1em;
}
@media (min-width: 35em) {
grid-auto-flow: column;
grid-auto-columns: 1fr;
}
And similar to that, it really works completely. And by declaring show: grid from the beginning, we will embrace the hole to take care of equal spacing, whether or not the kids are rows or columns.
I additionally discover this to be much more intuitive than altering the flex-direction inside a media question to get the same outcome. As a lot as I really like flexbox (and I actually do nonetheless assume it has nice use instances), the truth that declaring flex-direction: column creates rows, and vice versa, is just a little counter-intuitive at first look.
And naturally, if you happen to desire rolling with out media queries, there’s nothing stopping you from taking this to the subsequent stage with the assistance of auto-fit, which might be just like setting one thing up with flex-wrap (although not precisely the identical):
.grid-container {
show: grid;
hole: 1em;
grid-template-columns: repeat(auto-fit, minmax(10em, 25em));
}
Making it work with flexbox
I notice that we will get round this with flexbox by nesting the aspect with the padding on it. We’ve completed this since we began making layouts utilizing floats, and Bootstrap actually hammered residence the sort of design sample.
<div class=”container”>
<div class=”row”>
<div class=”col”> <div class=””>… </div>
<div class=”col”> <div class=”element-with-padding”>…</div> </div>
<div class=”col”> … </div>
</div>
</div>
And there’s nothing mistaken with that. It really works! However floats work too, and we’ve stopped utilizing them for layouts as higher options have been launched lately.
One of many causes that I love grid is as a result of we will simplify our markup fairly a bit. Identical to we ditched floats for a greater resolution, I’d no less than wish to folks to maintain an open thoughts that perhaps, simply perhaps, grid may very well be a greater, and extra intuitive resolution for the sort of design sample.
Flexbox nonetheless has it’s place, in fact
I nonetheless love flexbox, however I believe its actual energy comes from instances that we need to depend on the intrinsic width of the flex gadgets, reminiscent of with navigations, or teams of parts, reminiscent of buttons or different gadgets of various width that you just need to go subsequent to at least one one other.
In these conditions, that habits is an asset that makes issues like even spacing between unequal gadgets such a breeze! Flexbox is great, and I’ve no plans to cease utilizing.
In different conditions although, when you end up preventing with how flexbox is attempting to work, perhaps you would flip to grid as a substitute, even when it’s not a typical “second” grid the place you’re informed you ought to be utilizing it for.
Individuals typically inform me that they battle to determine grid as a result of it’s too difficult, and whereas it can be, as we noticed right here, it doesn’t should be.
The submit Equal Columns With Flexbox: It’s Extra Difficult Than You Would possibly Assume appeared first on CSS-Tips.
You may assist CSS-Tips by being an MVP Supporter.
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!