Introduction
Flexbox and CSS Grid are both powerful layout technologies built into CSS. They have many overlapping abilities. For most tasks, such as vertical centering, I could reach for either one. In some cases, one or the other is the only way to get the job done.
Is one better than the other, given the current state of web standards?
In the event that either Grid or Flexbox would work, I’m now reaching for Grid. I’ll explain why after discussing some various multiline scenarios.
Gap
Soon there will be a uniform way to apply consistent spacing between child items, as defined by the parent: gap
. So, gap: 5px
will not affect the outside margin, only the spacing between interior items.
This was inspired by and will eventually supersede Grid’s grid-gap
property. Unfortunately, the only way achieve the same result on multiline (wrapping) items in Flexbox using any browser other than Firefox is the Negative Margin Hack. This is where all the child items get a margin equal to half of the gap. Then to account for the extra space on the outside, the container gets a margin of the same value multiplied by -1. You can only use :first-child
and :last-child
on the items to account for the extra space when you have a single row (non-wrapping flex container).
For multiline grid containers, just apply a grid-gap
.
Winner: Grid, but hopefully gap
for flex layout will soon be added to Chrome and Safari.
Consistent Sizing vs Automatic Sizing
If you have tracks in both directions (a multi-column and multi-row layout) then your choice depends on the widths of the child items relative to others.
If you want all the items to line up evenly and stack vertically, use Grid.
If you want the items to retain their natural width and not line up vertically, use Flexbox.
The code for Grid requires a repeat()
function to be defined on the container’s grid-template-columns
property. The repeat
function accepts two values. The first for our purpose is either auto-fill
or auto-fit
. And the second is a minmax
function, which accepts a value with a fixed unit, and another fixed or relative value.
All together it might look like this:
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
This will give each item a base width of 200px that will scale up as needed.
For Flexbox, just add flex-wrap: wrap
.
Winner: Depends on the use case, but Flexbox is a lot simpler. 🙃
Container Control vs Item Control
There may be some cases — such as the boundary between two components — where you only want to modify the parent container’s CSS or the children’s CSS.
If you have control over the parent element, use Grid, which defines the children with grid-template-*
and grid-auto-*
.
If you have control over the child elements, use Flexbox, where the children define their own flex-basis
.
If you must use Flexbox for some other reason, you can still define a CSS variable on the parent that will be inherited by the children.
Winner: Depends on the use case, but Flexbox gets a point for versatility. Personally I like having the ability to control all the items on the parent in one place whenever possible, so Grid gets a point too.
Nested Layout
One killer CSS Grid feature that’s only landed in Firefox is subgrid
. This allows a child grid item to define its grid children according to the same track definition as the top level parent.
If you had a set of items that internally are split into a top and bottom section with variable amounts of content, you could define two repeating auto
grid tracks at the top level. Then the middle-level child items take up two each of the repeating rows. Then they pass down the track definition so that the top part receives one auto
track and the bottom part receives the other. Now, across the items, the split will be at the same place, so internally they all line up.
Winner: Grid, but you’ll still have uneven layouts in any browser other than Firefox.
Conclusion
For most other use cases, especially when working with one track in one direction with no spacing between items, I would be comfortable using either. That goes for situations where you need vertical centering and relative sizing.
But I find it easier to reason about how the children should be laid out when I’m defining them in one place on the parent element — so Grid wins out most of the time.
Overall Winner: Grid, but know its limitations!
As I mentioned, Firefox has taken the lead in this area. Please ⭐️ / CC yourself on these issues on Chromium and WebKit to make both Flexbox and Grid more powerful in the future!
gap
for Flexbox (Chromium): https://bugs.chromium.org/p/chromium/issues/detail?id=762679gap
for Flexbox (WebKit): https://bugs.webkit.org/show_bug.cgi?id=206767subgrid
(Chromium): https://bugs.chromium.org/p/chromium/issues/detail?id=618969subgrid
(WebKit): https://bugs.webkit.org/show_bug.cgi?id=202115
Top comments (4)
Great article. Many are unaware how well Grid and FlexBox can work well together.
My strategy: FlexBox for Navigation and informational Footer, I always use Flex on containers that are being iterated or dynamically updated, the wrap feature is gold to ensure sanity when new line starts.
It's Grid for everything else that I need to ensure that a container doesn't surprise me in the browser. Haha!
That's a great example of where flexbox shines! Throw a bunch of stuff at it and let it find the best fit. Flex layout is a constraint system, which is great to be able to dip into, but the layout logic can certainly cause surprises. Grid to me feels like building with brick and mortar, much more predictable. We're very lucky to finally have both at our disposal!
🤘
Very helpful... thanks.
I was looking for the article. Now I got it.