DISCOVERY

January 24th, 2019

CSS Grid Backwards Compatibility

CSS

CSS Grid

HTML

When I created my personal website, I wanted to use all the latest technologies. I created a modern front-end with React.js, Webpack, Sass, and the latest JavaScript. When it came to stylesheets, I used the latest features that ease website layout creation. One of these features is CSS Grid. I wrote an article about CSS Grid over the summer, explaining how it simplifies complex CSS layouts. As with all new web technologies, an issue with CSS Grid is that older browsers don't support it. This article looks at some of the workarounds to make CSS Grid backwards compatible to older browsers.

I took three components from my website and simplified them to show how they work on older browsers. All modern browsers (Chrome, Edge, Firefox, Opera, Safari) implement feature queries, which check if certain stylesheet features are available in the browser environment1,2. Feature queries are created with the @supports CSS rule.

One of the big issues with my website was CSS Grid didn't work properly in Microsoft Edge. This was due to Edge implementing an older spec of CSS Grid. I used feature queries in my stylesheets to provide an equal viewing experience between Edge and the rest of the modern browsers.

Unfortunately, Internet Explorer does not support feature queries. If you are looking for IE support and also want to leverage new CSS features, you can use feature detection libraries such as Modernizr. The rest of this article uses my three components to explain feature queries and creating backwards compatible CSS Grid stylesheets.

The first layout example is similar to the one used in my software development articles (like the one you are currently viewing).

Here is the HTML and relevant CSS styles for this layout:

<body> <header class="header"> <p>Software Discovery</p> <p>January 10th, 2019</p> </header> <div> <h1>CSS Grid Backwards Compatibility</h1> <div> <p> This article discusses how to make CSS Grid web pages backwards compatible to older browsers. </p> </div> <div> <p> <strong>[1]</strong> CSS Grid </p> </div> </div> <footer> <figure> <img src="https://asset.jarombek.com/jarombek.png"> </figure> </footer> </body>
/* Layout for CSS Grid supporting browsers */ @supports (grid-area: auto) { body { display: grid; grid-gap: 10px; grid-template-columns: 1fr 3fr 1fr; grid-template-areas: "header header header" ". body . " ". footer . "; } header { grid-area: header; display: grid; grid-template-columns: 1fr 2fr 1fr; grid-template-areas: "type . date"; } header > p:nth-child(1) { grid-area: type; justify-self: start; align-self: center; padding-left: 20px; } header > p:nth-child(2) { grid-area: date; justify-self: end; align-self: center; padding-right: 20px; } body > div { grid-area: body; justify-self: center; align-self: center; } footer { grid-area: footer; justify-self: center; align-self: center; } } /* Layout for legacy browsers */ @supports not (grid-area: auto) { header { display: table; height: 45px; width: 100%; } header p { display: table-cell; vertical-align: middle; height: 100%; width: 50%; } header:nth-child(1) { text-align: left; padding-left: 20px; } header:nth-child(2) { text-align: right; padding-right: 20px; } }

In this layout, browsers supporting grid-area: auto use styles within the @supports (grid-area: auto) {...} rule block. Browsers unsupportive of grid-area: auto use styles within the @supports not (grid-area: auto) {...} rule block.

For browsers not supporting CSS Grid, I replaced display: grid with display: table. The display property is used to determine the display type of an HTML element. Both the grid and table values for display alter how child elements are laid out3. While display: grid defines a CSS Grid container, display: table creates a table layout with rows and columns containing cells. Table layout is just like an HTML table where the element <tr> represents a table row and the element <td> represents a table cell. The corresponding display values are table-row and table-cell, respectively4.

With the table layout I created a similar view to the one built with CSS Grid. I gave both article headers the display: table-cell definition. Table cells can be vertically positioned just like grid areas in CSS Grid5. While CSS Grid uses align-self to position elements vertically inside their grid area, table cells use vertical-align. vertical-align: middle positions the contents of a table cell in the middle of the cell6.

The rest of the HTML component doesn't need a grid layout, making it easy to convert for older browsers.

The second layout example is a technology tag that I use at the top of my software development articles. This article has CSS, CSS Grid, and HTML tags.

Here is the HTML and relevant CSS styles for this layout:

<body> <div> <figure> <img src="https://asset.jarombek.com/jarombek.png" /> </figure> <p>CSS Grid</p> </div> </body>
/* Layout for CSS Grid supporting browsers */ @supports (grid-area: auto) { body { display: grid; align-items: center; justify-items: center; height: calc(100vh - 16px); } div { display: grid; grid-template-rows: [top] 100% [bottom]; grid-template-columns: [image] 40px [label] calc(100% - 39px) [end]; } figure { grid-area: top / image / bottom / label; justify-self: center; align-self: center; } p { grid-area: top / label / bottom / end; justify-self: center; align-self: center; } } /* Layout for legacy browsers */ @supports not (grid-area: auto) { body { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } div { display: table; } figure { display: table-cell; vertical-align: middle; } p { display: table-cell; vertical-align: middle; } }

Once again I'm using display: table as a replacement for display: grid. This time around I'm also centering the tag component in the middle of the the <body> element. In CSS Grid, I'm using align-items: center and justify-items: center to align children elements in the middle of the page vertically and horizontally, respectively.

For older browsers, things get a bit more complex. First I use the position: absolute definition, which positions <body> relative to its nearest positioned relative. A positioned element is an HTML element with a position property of value relative, fixed, absolute or sticky. Since <body> has no positioned ancestor, its positioned relative to the webpage document7.

With absolute positioning, the top: 50% and left: 50% definitions place <body> in the middle of the webpage document. The only issue with these two definitions is they place the top left corner of <body> in the middle of the webpage. Therefore the tag component appears misaligned from the center. To fix this I use the transform property. transform: translate(-50%, -50%) feels like a hack to get the central positioning perfect, but sometimes with legacy CSS hacks are required8! translate() repositions an element along the x-axis and y-axis of the webpage. translate(-50%, -50%) moves <body> 50% of its height upwards along the y-axis and 50% of its width leftwards along the x-axis. Now the <body> element is centered!

The third layout example displays a feature for the website. My website home page has three feature components.

Here is the HTML and relevant CSS styles for this layout:

<body> <div class="feature"> <div> <div class="feature-text"> <h5>Articles</h5> <p>Read software development articles I've written and follow my progress as a programmer.</p> </div> <div class="feature-picture"> <figure> <img src="https://asset.jarombek.com/tech_logos_white.svg"/> </figure> </div> </div> </div> </body>
/* Layout for CSS Grid supporting browsers */ @supports (grid-area: auto) { body { display: grid; align-items: center; justify-items: center; height: 100vh; margin: 0; } .feature > div { display: grid; grid-template-columns: 1fr 1fr; grid-template-areas: "content picture"; grid-gap: 20px; } .feature-text, .feature-picture { justify-self: center; align-self: center; } .feature-text { grid-area: content; } .feature-picture { grid-area: picture; } } /* Layout for legacy browsers */ @supports not (grid-area: auto) { body { position: absolute; top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); } .feature > div { display: table; height: 100%; width: 100%; float: left; } .feature-text { display: table-cell; vertical-align: middle; height: 100%; width: 50%; } .feature-picture { float: left; margin-top: 15vh; } }

The concepts covered in my first two layouts will help you understand the code for my website features.

While it's fun to work with the latest browser technologies, we still need to support users that aren't as bleeding edge. Feature queries with the @supports CSS rule will soon be all that's needed to support legacy browsers as Internet Explorer usage continues to dwindle. All the code from this discovery post is available on GitHub.