How to Flex(box)

How to Flex(box)

So, here I am, attempting to write a somewhat digestible guide on how Flexbox works. There are a few great resources out there for example “An Interactive Guide to Flexbox” and “What the Flexbox” but I understand that sometimes those guides are way too much, especially for beginners.

And so I’m gonna try to write a somewhat digestible, short guide on how Flexbox works. So let’s get started.

First thing first, contrary to the classic display block and inline-block and inline, flex, like grid, works as a combination of parent and child elements. Using flex on a container with no children is—almost always—kinda useless. There are some situations where it makes sense but there’s no point in discussing them here since the goal is to make it simple.

So, for all the following examples, I’m gonna use the following markup:

<div class="flex-container">
	<div class="flex-item">1</div>
	<div class="flex-item">2</div>
	<div class="flex-item">3</div>
</div>

A simple container, with three items inside it. Should be enough to understand the basics of how flex works.

This is our starting point. I added some styling to make a bit more clear what’s happening here. The .flex-container has a dotted border and a fixed width (width: 500px)

Everything is as you’d expect: the three divs are stacked on top of each other and are taking up the entire space. So far so good. Let’s transform the parent into a flex container using display: flex.

Ok, lots have changed:

  1. The divs are no longer stacked vertically
  2. They’re no longer taking up all the width available

Why is that happening? The first thing to know is that flex has an intrinsic direction that controls how the content inside the container flows. That direction is controlled using flex-direction which by default is set to row. You also have flex-direction: row-reverse that does exactly what you’d expect.

And we can also go vertical using flex-direction: column

And flex-direction: column-reverse.

Another thing to keep in mind is that, by default, a flex container has only 1 row or 1 column, meaning it will never wrap around into a new line.

Ok, so we have our flex container that can align the content inside it both horizontally and vertically, now we need to do something with that content. It’s time to tackle what’s probably the most confusing part about flex and that is how to size content inside a flex container.

Flex grow, shrink, and basis

The content inside a flex container can be sized using three distinct properties:

  • flex-grow
  • flex-shrink
  • flex-basis

flex-basis is essentially the width of an item in the context of flex. So let’s try to apply, for example, a flex-basis: 100px to the first child.

Ok, the item is now 100px wide. Awesome! Let’s apply a flex-basis: 200px to the second now.

Neat. Ok, time to do something with the third container. The first one is 100px, the second is 200px, only reasonable to make the third one 300px.

Ok, you might have noticed that something odd is happening. Our parent, the box that contains the three items, has a 500px width set. And out three containers are 100px, 200px, and 300px. That’s 600px total so they shouldn’t fit. What’s going on here?

Remember how I said that by default a flex container only has 1 row? This is what I was referring to. But we can change that behaviour using the flex-wrap property. By default is set to flex-wrap: nowrap but if you want to allow the content to wrap over multiple rows or columns you can set it to flex-wrap: wrap.

So we learned that flex-basis sets the width of an item but how about the other two properties, flex-grow and flex-shrink? These two can be tricky and I’ve seen developer with years of experience not managing to wrap their heads around how those two work.

Both of those properties accept a numeric value, and they control how an item grows or shrinks when there’s extra space inside the container or not enough. It’s a lot easier to understand with a simple example.

I expanded the flex container and it is now 600px wide and the three items inside it are all set to be 200px wide using flex-basis: 200px. 200+200+200 is 600px and so they fill all the space available.

By default, flex-shrink is set to 1. 1 what you might be wondering. 1 part of the missing space, and this is how it works. Imagine we scale down the container from 600px down to 300px.

Our three green divs are all still 200px wide and so in order to make them fit we need to remove 300px from them somehow. Those 300px are going to be subtracted from the width of the 3 divs and flex-shrink allows us to control in which proportion.

The calculation goes like this:

  1. First div has a flex-shrink value of 1
  2. Second div has a flex-shrink value of 1.
  3. Third div has a flex-shrink value of 1.
  4. 1+1+1 = 3 total units
  5. 300px / 3 = 100px
  6. Each div shrinks by 100px

This is because we calculated that the value of that shrink unit is 100px and each div shrinks by 1.

flex-shrink controls the way width is subtracted from the various elements when there’s not enough space relative to their flex-basis value. And the reason why it’s just a numeric value without units is because it’s nothing more than a way to express a proportion.

If you set to elements to have flex-shrink: 1 and flex-shrink: 2, the second element will shrink twice as fast. Because 2 units of “missing space” will get subtracted to it compared to the 1 that will be subtracted to the first element.

More visually, these are two items, flex-basis: 300px inside a 600px container. Number 1 has flex-shrink: 1, number 2 has flex-shrink: 2.

If I make the box 300px wide this is what happens:

Number two has shrunk down to 100px wide and number one has shrunk down to 200px wide. That is because we had to subtract 300px—our missing space—and div number two had to give up 2 (flex-shrink: 2) units while div number one only had to give up 1 unit (flex-shrink: 1)

Goes without saying that you can use whatever number you want in there, doesn’t have to be 1 or 2 you can set it to 124 and 322 and the overall logic will work the same:

  • 300px to be subtracted
  • 124 + 322 = 446
  • 300px / 446 = 0.67px (this becomes the value of our unit)

One box will shrink by 124 units and the other by 322.

And that’s how flex-shrink works. flex-grow is nothing but the same thing when there’s more space, instead of less. So, to keep the same example, if you have the same two boxes, both 300px wide thanks to flex-basis: 300px, one has flex-grow: 1, the other flex-grow: 2, and you increase the size of the parent container from 600px to 900px now you have 300px of extra free space. And that free space will be distributed based on the same calculation:

  • flex-grow: 1 + 2 = 3
  • 300px / 3 = 100px (this becomes the value of our unit)

One div will grow by 200px, the other will grow by 100px.


And this is all for part 1. Next time i’ll cover the ramaining properties but I think this is the more tricky part of flex because sizing inside a flex container can be confusing.
@Sunny_Velvet_Luxe let me know if this has helped in any way and especially let me know if you have questions!

8 Likes

I don’t know if it’s because I’m tired and barely got enough sleep last night, but I got kinda lost after the flex-shrink part. I do get the flex-wrap somewhat so I probably need to process more of this. I don’t really have any useful questions rn, I’ll get back to you on that.

1 Like

What really made flexbox “click” for me was understanding that it’s used for one dimensional layouts; Laying things out in a single direction. Everything else is simply a means to achieve that end.

1 Like

Correct. It can be used for layouts but things become very messy. And grid is usually a lot better for that.

Wow this is excellent! Thank you for the writeup

1 Like

This is an awesome guide, love the examples! You should totally consider publishing this on your website as well (if you haven’t already)!

2 Likes

Mirroring the other sentiments, this was a great intro to flexbox!

thank you so much!!! :D i’m going to add this to the resources list as well. if folks think a pin would be a good idea for this board, let me know. :)

How to Flex(box): Part 2

Quick recap of what we learned so far:

  • display: flex turns a container into a flex container
  • flex-direction controls the direction of the flow of the content inside the flex container
  • flex-wrap controls if the content inside of the flex container will wrap around into multiple lines
  • flex-basis is the width equivalent for the items inside a flex container
  • flex-shrink is used to decide in which proportion an item will shrink when there’s not enough space inside a flex container
  • flex-grow is used to decide in which proportion an item will grow when there’s extra space inside a flex container

Ok, we have our container, we have our content inside it, it’s time to decide how to place this content. For the following examples, I modified our trusted container with the 3 green boxes and this time it also has a fixed height of 200px. The three divs are all 100px wide (flex-basis: 100px) and won’t grow, even though there’s free space (flex-grow: 0). It looks like this:

As you can see, the three green divs are taking up the entire height of the container. This is not a normal div behaviour. Usually a div—unless there are other properties that interfere— takes up all the width available but the height is determined by the height of the content inside it. Things are a bit different inside a flex container. That is because the flex container has two properties that control how the content inside it behaves. The first one, responsible for the stretching of the height is called align-items and it’s pretty self-explanatory. It controls the alignment of the items inside the container and the default value is align-items: stretch. But there are other values we can use. For example, we have align-items: flex-start

…Or align-items: flex-end

…Or align-items: center.

These are by far the most common but there are a few others that can come in handy in specific situations. So, we can align items vertically, how about horizontally? For that, we can use justify-content. Like with the previous property, we can use flex-start, flex-end, and center

But we also have three more useful values: justify-content: space-between

justify-content: space-around

…and justify-content: space-evenly

These three are all kinda similar but you might have spotted the difference already. space-between places the first and last item on the edges and then distributes the space in between the items evenly. space-around doesn’t place the first and last items on the edges but instead it adds the same space around each item and the end result is half a column of space on the sides. space-evenly instead distributes the items evenly and so both on the sides and in between items you have the same distance.

You might have noticed that both justify-content and align-items don’t use values such as top or bottom or left or right but instead they use flex-start and flex-end. That is because—and this can also be confusing at first—the directions inside the flex container are determined by the value of flex-direction.

Right now justify-content: flex-start places the content on the left edge because flex-direction is set to row. But look what happens if I set it to row-reverse:

Now the container starts on the right, and so justify-content: flex-start places the items on the right side. I’ll skip what happens when you decide to go vertical using flex-direction: column for the time being because that makes everything even more confusing.

So, you move items up or down using align-items, you space them and align them left or right using justify-content. What else can we do?

Well, inside flex you can use gap which is pretty self-explanatory. It adds a gap between the items. For example, gap: 20px gets you this:

But what if you want to move individual items differently and not just all together as one big group? For that, you have a few options you can use on each individual item. You can use align-self that behaves exactly like the align-items property discussed earlier, but it’s simply applied to that individual item, rather than being applied to the entire container. In this example, Number 2 is using align-self: center and Number 3 is using align-self: flex-end.

But you can also still use good ol margin and margin: auto still works as you’d expect. In this example, Number 2 has a margin-left: auto set.

And as a result, it will push everything else to the right. Margin, inside a flex container, actually has a bit of a superpower. That’s because by using margin: auto you can center something not only horizontally, but also vertically! For example, this is a lonely div, placed at the top left of the flex container…

Look what happens if I simply add margin: auto

SUCCESS! Never been easier to center an item both vertically and horizontally.

Ok this covers the most common use cases I believe. And, if I have to be honest, considering we now have CSS grid, there’s no reason to use flex for complex layouts anymore. But flex is still super useful in some situations.

4 Likes

Writing guides is tricky, you never know how in depth you have to go. But, I’m more than happy to help people with their projects if they’re stuck or have questions about specific situations. Because the problem with CSS is that here i’m just moving a few divs around while in reality you might have a lot going and so the situation you’re facing can be a lot more complex

2 Likes

I think this seems like a great baseline to build our knowledge on! Made my confusion about what I even use a bit more clear (bastardized flexbox, I think, lol) and gave a good oversight of the basic functionalities :))

1 Like