Column confusion continued

While learning about flexbox, I found that row-based things made sense quickly. However once I started trying some flex-direction:column stuff, I got confused.

Ok, so things seem easy enough. Once we activate flex-direction:column on our flex container, you just use the other axis stuff to do your alignments, right? Instead of using justify-content:center to horizontally align, you just use align-items:center. Pretty easy right?

I think that wrapping is where you have to be careful.

Let's say that you activate wrapping with flex-wrap:wrap.

  • With left-right orientation (flex-direction:row) wrapping happens when?
  • With top-bottom orientation (flex-direction:column) wrapping happens when?

Understanding the "why" to the "when" is extremely helpful.

It's based on both the flex container AND the flex items. Remember that flexbox will try it's best to align child items within the flex container based on the rules that you give it. Everything fits on one row or column if there is extra space leftover.

Items will align, stretch, and shrink along that row or column as long as it's possible. But if there isn't enough space to expand or shrink - while still fitting inside the limits of the flex container...problems.

This is the "when" that we are looking for!

"If you aren't sure what's going on, put a red border on your child items." - Wes Bos (paraphrased)

Remember, your browser by default limits the width of your flex container - simply by the width of your browser window. But the height is never limited because of default scroll behavior of browsers.

This means that if you want to do something fun with flexbox, like having your links look like:

instead of:

you need to set a height on your flex container!

Nooooo!!!

I know! My reaction was very similar. This is the land of flexible design! Responsive, adaptive, and all those buzz words! I won't go back to fixed sizes, I shan't!

And yet, the vertical scrolling nature of web pages require that vertical containers need a vertical limit if we expect wrapping of things inside to make sense. Said another way, there is no need for the internal items to wrap in our nifty new vertical direction if they all fit in a single column.

Ok, now that we've partly calmed down - Let's see go step by step to achieve the fun vertical flow.

Let's start with a basic flex container with six child items:

Now, let's turn on flex-wrap:wrap

Did anything even happen above? Well, yes but it's not wrapping because the items aren't wide enough to need to. Let's fix that by making each item have a starting width set to half the width of the row. We'll do this with flex-basis: 50%

That's better. :) Now it's just a simple matter of changing the flex-direction from the default of "row" to "column" right?

Rats! It didn't work! Or did it? Notice that because our flex container doesn't have a set height, it grew taller to fit all of the child items that are trying to now flow top-to-bottom.

"But what happened to the 50% basis!" This threw me at first also. Remember that we've changed the axis from left-to-right (horizontal) to top-to-bottom (vertical).

The width from the basis is actually no longer a factor in determining when new rows happen. Because our flex-direction is column, each item will stack solely because that's the direction it goes now. It would need to run into something at the bottom in order to trigger a wrap (a new column) - but that never happens because the flex container grew taller.

But flex-basis:50% still means what it did before. This is where the red dashed border will help illustrate. Let's set a height to our container to see both the basis visually, as well as the column-wrap point.

In the above, notice how flex-basis: 50% is now making the child items take up 50% of the column(vertical) space? (due to the axis change)

Also, now that the flex container cannot increase, the wrapping triggers new columns to fit the items. :)

In the example below, notice that without the flex-basis:50% it fits as many items as vertically possible before wrapping. (reduced the vertical height from 200px to 100px to help illustrate)

But there is that extra space at the bottom, where there wasn't quite enough space to fit an item vertically - so it wrapped instead. How do we evenly distribute that space into our items? It's the same way we did it with rows. Just put a grow on the items so they receive even distributions of the space. Instead of using flex-grow:1, we'll use the short-hand notation flex:1.

When adding a grow or shrink try to use the short-hand notation because:

It is recommended that you use this shorthand property rather than set the individual properties. The short hand sets the other values intelligently.

So, flex:1 = flex:1 0 auto = flex-grow:1; flex-shrink:0; flex-basis:auto;

With the grow enabled, we see the below example with the rows fitting nicely into the container - all with wrapping. :)

Take away

Column wrapping needs a container with a fixed height.