When you apply a CSS property to an element, there’s lots of things going on under the hood. For example, let’s say we have some HTML like this:
<div class="parent">
<div class="child">Child</div>
<div class="child">Child</div>
<div class="child">Child</div>
</div>
And then we write some CSS…
.parent {
display: flex;
}
These are technically not the only styles we’re applying when we write that one line of CSS above. In fact, a whole bunch of properties will be applied to the .child
elements here, as if we wrote these styles ourselves:
.child {
flex: 0 1 auto; /* Default flex value */
}
That’s weird! Why do these elements have these extra styles applied to them even though we didn’t write that code? Well, that’s because some properties have defaults that are then intended to be overridden by us. And if we don’t happen to know these styles are being applied when we’re writing CSS, then our layouts can get pretty darn confusing and tough to manage.
That flex
property above is what’s known as a shorthand CSS property. And really what this is doing is setting three separate CSS properties at the same time. So what we wrote above is the same as writing this:
.child {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
So, a shorthand property bundles up a bunch of different CSS properties to make it easier to write multiple properties at once, precisely like the background
property where we can write something like this:
body {
background: url(sweettexture.jpg) top center no-repeat fixed padding-box content-box red;
}
I try to avoid shorthand properties because they can get pretty confusing and I often tend to write the long hand versions just because my brain fails to parse long lines of property values. But it’s recommended to use the shorthand when it comes to flexbox, which is…weird… that is, until you understand that the flex
property is doing a lot of work and each of its sub-properties interact with the others.
Also, the default styles are a good thing because we don’t need to know what these flexbox properties are doing 90% of the time. For example, when I use flexbox, I tend to write something like this:
.parent {
display: flex;
justify-content: space-between;
}
I don’t even need to care about the child elements or what styles have been applied to them, and that’s great! In this case, we’re aligning the child items side-by-side and then spacing them equally between each other. Two lines of CSS gives you a lot of power here and that’s the neatest thing about flexbox and these inherited styles — you don’t have to understand all the complexity under the hood if you just want to do the same thing 90% of the time. It’s remarkably smart because all of that complexity is hidden out of view.
But what if we want to understand how flexbox — including the flex-grow
, flex-shrink
, and flex-basis
properties — actually work? And what cool things can we do with them?
Just go to the CSS-Tricks Almanac. Done!
Just kidding. Let’s start with a quick overview that’s a little bit simplified, and return to the default flex
properties that are applied to child elements:
.child {
flex: 0 1 auto;
}
These default styles are telling that child element how to stretch and expand. But whenever I see it being used or overridden, I find it helpful to think of these shorthand properties like this:
/* This is just how I think about the rule above in my head */
.child {
flex: [flex-grow] [flex-shrink] [flex-basis];
}
/* or... */
.child {
flex: [max] [min] [ideal size];
}
That first value is flex-grow
and it’s set to 0
because, by default, we don’t want our elements to expand at all (most of the time). Instead, we want every element to be dependent on the size of the content within it. Here’s an example:
.parent {
display: flex;
}
I’ve added the contenteditable
property to each .child
element above so you can click into it and type even more content. See how it responds? That’s the default behavior of a flexbox item: flex-grow
is set to 0
because we want the element to grow based on the content inside it.
But! If we were to change the default of the flex-grow
property from 0
to 1
, like this…
.child {
flex: 1 1 auto;
}
Then all the elements will take an equal portion of the .parent
element, but only if the lengths of their contents are the same.
This is exactly the same as writing…
.child {
flex-grow: 1;
}
…and ignoring the other values because those have been set by default anyway. I think this confused me for such a long time when I started working with flexible layouts. I would see code that would add just flex-grow
and wonder where the other styles are coming from. It was like an infuriating murder mystery that I just couldn’t figure out.
Now, if we wanted to make just one of these elements grow more than the others we’d just need to do the following:
.child-three {
flex: 3 1 auto;
}
/* or we could just write... */
.child-three {
flex-grow: 3;
}
Is this weird code to look at even a decade after flexbox landed in browsers? It certainly is for me. I need extra brain power to say, “Ah, max, min, ideal size,” when I’m reading the shorthand, but it does get easier over time. Anyway, in the example above, the first two child elements will take up proportionally the same amount of space but that third element will try to grow up to three times the space as the others.
Now this is where things get weird because this is all dependent on the content of the child elements. Even if we set flex-grow
to 3
, like we did in the example above and then add more content, the layout will do something odd and peculiar like this:
That second column is now taking up too much darn space! We’ll come back to this later, but for now, it’s just important to remember that the content of a flex item has an impact on how flex-grow
, flex-shrink
, and flex-basis
work together.
OK so now for flex-shrink
. Remember that’s the second value in the shorthand:
.child {
flex: 0 1 auto; /* flex-shrink = 1 */
}
flex-shrink
tells the browser what the minimum size of an element should be. The default value is 1
, which is saying, “Take up the same amount of space at all times.” However! If we were to set that value to 0
like this:
.child {
flex: 0 0 auto;
}
…then we’re telling this element not to shrink at all now. Stay the same size, you blasted element! is essentially what this CSS says, and that’s precisely what it’ll do. We’ll come back to this property in a bit once we look at the final value in this shorthand.
flex-basis
is the last value that’s added by default in the flex
shorthand, and it’s how we tell an element to stick to an ideal size. By default, it’s set to auto
which means, “Use my height or width.” So, when we set a parent element to display: flex
…
.parent {
display: flex;
}
.child {
flex: 0 1 auto;
}
We’ll get this by default in the browser:
Notice how all the elements are the width of their content by default? That’s because auto
is saying that the ideal size of our element is defined by its content. To make all the elements take up the full space of the parent we can set the child elements to width: 100%
, or we can set the flex-basis
to 100%
, or we can set flex-grow
to 1
.
Does that make sense? It’s weird, huh! It does when you think about it. Each of these shorthand values impact the other and that’s why it is recommended to write this shorthand in the first place rather than setting these values independently of one another.
OK, moving on. When we write something like this…
.child-three {
flex: 0 1 1000px;
}
What we’re telling the browser here is to set the flex-basis
to 1000px
or, “please, please, please just try and take up 1000px
of space.” If that’s not possible, then the element will take up that much space proportionally to the other elements.
You might notice that on smaller screens this third element is not actually a 1000px
! That’s because it’s really a suggestion. We still have flex-shrink
applied which is telling the element to shrink to the same size as the other elements.
Also, adding more content to the other children will still have an impact here:
Now, if we wanted to prevent this element from shrinking at all we could write something like this:
.child-three {
flex: 0 0 1000px;
}
Remember, flex-shrink
is the second value here and by setting it to 0 we’re saying, “Don’t shrink ever, you jerk.” And so it won’t. The element will even break out of the parent element because it’ll never get shorter than 1000px
wide:
Now all of this changes if we set flex-wrap
to the parent element:
.parent {
display: flex;
flex-wrap: wrap;
}
.child-three {
flex: 0 0 1000px;
}
We’ll see something like this:
This is because, by default, flex items will try to fit into one line but flex-wrap: wrap
will ignore that entirely. Now, if those flex items can’t fit in the same space, they’ll break onto a new line.
Anyway, this is just some of the ways in which flex
properties bump into each other and why it’s so gosh darn valuable to understand how these properties work under the hood. Each of these properties can affect the other, and if you don’t understand how one property works, then you sort of don’t understand how any of it works at all — which certainly confused me before I started digging into this!
But to summarize:
- Try to use the
flex
shorthand - Remember max, min and ideal size when doing so
- Remember that the content of an element can impact how these values work together, too.
Awesome post!
Great post! I still struggle with flex-box and its magical behavior, but you ‘max min ideal’ way of seeing it really seems to make things easier to remember and understand. Thanks!
Great post, thanks I think I might be able to use flexbox without referring to a guide each time!
very good article! This help me understand more about flexbox.
I usually don’t comment on 3rd party forms, but this time I felt needing to do!
I wanted to say, besides the facts- which are spot on, that your way of writing is fabulous! The way you kept me focus all the way, great job! Also my compliments for the accessibility in a way beginners understand everything and more experienced users can scroll (or read) through the content for the part they’re looking for.
Keep up this good work! I think you would be an excellent copywriter / blogger as a business
nice tutorial helped me lotlplease keep posting articles
They will take up an equal portion of the .parent element only if the lengths of their contents are the same.
Correct. This detail is VERY important. Hopefully it’ll be corrected in the article so beginners won’t run into issues later on when working with flexbox. Receiving the wrong information is worse than not knowing at all.
Hello, I have problem with flexbox and truncated text.
I wanted to cut out the excess text but it didn’t work when I used it with flexbox. but if I use the float instead it works again. Can you help me.
I have referenced this article but it still doesn’t help me. Maybe I’m not understanding how flexbox works properly.
example: https://jsfiddle.net/95mgc083/
Add
overflow: hidden
to.detail
and transfer all the styling from thea
element to.name
To truncate text within a
flex-item
, you need to addoverflow: hidden
to the parent (theflex-item
)I found this CodePen a tad helpful.
Thanks, man! This post makes the “flex- grow/shrink/basis”-problem imaginable for me … for the first time since I work in Frontend. <3 Since most of the time I am using the defaults and do not overwrite them now I can’t wait to be challenged with something where I need this knowledge here. (:
Use Flexbox Zombies game by Dave Geddes to understand it better
Thanks for this tutorial, I had never understood how flex-grow/shrink/basis worked.
Nice one, this helped my understanding a lot. Thank you
Great Post! Coming back to this each day to cement it in.
Just want to reiterate that the “flex” property is inherited by all of a parent’s children such that if you explicitly change the flex shorthand property on the parent those changes are inherited by the children. For some reason, I got confused and thought that I needed to individually target the children’s flex properties. I guess it really doesn’t matter where you set the flex property come to think of it. You can set it on the parent or on the children. Anyways Thanks again!
Amazing post. It now totally makes sense to me when I remember it as [max] [min] and [ideal]. Thank you!
Thanks, the
[max] [min] and [ideal]
thing is awesome. Would you say its advisable to not use height/width in conjunction with flex (if avoidable)? Just curious if you have an opinion on that. I think a lot of my confusion with flexbox stems from the things you described in your article as well as people commonly using height/width.Min and max are mistakenly used, because actually flex-grow shows the potential increase of the size (aka of the fkex-basis) while the flex-shrink shows the potential decrease (the loss) from the original size (which is fkex-basis) of the specific element. You can better understand it as a profit or loss from an initial capital. It is not the minimum or maximum capital in itself. Sadly the author misunderstood the topic, and by posting it in a renowned CSS portal made things even worse.
How can I use flexbox to create a horizontal scrolling image gallery where the image size is responsive up to a point?
This is where I’ve got to:
https://codepen.io/HightonRidley/pen/MWbWYgw
The height of the area for the text underneath each image isn’t really an issue as I think I’ve covered that ok.
Ideally the images will be responsive between a maximum and a minimum size, with an indeterminate number of images depending on usage. The number of images on display intially should be determined by the width of the containing div. I don’t want to use media queries.
I’d really appreciate any help :)
The explanation with
flex-shrink
being the minimal size of the element is incorrect.Flex shrink actually says (as flex grow does, too, but in a twisted direction) how much the space available will be redistributed.
The ‘available’ space for the shrink case is of course, negative.
Therefore from all the needed space (think of the over flown space outside of the wrapping container) which is necessary to the elements in order to exactly fit inside that wrapper after they get compressed by the flex shrink, each one must give up to a share, according to the flex shrink coefficient of each one.
That does not mean that it is their final size, but how many fractions from the total negative space each one will give up.
Compare that with the dilution of equity in the financial world when in a company arrives an investor who injects liquidity and receives instead shares, pushing all the founders towards a smaller pie of their initial stock holding.
I will come later with a post more thoroughly about this topic, with examples for empty elements or ones having or not imposed margins or paddings, so our fellow devs can understand better how to write quality code in this area.
Sadly several comments with my contributions in some useful areas were not accepted to this site by Chris since I write my opinions here so I am not sure if my post will be seen here or not.
I advocate for the simplest and strongest code use, if possible, therefore I also appreciate the efficiency of a comment if it meets the good will of the blog host, too. If not, for the sake of users greater good, maybe these comments will contribute to the someone else’s page. I think that good points might be allowed to be heard and not stopped at the gates.
Thank you!
great thank you.
this was awesome I was confused at the first also I searched a lot but now I got the whole idea.
Thank you for this! I think I now understand the concept … I think! :D
This is saying that 0 and 1 mean the same thing which is clearly not true.
0 means don’t shrink at all. 1 means shrink by a factor of 1 proportionally to how much shrinking is needed from all shrinkable siblings. 2 means shrink by a factor of two.
Imagine you have three flex siblings that need to shrink collectively by 100px, and the first child has
flex-shrink: 2
and the others haveflex-shrink: 1
. The first child will shrink by 50px and the other two will shrink by 25.I thought
flex-grow: 3
meantflex: 3 1 0
, notflex: 3 1 auto
. Did I misunderstand something?Your question had me wonder the same thing. I believe flex-grow doesn’t impact the default values for flex-shrink and flex-basis, which is 1 and auto. However, flex: 1, sets flex-shrink to 1 and flex-basis to 0.
In short,
flex-grow: 1; = flex: 1 1 auto;
flex: 1; = flex: 1 1 0;
Very well explained.
A very down-to-earth explanation! So very valuable
Best explanation ever,thanks
really good explanation for a beginner in CSS to understand, thank you!
Thank you! you are an amazing human bean