A Work in Progress

developer's blog by Wei
lots of work in progress notes
TimelineCredits

Do You Spam Flex Box Also?

March 21, 2019

Things learned reading CSS Flexible Box Layout Module Level 1.

This is not a post about how to use flex box. For this aim, you may find the following posts (app) interesting:

I have been using flex box heartlessly for almost two years now. I guess sharing a similar motivation from this amazing post, there is just one day for every flex boxer that is like “today is the day”.

And what I particularly enjoy doing nowadays as I read the specs is that I’d like to dig into the earlier versions to try to answer these questions: What is it intended for (am I using it at the right situations)? What is it not intended for (am I misusing it)?

What is flex box intended for?

Flex box is a layout module. By the time the flex box layout module was born, there were already the following layout modules:

  • block layout, designed for laying out documents
  • inline layout, designed for laying out text
  • table layout, designed for laying out 2D data in a tabular format
  • positioned layout, designed for very explicit positioning without much regard for other elements in the document

In an early post by Tab Atkins, one of the editors for the flex box specs, he writes that:

The defining aspect of Flexbox Layout is flexibility - flexbox children can be made flexible, which means they'll work together to distribute available space, stretching or shrinking their widths and heights as necessary to fill the flexbox completely.

I think this is best one-liner to describe what flexbox does. I don’t know why they don’t put this line in the specs. But that’s a nice intention to have in mind.

Now, how exactly does flex box let items work together to create flex layout is still in the wild jungle for me. So I guess I’ll want to understand more.

Flex box is biased towards a designated main axis

Before flex box, we all had a rough feeling that the vertical and the horizontal spaces are manipulated a bit differently. Like margin: auto gives you horizontal centered item but doesn’t do anything vertically. In specs’ term:

Unlike block and inline layout, whose layout calculations are biased to the block and inline flow directions, flex layout is biased to the flex directions.

When the flex direction is the default row, and if you don’t set a definite width to the container, it gives you this T-Rex track that can theoretically go on forever (?). The vertical direction becomes the cross axis. You’d normally justify content along the main, and align items along the cross axis, respectively.

If, on the other hand, your main axis is vertical, you’d just turn your head 90 degrees and you’d get a comparable behavior and I’m sure we all know this already.

With this main- and cross-axis mind set, I’d like to claim that flex box is more one-dimensional than any-other-dimensional. Yes, you can nest flex boxes to create two-dimensional layout. But each individual flex box has exactly one main axis. It acts very much like a number axis. You can combine two (or more) number axes to create a coordinate system. But each number axis extends in its own direction.

While align-content allows for alignment across wrapped lines, and certain calculation and alignment are done in coordination between flex items and flex container. They’re like the tiny flower buds that emerge into just a little bit of more than one-dimensional.

Flex items work together to distribute space

The layout modules prior to flex box did not allow items to adjust their widths and heights with respect to their peers or distribute remaining space. With flex box, we can:

Justify content on the main axis

https://www.w3.org/TR/css-flexbox-1/images/flex-pack.svg

I realize that the specs provided the examples rather biased towards the default flex direction. So I went ahead implement the above visualization with flex-direction set to column. I would expect life to be as easy as simply saying flex-direction: column. Turned out I probably just poked the beehive and a good bunch of more specs spilled out for me to read 🤓 It’s fun and you should do it too.

Align items on the cross axis

The flexibility of flex box items also work on cross axis. The items will look at how tall or wide their peers are, and may shrink or stretch based on the alignment scheme.

With box model, the issue I encountered last week, the items also stretched to an equal width. I’d like to point out that that is based on container width, which in turn is deduced from its children’s content widths. Flex box items gain extra flexibility from a combined factor of dimensions of other flex items, available space from the flex container, and alignment scheme.

Some steps in the Flex Layout Algorithm can be hard to follow, but I think this illustrates the case nicely. https://www.w3.org/TR/css-flexbox-1/images/flex-align.svg

Distribute space when flex items are wrapped to multiple lines

When you wrap your flex items and therefore obtain a multi-line flex layout, those lines can distribute available space as well. This, actually, feels, pretty uselessly (?) cool 👹

flex-box specs: https://www.w3.org/TR/css-flexbox-1/images/align-content-example.svg

A more powerful auto margin for center alignment

As I understand it, this is not the direct design intention for flex box, but rather a convenient consequence that you may use flex box for horizontal and vertical alignment. Maybe so handy that there are a few places in the specs that mentioned this, even in the abstract:

Both horizontal and vertical alignment of the children can be easily manipulated.

I always thought I’ve been abusing flex-box just for vertical alignment. Now I know it’s not a hack or anything, it’s a feature!

Although, do you know that instead of:

.parent {
  diaplay: flex;
  align-items: center;
  justify-content: center;
}

You can actually:

.parent {
  display: flex;
}
.child {
  margin: auto;
}

Flex algorithm

Section 9, Flex Layout Algorithm of the specs is normative. This means that it takes extra what-the-hecks to read. But I guess a good idea is to read the titles first, which are quite declarative in this case:

9.1. Initial Setup 9.2. Line Length Determination to determine the available main + cross space, prepare hypothetical item sizes, flex base sizes

9.3. Main Size Determination determines the sizes of items along the main axis. This is the step to consult the available space and the flex and shrink factors, and loop until the lengths of all items are sorted 9.4. Cross Size Determination proposes then determines the cross size, determine for each flex lines if applicable, handle stretching on flex lines, handle visibility collapsed case (revisits once), finally determining the cross size for each items

👆 and 👇 are the magics to flexibility.

9.5. Main-Axis Alignment 9.6. Cross-Axis Alignment

These titles are further broken down to smaller steps which you can just patiently go through one by one. The more complex step, main size determination, is discussed separately in section 9.7. Although you’d gain a fair understanding of the process already even if you don’t read all the details.

Flex box is not for everything 😭

So I went on to hunt for pages to implement with flex box. I had a nice candidate, or so I thought. On Tab Atkin’s website (the xanthir.com URL on his public profiles is broken, you need the www in front) there is a page called Recipe Book, under which there is a Recipe Planner that lets you pick from roughly three hundred recipes and generates shopping list based on the ingredients. You can drag them to a dialog on a top section of the page to compose a shopping list. Tab Atkins’ name heads the editors list so I naively assumed I’d see some flex box here.

Should I flex box

I mean, nowadays as we’re all so used to the default display: block set to divs by browsers (thanks Huijing for pointing that out, steering me clear from that mistake before I even have a chance to make it). Whenever I see a design that lays things out horizontally I’d throw in a display: flex.

I now call this "spamming flex-box" 🙈 Do you spam flex box also 🇸🇬?

This top section that contains an array of boxes for the ingredients you’ve selected. I inspected this reasonably fair candidate for a flex box layout and ugh, no, there is no flex box 🤔. They are just inline boxes. They break into several lines and the items within each line do not justify (Visual formatting model: Inline formating contexts). There is no need for flex box.

Can I flex box

On the lower section of the page is the main chunk that contains the hundreds of recipes.

Considering I’m on a mission to hunt for flex box, and that I’ve read the whole specs! I’d like to think that at least I can do it with flex box. I discovered a few more features of this section:

  • the items are listed from top to bottom, then left to right
  • there is a fixed width to each item, or say “column”, enlarging or shrinking the viewport will not change the widths
  • it will, however, add or reduce the number of columns, and the items will automatically reflow while keeping the columns roughly end at the same level

Does this look like a fair candidate for flex box?

And so I went ahead dumped the html into a CodePen and started playing with it, first adding a fixed width to the list items

li {
  width: 160px;
}

And apparently there should be some flex box magic

ul {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: space-between;
}

… And I start to hate typing already. If you are curious, below is what it looks like now. Note that my flex container now has main axis extends to infinity vertically.

And then I’m stuck. I want my flex items to wrap, which means I need a definite main axis length. But how do I know how long it should be?

My understanding is that this layout with features described above is not achievable with flex box.

Thinking about this again in analogy to our number system. You can put a definite constraint on the container, much like the number base in a place-value number system. The flex items will wrap whenever there is not enough space, just like how we bump the digit 9 → 10 in our number system, or how 13:00 becomes 1pm. You may as well not place a constraint, in which case you just keep stacking your items in a single line. But you cannot, say, see how much your items extend and then decide on a constraint.

The layout is done with column-width, a property described in CSS Writing Modes Module Level 4, but perhaps defined in CSS Multi-column Layout Module Level 1. I guess I’ll explore this in a future post.

And are a couple more topics I’d like to write about regarding flex box:

  1. Fragmenting Flex Layout
  2. Some fine-tuned understanding about flexible length determination and alignment, such as

    • Flex basis
    • Difference in centering items between auto margin and align-items: center

Till next time :]

Links

© 2019 - 2021 built with ❤