In my last post I presented 4 specific CSS problems that can be effectively solved with the help of Flexbox, a progressive layout model that is now well supported on all modern web browsers (http://www.chrisgeelhoed.com/4-classic-css-problems-solved-with-flexbox/). Although Flexbox can behave inconsistently on browsers like Internet Explorer, these bugs are well known and can usually be avoided (Check out https://github.com/philipwalton/flexbugs and my previous post on this topic http://www.chrisgeelhoed.com/flexbox-things-didnt-tell/).
But as great as Flexbox is, it still falls short in solving certain layout problems that developers will commonly encounter on the web. Speaking generally, Flexbox fails to provide simple solutions to 2D (or grid-based) layouts.
In fact, it isn’t hard to understand why this is the case. Flexbox is designed for single dimensional layouts. Elements within a flex container are arranged along either the row or column axis and are distributed along that axis (by use of margin or
justify-contents). While it is possible to position elements along their cross axis (by use of
align-self), elements cannot share a single cross axis column. Or put simply, they cannot easily be positioned in grids.
Two major strategies can be employed to force Flexbox into rendering grid layouts:
- Nested container elements – Children of flex containers may contain children of their own.
- Wrapping elements – Although Flexbox will force all of its children along its primary axis by default, the
flex-wrapproperty can be used to overcome this and create the appearance of 2D layouts.
Both of these strategies leave much to be desired. The first strategy, while very versatile, is tedious, not semantic, and is difficult to implement when the the number of children elements is unknown. The latter strategy overcomes some of these shortcomings but presents challenges of its own.
The first such issue with the wrapping technique is that the code required to achieve it is somewhat complicated and tiresome. Check out this example to see how a custom 3 up grid can be achieved in Flexbox and with a traditional float based system.
Notice that although a flexbox based grid does have significant advantages over it’s floated equivalent (equal column heights, no clearfix required, convenient reordering), the code is actually very similar and has many of the downsides of traditional grid systems like:
- Calculating the width is tricky, and although the
calc()function is helpful, setting the appropriate width of a column should not require this much math.
- Having to manually target the right most columns with the
nth-childselector is equally non-ideal
- Setting the vertical spacing between rows can be achieved by declaring a margin-bottom on all children, but what if I only want that space to exist between rows, and not after the final row. This is tricky to achieve at best.
In fact, the hacky nature of coding grid systems is a significant factor in why CSS frameworks like Bootstrap, Foundation, and Bulma have achieved such popularity. It has been my experience that almost no developers create such layouts without the help of some kind of framework, and I can easily understand why.
How CSS Grid Solves this problem
Fortunately, a new layout system called CSS Grid has been created to address many of Flexbox’s shortcomings for creating designs featuring row/column arrangements. Checkout the example below:
Much clearer, right? No painstaking width calculation or
nth-child business is required, and the
grid-gap property only applies between rows and columns (alternatively, you can use
grid-column-gap to set the vertical and horizontal spacing independently).
And although the advantages to CSS Grid are already apparent, this pen is nothing more than a
Hello World! example. Check out how the following pen achieves the Holy Grail Layout.
In this example, I use the
grid-template-columns property to split the grid into 12 columns much like what Bootstrap and Foundation elect to do (Twelve is an ideal number as it can be divided evenly in 2, 3, 4, and 6 equal parts as opposed to ten for example, which can only be split into 2 and 5 equal parts. Incidentally, this is also a reason that Canadian workmen often prefer British units despite living in a largely metric country, but I digress…) and use
grid-template-rows to set the first and last row to be a height of 60px, and set the middle row as
auto which allows it to stretch vertically (much like Flexbox).
Once the sizing of the grid is defined, the position of each element can be set by using the
grid-column property, which sets the starting and ending column for that element (notice that unlike many programming languages, this is indexed with 1 being the starting number, not 0).
In fact, the properties used above can be used to create much more complicated arrangements than the Holy Grail Layout, and are appropriate for layouts that would traditionally require nested wrapper elements or absolute positioning.
Although CSS Grid support is already in place for many browsers and is improving rapidly, it still lags behind Flexbox and is not well supported for Internet Explorer. This being the case as of June 2018, I am still avoiding CSS Grid for professional work but am beginning to use it for my personal projects. I can’t wait until the point where CSS Grid has full support and I can drop my 3rd party grid framework in favour of a much better and much more lightweight solution.