Flexbox Percentage Margins and Paddings

UPDATE: This has been addressed and updated in the latest WC3 Editor’s Draft, which you can read here.


I came across a strange issue regarding a seemingly rare use-case, while dealing with specific aspect ratios for child elements combined with new-and-shiny Flexbox support in major browsers.

Here’s the idea: we have a “grid” of list items that flow inline, are flexible, and maintain their aspect-ratio along the way. These squares should always remain squares.

squares

Rather than simply adding and dropping columns between breakpoints, the items would flex to fit the space allocated to them while maintaining their “grid” layout as well as their proportions.

See the Pen Flexbox items with padding by John Kreitlow (@kreitlow) on CodePen.15401

Depending on what browser you’re using to read this, and the amount of time passed since this was published, you’ll either see a nice collection of gray boxes or a blob of #debugpink in the CodePen above.

The W3C has recently been discussing the issue of percentage-based margins and paddings on flex items. The meat of the issue is that the W3C would prefer to keep Grid and Flexbox algorithms as similar as possible, to reduce confusion and make developers’ lives easier I guess.

The initial reason for the change was that Grid, as drafted and implemented by Microsoft, was the other way around. If they refuse to change Grid, and Blink refuses to change Flexbox, then we have a problem.

~fantasai (https://lists.w3.org/Archives/Public/www-style/2015Feb/0566.html)

I’ve gone this far not explaining what the actual problem is. It’s a narrow one, and may not seem like such a small detail in the grand scheme of the Internet. The change referred to above is this line in the current Flexbox spec draft:

Percentage margins and paddings on flex items are always resolved against their respective dimensions; unlike blocks, they do not always resolve against the inline dimension of their containing block.

CSS Flexible Box Layout Module 1 [W3C Working Draft] (http://www.w3.org/TR/css-flexbox-1/#item-margins)

So if you use margin-top, margin-bottom, padding-top, or padding-bottom, with a percentage value, the containing block decides whether that value resolves against the main dimension or the cross dimension.

The animation below is intended to show the relationship between containers and child elements. On Chrome 43, both left and right animations appear the same. In Firefox 38.0.1, the Flexbox implementation appears to be broken, which will only display a red line on the right.

See the Pen Block vs. Flex margin and padding animation by John Kreitlow (@kreitlow) on CodePen.15401

According to the W3C and @CodingExon, Firefox is right, and Chrome is wrong:

Fantasai proposes two resolutions for this problem on the blog CSS3.Info. Those both boil down to either resolve p/m-t/b against the height or width of the containing block (i.e., pick one). There have been suggestions from others in the mailing list, proposing an aspect-ratio property or similar, which I think would be weird (merely because it seems too ambiguous).

So, why not add a new flexbox-specific property to solve this problem?


flex-relation: main-axis | cross-axis | width | height | auto

The flex-relation property allows for changing the dimension that percentage margins and paddings are resolved against for flex items. The property applies to the flex container and affects all flex items.

main-axis
Flex items will always resolve their padding or margin size against the main dimension. For `row` and `row-reverse` flex containers, flex items resolve all percentage margins and paddings against the width of the flex container. For `column` and `column-reverse` flex containers, flex items resolve all percentage margins and paddings against the height of the flex container.
cross-axis
Flex items will always resolve their padding or margin size against the cross dimension. For `row` and `row-reverse` flex containers, flex items resolve all percentage margins and paddings against the height of the flex container. For `column` and `column-reverse` flex containers, flex items resolve all percentage margins and paddings against the width of the flex container.
width
Flex items will resolve all percentage margins and paddings against the width of the flex container, regardless of the flex container’s direction.
height
Flex items will resolve percentage margins and paddings against the height of the flex container, regardless of the flex container’s direction.
auto (default)
Flex items will resolve percentage margins and paddings against their respective dimensions.

I feel like margins and paddings are just a few potential uses of this property, and it could be expanded on for some interesting use cases.

I don’t know what the level of effort is to implement something like this, but I’d like to hear what others say about adding a new property. With flex-relation, Browser developers would be able to have different defaults for grid and flexbox if they want. Developers wouldn’t have to agree with those defaults and would have the power to adjust things to how they prefer. And my divs would be nice and square.