How should we resolve percentage margins and padding on grid and flex items?
The CSS Working Group would like your opinion. There is a longstanding issue in both the CSS Grid Layout and Flexbox specifications.
Percentage margins and paddings on grid items can be resolved against either:
- their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
- the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended to require that.
Authors should avoid using percentages in paddings or margins on grid items entirely, as they will get different behavior in different browsers.
The flexbox specification has the same wording.
What is the problem here?
A percentage has to be resolved against something. If you give a grid item a margin-right of 10%, you would probably expect that 10% to be calculated as 10% of the width of the grid area. What happens however if you give the item a margin-bottom of 50%? Do you expect it to resolve to 50% of the total height of the grid area or do you expect it to calculate 50% from the width? The spec allows for both, and browser implementations are split.
You can see the problem in this very simple CodePen. We have three column tracks which are each 120 pixels in width. The margin-right applied to each track resolves to 12 pixels, 10% of 120. In Chrome and Safari the margin-bottom resolves to 60 pixels. 50% of the width of 120 pixels is 60 pixels.
In Firefox and Edge the margin-bottom uses the height of the grid area and so in this case resolves to 150 pixels as I have put a height on the grid and items are stretching. If you remove the height on the grid container you will see how Firefox now completely collapses the container as there is now no height to resolve against. Chrome will keep the container at 60 pixels - that being the margin.
We see the same variance in Flexbox, however in Flexbox we resolve against the flex container as the containing block. However you can see in the below example how Chrome uses 10% of 500 pixels for the margin-right, and 50% of 500 pixels for margin-bottom. Firefox uses 10% of 500 pixels for margin-right and 50% of 300 pixels for margin-bottom.
The fact that percentages resolve from the width is essentially a throwback to the old days of layout on the web where we didn’t have great control over the height of things. The width was the measurement we could control and so became the dominant measurement.
The ‘aspect ratio hack’
One reason to follow the Chrome behaviour here is that it allows the percentage-based padding “aspect ratio hack” to work on flex and grid items. There is an excellent write-up of the interoperability issue on Bram.us - Vertical margins/paddings and Flexbox, a quirky combination, the issue is also detailed on Flexbugs and Gridbugs.
However, perhaps a better solution is to properly solve the aspect ratio issue, while also deciding on one solution for margins and padding in general.
We want your feedback!
The CSS Working Group would love to know your thoughts on this issue. As you can see above this is not an issue when using horizontal percentage margins and padding, this continues to work as it always has done. The issue is with vertical margins and padding. Would you prefer the Chrome behaviour, of the Firefox one? Other than the aspect ratio padding hack, are you using vertical margins and padding for any other reason?
You can comment directly on the GitHub issue with thoughts and use cases. It would be great to get this particular interoperability problem solved.
Also posted to the CSS WG Blog.