Browser Compatibility for CSS Grid Layouts with Simple Sass Mixins

According to an article from A List Apart about CSS Grid, a "new era in digital design is dawning right now." With Flexbox and Grid, we have the ability to create layouts that used to be extremely difficult to implement, if not impossible. There's an entirely new system available for creating layouts, especially with Grid. However, as with most web technologies, browser support is always something of an issue. Let's look at how we can make the fundamental aspects of Grid work across the browsers that support it, including older versions of Internet Explorer that supported an older and slightly different version of Grid.

The Sales Pitch

If you visit caniuse.com, you'll see that CSS Grid is supported in current versions of all major browsers except Opera Mini. So why not start using it? Rachel Andrew wrote extensively on the subject of if it's "safe to use" or not. It is, assuming you're OK with a fallback scenario that doesn't replicate exactly what Grid can do:

If your website really needs to look the same in all browsers (whatever that means to you), you won't be able to use any features only available by using Grid. In that case, don't use Grid Layout! Use Grid Layout if you want to achieve something that you can't do in a good way with older technologies.

If you'd like to get started learning Grid, Jen Simmons has a nice collection of links and there is a reference guide here.

Grid is a major change to CSS layout. It's powerful, (fairly) easy to use, and, if you're working on open source or on a team, easy for fellow developers to read. In this article, we're going to look at how we can write Grid code to be as compatible as we can possibly make it, including some degree of fallback.

The Sauce

The main thing we want to do in this post is address browser compatibility for the fundamentals of CSS Grid. We'll cover how to construct a parent grid element and place child grid elements within.

The outliers are going to be Internet Explorer and Edge. Edge is just starting to ship the modern CSS grid syntax, and it's an evergreen browser so ultimately we won't have to worry about Edge too much, but at the time of this writing, it matters. IE 10 and 11 are rather locked in time, and both support the old syntax.

Again, Rachel Andrew has information on this old syntax, what it supports, and how to use it. The old syntax, for example, doesn't support display: grid;, we have to do display: -ms-grid;. And there are similarly prefixed for many of the properties.

Even then, many of the properties themselves are not the same. But it's okay. The differences are not that great and we can get some help from Sass. The saving grace here is that we only need vendor prefixes for IE/Edge. Any other browsers will be addressed by the "standard" properties.

First, let's define a Grid parent using a Sass @mixin:

@mixin display-grid {
  display: -ms-grid;
  display: grid;
}

.grid-parent {
  @include display-grid;
}

Here's a demo of that, which also defines and lays out a simple grid:

See the Pen CSS Grid Demo 1 by Farley (@farleykreynolds) on CodePen.

This is helpful, but the grid itself isn't yet compatible with the old CSS Grid style.

Next we need to cover the differences in defining the grid parent rows and columns. Let's beef up the grid a little bit and define it to be compatible across all browsers (for example, by using -ms-grid-columns in addition to grid-template-columns):

See the Pen CSS Grid Demo 2 by Farley (@farleykreynolds) on CodePen.

The -ms- prefixed properties will work for IE/Edge and the non-prefixed properties will work for other grid-supporting browsers. This particular demo will give us the following dimensions:

  • One column 75px wide.
  • One column that takes up all available space left over by the other columns (1fr = 1 fraction of the remaining space after other elements are calculated).
  • Two columns at 50px wide apiece.
  • Three rows at 1fr tall apiece.

Check out the value for grouping on line 19. IE and Edge don't have syntax for grouping a set of rows or columns that are all the same dimensions. We can accomplish the same thing in any other browser using the repeat() function:

repeat([number of columns or rows], [width of columns or height of rows])

No vendor prefix can help us here, we'll need to write out each column manually with the old syntax.

Now we have a grid that's compatible across all browsers, but we still need to address the grid children. The following Pen illustrates how they can be made compatible:

See the Pen CSS Grid Demo 2.5 by Farley (@farleykreynolds) on CodePen.

Here's the mixin for placing the grid items in both the old and new syntax:

@mixin grid-child ($col-start, $col-end, $row-start, $row-end) {
  -ms-grid-column: $col-start;
  -ms-grid-column-span: $col-end - $col-start;
  -ms-grid-row: $row-start;
  -ms-grid-row-span: $row-end - $row-start;
  grid-column: #{$col-start}/#{$col-end};
  grid-row: #{$row-start}/#{$row-end};
}

.child {
  @include grid-child(2, 3, 2, 3);
}

Here's what you need to know about the difference between properties for the grid children in different browsers. In most browsers, you define a grid child by the grid lines where it starts and ends. Grid lines are the lines that exist between the columns and rows you've defined. The syntax looks like this:

grid-column-start: 3;
grid-column-end: 5;
/* or the shorthand version: */
grid-column: 3 / 5;

This element will span column lines 3 through 5 in your grid.

In IE and Edge, you define a grid child by the line it starts on and how many rows or columns it spans (There is no shorthand version as in the previous example). The syntax looks like this:

-ms-grid-column: 3;
-ms-grid-column-span: 2;

This element will start on line 3 and span 2 columns. The two code snippets above will effectively create the same element. Notice that 5 - 3 (from the first snippet) is 2, which is the column span from the IE/Edge example. This allows us to do some quick math in our @mixin and get all the needed information from four numbers. The subtraction on lines 17 and 19 sets your span number for IE/Edge.

Using @include grid-element; allows you to define a grid child for any browser using only four numbers: The column start and end, and row start and end.

So now we've got grid parents and children that work for all browsers.

Drawbacks and Fallbacks

It's an unfortunate reality that not all browsers support CSS Grid, and that the old syntax doesn't support everything from the modern syntax. For example, grid-gap and grid-auto-rows or grid-auto-columns are very useful properties in the modern syntax that there isn't any equivalent to in the old syntax.

Sometimes you can use the @supports for help. @supports works a bit like a media query, where if it matches the CSS inside it applies.

This can get very tricky though, as @supports is not supported in IE. This kind of creates a puzzle when you want to use features like grid-auto-rows or grid-gap to automate portions of the layout, as you have three scenarios now: modern grid support, old grid support with @supports, old grid support without @supports.

@supports (display: -ms-grid) {
  /* This will apply in Edge (old syntax), but not IE 10 or 11 */
}

For the old syntax, you'll have to place your grid children and set their margins explicitly so the CSS is recognized by IE, which would nullify the need for auto placement or grid-gap in other browsers.

The following Pen is kind of a hodge-podge, due to the issue of @supports compatibility. You can see how grid-auto-rows works, and how to set the gaps for IE/Edge where grid-gap won't work. Again, if you have to support IE, the need for explicitly setting values may nullify the need for properties that set layout styles automatically.

See the Pen Grid Demo 3 by Farley (@farleykreynolds) on CodePen.

The grid-auto-rows property will automatically generate successive rows of a specified height as the columns fill up. You can play with it in the Pen by adding more divs. Another row will be added each time you increase the number of divs past a multiple of three (the number of columns).

The grid-gap property essentially turns the lines between your grid children into gutters. You can set its value using all the usual CSS size units like rems, ems, pixels, etc. In the demo above, the properties involving nth-child set margins that replicate the gutter effect of grid-gap for IE and Edge. It's not that difficult to account for with simple grids but you can see how it could get out of hand quickly with more advanced or flexible grids.

These two properties and others can be used as a basis for some very powerful layouts. If you're responsible for supporting IE and Edge, it will come down to a judgment call on whether or not your project warrants the code it takes to account for them. It's also true that sites don't necessarily have to look the same in all browsers. And because grid layouts are so easy to construct, they're probably worth the extra time.

I think it's worth taking some time to consider whether your project would benefit from CSS Grid and use the @supports rule if it would.

Conclusion

CSS Grid is changing the way layouts on the web are constructed and how they work. Browser support is probably always going to be an issue for web technologies but the saving grace here is that it's really not that bad for CSS Grid. And even then, the differences are easily accounted for in our code. CSS Grid layouts are awesome and powerful and with a little convenience help from tools like Sass, they can also be compatible.