This post is part three of a three-part series about providing support for IE11 when working with CSS Grid.
Part One – Providing Basic CSS Grid Support.
Part Two – Finding ways to use CSS Grid properties that are not supported.
Ok, so by now if you have followed my first two posts you should have something in IE11 that looks pretty close to the layout you’ve created in modern browsers. But there is nearly always something that just won’t work, no matter how hard you try to make it, and that is when you maybe need to take a different approach…
Using Feature Queries.
I briefly covered Feature Queries in part two. They are another super cool addition to the CSS3 specification and look and work in a similar way to @media
queries. But instead of detecting device characteristics, they look for CSS properties that are supported by the browser being used.
These are a great way to progressively enhance your CSS because generally it is considered good practice to first write CSS that works in all browsers, and then enhance it for modern browsers by adding new properties, but only if they are supported.
A typical feature query would look like this:
@supports( display: grid ) {
...
}
If display: grid
is supported by the browser, then any code that is wrapped inside is run. If it isn’t, then the code isn’t run either.
The times I most often find that I need to take this approach is when I’m trying to provide support for auto-placement. This is a pretty rare edge case and I’ve only really needed when I don’t know how many rows there will be so can’t manually place each item.
For example, I recently worked on a WordPress project where the designer had outlined a very specific 12 column grid for a content area and exactly how many columns the component within should span. This seemed an ideal opportunity to use CSS Grid as it would allow me to position all of the content components (Gutenberg Blocks) within a grid exactly as the designer wanted, and they would then autoflow down the page.
In modern browsers, this worked really well, but unfortunately, it didn’t work in IE. Because the content blocks are created by a user, there is no way to know whether a page would have 20 blocks or only 3 to be able to explicitly place them all.
In this case, the decision was made to drop using CSS Grid on the content area for IE and use flexbox instead, but still continue to use Grid in modern browsers. This was achieved by using the @supports
feature query:
.grid__container {
display: flex;
flex-flow: row wrap;
@supports( display: grid ) {
display: grid;
grid-template-columns: repeat( 3, 1fr );
}
}
Here we’ve set the container to display: flex
in all browsers, but then in browsers that support Grid, it is set to display: grid
instead. The only thing left after that is a few specific styles for the grid__items.
Why isn’t this styling a layout twice?
This seems like you are defining two layouts for the same page, and you would be forgiven for dismissing this as a lot of extra time and effort, but it isn’t really.
What is nice about the CSS display property is, once display: grid
has been set, it automatically cancels out any other display properties and any associated properties. Therefore we don’t need to add a lot of extra CSS to cancel them out manually.
For example, here we’ve used display: flex
. This gets cancelled out by display: grid
, which we would expect because it’s further down in the cascade. However, all other flexbox properties are now void as well. We’ve now set our grid columns using grid-template-columns
, this tells us how many items per row there would be and their maximum size. The content is then auto-placed within this grid. Flexbox properties like flex-direction
and flex-grow
etc. don’t need to be cancelled out because they no longer have any effect.
Similarly, had we gone truly old school and created a grid using display: block, floats and margins. As soon as display: grid;
is applied, display: block
is cancelled out and because we’ve defined our columns and the content is auto-placed, float has no effect either. The only property that would need cancelling is the margins applied (see grid-gap in part two).
Using @supports not ().
So it’s clear that feature queries are pretty neat. However, being totally honest, when trying to provide support for IE they are nearly always a last resort for me. This is because, I usually only find I need them when I’m testing my layout in IE11 and discovered that because of an edge case, none of the fallbacks and techniques I’ve already outlined will work. At this point you’re no longer trying to progressively enhance your CSS, you are instead trying to retro-fit support.
Rather than having to add the additional flexbox fallback to already existing styles and risk causing side-effects in other browsers, then add in the @supports
rule so that modern browsers can use grid instead, wouldn’t it be great if we could add our fallbacks only if something is not supported?
@supports
can do this by using the not
keyword:
@supports not ( display: grid ) {
display: grid;
}
This looks great and should be exactly what is needed. However, there is one major problem with this approach and it has tripped me up multiple times. IE11 doesn’t support feature queries and will, therefore, ignore it completely. Meaning any and all fallbacks we write specifically for this will be ignored.
IE Feature Detection Mixin.
This mixin was shared with me by some of my colleagues at Human Made, when I was working on a project where I did have to retrofit support for IE11 after I had almost completed the project. It was a total lifesaver!
@mixin ie-query {
@media all and
( -ms-high-contrast: none ),
( -ms-high-contrast: active ) {
@content;
}
}
Essentially it is a standard media query set to detect -ms-high-contrast
. Because the feature being detected is prefixed with -ms
, it only applies to Microsoft browsers, and, high-contrast is only available in IE10 +, therefore any CSS written inside this mixin will only be applied in Internet Explorer:
body {
@include ie-query {
background-color: red;
}
}
In this example, the main page body is given a background-color
of red, which is only applied in IE. Great! This is basically what I had wanted from @supports not ()
In an ideal world, this shouldn’t really be needed, we should allow the cascade to work its magic, set styles for older browsers first and allow them to be overwritten by styles for newer browsers if they are supported.
However, we’ve all been on a project where we’ve had to retrofit support afterwards. To do things “the right way” could involve a massive amount of refactoring, and we don’t want any changes we make to support IE11 to affect the work we’ve already done either. This mixin allows us to target only what we need to.
Sending Headers.
This is something that we (hopefully) rarely have to consider these days, but if you are working on a project for a large organisation whose IT infrastructure is locked down tight, and your stakeholders have no control over their own settings. It’s very likely they are all forced to use IE11 still and worse…. Compatibility Mode will be switched on 😱
Luckily, even though all of the articles I found on the internet about this are super old now, there is an easy fix:
<meta http-equiv="X-UA-Compatible" content="IE=edge">
By adding this meta tag to the head of your website, we are specifying that all IE browser versions should use a minimum of the Edge rendering engine.
This may not be a CSS fix but, if the websites you are building are being viewed in compatibility mode, then without this one change none of your CSS Grid fallbacks will work.
Finished.
Ok, so now we are finished.
This is my toolkit for providing support for IE11 whether, I write it in from the beginning of the project and progressively enhance my code base or I have to retrofit a project to support IE11 afterwards.
I haven’t covered all aspects of the CSS Grid Specification, or all of the ways you can create your layouts to work in IE, I’ve tried to stick to methods and techniques that I need most often. There are a lot of different and creative ways to provide support, for example, there is an argument to not use any of the -ms-
prefixes and instead create your layout using floats, or flexbox and nest your Grid related CSS inside feature queries. Which is a perfectly good solution as well.
Personally, I rarely need to support browsers older than IE11 now, so I don’t like to create my layouts using floats first. I find that by using the toolkit I have outlined in these posts, I can create fallbacks using the -ms- prefixes just as easily, and allow SASS to output most of the repetition for me, saving me development time as well.
Hopefully, this gives you all a solid idea of how you can provide support for IE when working with CSS Grid. There will come a day when we no longer need to provide support for IE11, but until that day, I hope people find this series useful. 🙂
Further Reading:
- How @supports works – CSS Tricks
- A Guide to CSS Support in Browsers – Rachel Andrew, Smashing Magazine
- How @supports works – CSS Tricks
- X-UA-Compatibility Meta Tag and HTTP Response Header – Microsoft Docs