Supporting IE – Part Three: The Last Resort! CSS Grid tips, hacks and workarounds.

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:

Supporting IE – Part Two: Finding ways to use CSS Grid properties that are not supported.

This post is part two of a three-part series about providing support for IE11 when working with CSS Grid.
Part One – Providing Basic CSS Grid Support.
Part Three – The last resort! CSS Grid tips, hacks and workarounds.

(This article assumes a reasonable knowledge of SASS, CSS and some understanding of using CSS Grid.)

In my last post, I mentioned that there are some small tweaks and edge cases that will still have to be accounted to provide full support for IE11, and most of these happen when using properties that are not supported in IE at all.

Rachel Andrew already does an excellent job of outlining what isnā€™t supported in her article, Should I try to use the IE implementation of CSS Grid?, and I donā€™t want to repeat that, so I wonā€™t list everything again in this post. Instead, Iā€™m only going to focus on the three main features that I regularly have to find a solution to somehow.

Auto-placement.

The eagle-eyed of you may have noticed that while I did discuss placing items within the grid in my previous post, I deliberately didnā€™t mention auto-placement. This is because it is the one feature that I find can become a headache to try to provide IE11 fallbacks for.

The problem comes when you donā€™t need to explicitly place your content in a grid, for example, an archive page on a blog. On pages like these, we want our grid items to be placed one per column and autoflow down the page, creating as many rows as needed. With auto-placement, this is made easy and we donā€™t have to provide any CSS to do that in modern browsers. In IE11 though, because you havenā€™t explicitly set the position of each grid item, they will all sit in column one, row one, on top of each other. Which is definitely not good.

Explicitly placing each grid item will fix this for you but, if you have a three-column grid with four rows, and a total of twelve grid items that all need to be explicitly placed, that will mean a lot of extra CSS. It would look something like this:

.grid__item:first-child {
	-ms-grid-column: 1; 
	-ms-grid-column-span: 1;
	grid-column: 1 / 2;
	-ms-grid-row: 1; 
	-ms-grid-row-span: 1;
	grid-row: 1 / 2;
}

.grid__item:nth-child(2) {
	-ms-grid-column: 2;
	-ms-grid-column-span: 1;
	grid-column: 2 / 3;
	-ms-grid-row: 1;
	-ms-grid-row-span: 1;
	grid-row: 1 / 2;
}

...

Here Iā€™ve used nth-child to select each grid__item and explicitly place it on the grid. This is now a lot of code to place each item, and if you then consider adding media queries into the mix then you can imagine the code soup it will create. This is pretty horrible and definitely deserving of theĀ  šŸ˜¢šŸ”„šŸ—‘emojis.

Letting SASS do the clean up.

We can’t avoid needing all of this extra code, unfortunately, but there are a few things we can do to clean it up and automate using Sass Mixins. For example, I first saw this mixin on CSS Tricks some time ago, and it provides a simple solution to reduce the number of lines we have to write each time:

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

This is a simple SASS mixin (simple because there isn’t any loops or functions being used), which has extracted the repeated code for placing each grid__item so that instead of repeating six lines of code on each property, we can re-use the mixin instead, making our outputted SCSS look like:

.grid__item:first-child {
	@include grid-child( 1, 2, 1, 2 );
}

.grid__item:nth-child(2) {
	@include grid-child( 2, 3, 1, 2  );
}

...

We could take this a step further and automate the output including each nth-child. In the example mentioned above, we know that there should be a three-column grid, so we could create the output for column placements like this:

@mixin ie-grid-columns(
	$columns: 3,
) {
	// Columns.
	@for $i from 1 through $columns {
		> :nth-child(#{$columns}n + #{$i}) {
			-ms-grid-column: ( ( $i + $columns ) - $columns );
			grid-column: ( ( $i + $columns ) - $columns ) / span 1;
		}
	}
}

Here, we start by defining a set number of columns, in this example, the value is 3. We then use the @for SASS loop to assign the nth-child value to each .grid__item. For example, when looping through, if $i is equal to 2, then the nth-child becomes 3n + 2 allowing us to select all grid items in multiples of 3 starting from 2 (2, 5, 8, 11 etc.).

Now instead of having to write out each .grid__item:nth-child() {} and apply a mixin with different values, we can apply this mixin to our grid container and it will apply each nth-child to the children in that container, in order, and the corresponding grid-column placement.

.grid__container {
	@include ie-grid-columns;
}

This saves us having to manually write out lots of extra code and all of the CSS needed to place items in columns in IE11 is still outputted when the SCSS is compiled.

A similar process can also be applied to rows. We know that because we have twelve posts and three columns there should be four rows. The mixin would look like this:

@mixin ie-grid-rows(
	$posts: 12
) {
	@for $i from 1 through $posts {
		> :nth-child(#{$i}) {
			@if $i >= 1 and $i <= 3 {
				-ms-grid-row: 1;
				grid-row-start: 1;
			}
			@if $i >= 4 and $i <= 6 {
				-ms-grid-row: 2;
				grid-row-start: 2;
			}
			@if $i >= 7 and $i <= 9 {
				-ms-grid-row: 3;
				grid-row-start: 3;
			}
			@if $i >= 10 and $i <= 12 {
				-ms-grid-row: 4;
				grid-row-start: 4;
			}
		}
	}
}

This time we set a number of posts, then using the @for loop again we loop through each grid__item, check whether $i is within a set range and then position it in the correct row.

Admittedly this isn’t anywhere near as elegant as the mixin for columns. It would be super nice to be able to select the first three grid__items, then the next three, then the next three, and so on without having to use an @if statement with hard-coded values, and I’m sure there is someone out there that can figure out the maths to do that. However, this does still go a long way towards helping to cut down the amount of code you have to write to get around the issue of IE11 not supporting auto-placement.

Note: While fact-checking these articles, I discovered that we could also use grid-template-areas here, which Autoprefixer does support and would create fallbacks for us rather than having to use mixins.

However, I haven’t ever used this technique in a production environment so I’m not covering it in this article. If you want to read more, check out CSS Grid in IE: CSS Grid and the NewĀ Autoprefixer.

repeat()

As I mentioned when discussing the use of Autoprefixer in part one, the repeat() function, while super cool, is not supported in IE. There is the [] syntax which you can use, and this is a perfectly acceptable solution, however, it does require you to manually add it in so that there are two lines of code. Most often this will occur when using grid-template-columns or grid-template-rows. For example:

-ms-grid-columns: 1fr[12];
grid-template-columns: repeat( 12, 1fr );

Letting SASS automate repeat.

Another way to ensure we have twelve columns that are all 1fr is to manually write 1fr out twelve times. Nobody wants to do this, but we could easily use SASS mixins to automate this for us. For example:

@mixin ie-repeatable-columns( $columns, $width ) {
	$r: '';
	@for $i from 1 through $columns {
		$r: $r + ' ' + $width;
	}
	-ms-grid-columns:#{$r};
	grid-template-columns: repeat( #{$columns}, #{$width} );
}

In this mixin, we have the option to add a custom number of columns and width, using $columnsand $width. We then create the variable $r. This will store the outputted value for the columns.

Using the @for loop again we loop through all of the columns and add the inputted $width for each column to the $r variable. The last thing we do is we then output the CSS properties and generated values for the grid columns.

Tip: Notice that in the output of this mixin we have interpolated both $r, $columns and $width. Without this interpolation, these values would be outputted inside “”, which would create invalid CSS. By interpolating them (wrapping them in #{}) they are outputted without quotation marks.

See further reading at the bottom of this post for more information on interpolation.

This allows us to use the mixin like this:

.grid__container {
	ie-repeatable-columns( 5, 1fr );
}

Which when the SASS has been compiled to CSS would output:

.grid__container {
	-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr;
	grid-template-columns: repeat( 5, 1fr );
}

Either using [] or a mixin would work to support the repeat() function in IE. However, with some modification the sass mixin could be made to also help support grid-gap (see below), whereas I don’t believe using [] instead of repeat() can.

grid-gap

Grid-gap is a nice little feature which works especially well when using the fr unit to calculate column and row sizes. Unfortunately, though, this super useful feature only has partial support in IE11.

If we had a three column grid with a 10px grid-gap, for modern browsers we would define it like this:

.grid__container {
	display: grid;
	grid-gap: 10px;
	grid-template-columns: repeat( 3, 1fr );
}

When providing support for IE though, there is no prefixed version for grid-gap, instead we can create the gaps by using the prefixed -ms-grid-columns instead. For example:

-ms-grid-columns: 1fr 10px 1fr 10px 1fr;

Now, we still have three columns that are 1fr wide each, but now we’ve also added two grid-gaps that are 10px wide as well!

The good news here is that this is something that Autoprefixer can automatically fix for us. The caveat though is that it will only work if both grid-template-columns and grid-template-rows are defined. This is because grid-gap defines both the gap between columns and rows, therefore Autoprefixer will want to apply 10px gaps to both properties. The full code with IE support for this grid would look like:

.grid__container {
	display: -ms-grid;
	display: grid;
	grid-gap: 10px;
	-ms-grid-columns: 1fr 10px 1fr 10px 1fr;
	grid-template-columns: repeat( 3, 1fr );
	-ms-grid-columns: 1fr 10px 1fr 10px 1fr;
	grid-template-columns: repeat( 3, 1fr );
}

This example does away with all of the fallbacks for supporting the repeat() function mentioned above. We could modify the sass mixin to include grid-gaps as well, although, this does start to get pretty complicated. Or we could use a feature query.

Using the @supports feature query

Another approach would be to make use of the @supports feature query instead, like this:

.grid__container {
	display: grid;
	grid-gap: 10px;
}

.grid__item {
	margin: 5px;

	@supports( display: grid ) {
		margin: 0;
	}
}

What is happening here is, grid-gap is set on the grid__container, this would be applied in modern browsers but because it is not supported in IE it would be ignored. A margin of 5px is then added to all sides of each grid__item, to create a gap around and is globally applied in all browsers. Then using @supports, if the browser used to view the website supports display: grid, the margin is removed from each grid__item. This is because grid-gap is already being applied in modern browsers and we don’t need to apply margins as well. In the case of IE11, the feature query is not supported and therefore the margin: 0 within is ignored.

This might seem a little long winded but it could be really useful if the grid you are creating is fairly complex and automating or autoprefixing don’t work as needed.

Finished?

Unfortunately, there is no avoiding the extra lines of code that are needed to ensure we provide full support for CSS Grid in IE11. But in a lot of cases, by using a preprocessor, we can take most of the pain away of having to write a lot of repetitive CSS.

However, there is always at least one area of your website where your IE11 fallbacks simply won’t play nicely and you have to resort to some more drastic measures. In the last post in this series I will go through some tips (and hacks) I’ve used when really nothing else will work.


Further Reading:


Supporting IE – Part One: Providing basic CSS Grid support.


This post is part one of a three-part series about providing support for IE11 when working with CSS Grid.

Part Two – Finding ways to use CSS Grid Properties that are not supported.
Part Three – The last resort! CSS Grid tips, hacks and workarounds.

There is one question, as frontend developers, that we all dread and that is ā€œwill it work in IE11?ā€ 

This is especially true when using CSS Grid. Last year, I spent a lot of time talking about CSS Grid and every conference or meetup I spoke at, I was always asked this question.

Iā€™ve worked with CSS Grid on production sites for 2-3 years now to varying degrees, and where needed, all of them work in IE11 as well. There are times where the experience created for IE11 does not exactly match what has been built for modern browsers, some of the time Iā€™ve written the CSS with progressive enhancement in mind and other times, Iā€™ve had to retrofit my CSS to support IE11 afterwards. Each approach provides its own challenges,  so I thought it would be useful to share some of the techniques Iā€™ve used on different projects in a series of blog posts.

(This article assumes a reasonable knowledge of CSS and some understanding of using CSS Grid.)

CSS Grid is supported in IE11.

A lot of people immediately assume that CSS Grid is not supported in IE11 at all or you need polyfills to make it work. However, an early version of the CSS Grid specification does work in both IE10 and IE11. 

Some of the syntax is different and with some properties, itā€™s not quite as easy as adding a prefixed version as well, so it is important to understand what is different, but it is possible to build a site using CSS Grid and have it work in IE11. 

Possibly the most useful article Iā€™ve ever read on this and I still refer to it often is Rachel Andrewā€™s Should I try to use the IE implementation of CSS Grid? It features a really useful table showing the Level 1 Specification of many of the commonly used properties, whether there is an IE version available for that property, and also whether Autoprefixer will recognise it or not.

The Autoprefixer column is out of date now, but I find the direct comparisons between each spec in the table to be really useful still.

Note: After initially posting this article Rachel Andrew pointed me to her follow up article Should I try to use the IE version of Grid Layout? Revisited for 2018.

In it, she discusses whether you should try to support IE11 when using CSS Grid. This is a very valid question and it is perfectly ok not to support CSS Grid in older browsers, however, this series of posts isn’t aiming to tackle that question, it is a series of tips for those times when you do find you have to support it.

Getting Started.

Whenever I think about support for IE11, I look at three key areas:

  1. The display property,
  2. Defining the grid itself and
  3. Placing items within the grid.

If we can make sure all three of these are working as expected within IE11, then you can be confident that 90% of the work is done, the rest is usually small tweaks and edge cases.

From looking at Rachelā€™s article you would be forgiven for thinking that Autoprefixer is most definitely not the answer, there is a lot it can do for us now. But…

Should we rely on Autoprefixer?

The newer versions of Autoprefixer can create a lot of fallbacks, however, it can’t do all of the hard work for us, there are some limitations still. If you are interested in reading more about what it can and can’t do I would recommend reading CSS Grid in IE: CSS Grid and the new Autoprefixer.

There could also be situations where your build process has to use an older version that cannot do all of this, or the auto-prefixed version creates unexpected changes in your layouts or a myriad of other reasons.

Therefore, I believe it is worth taking the time to fully understand the differences between the Level 1 spec and the modern specification and not rely on Autoprefixer to automatically fix it for us.

Using display: grid;

In order to use CSS Grid on a selector we first need to set the display property to grid, like this: 

 display: grid;

However, the prefixed equivalent for IE is a little different and looks like:

display: -ms-grid;

Note the prefix is applied to the value and not the property itself. 

To define the grid in IE and modern browsers we need to include both lines in our CSS so that it looks like:

display: -ms-grid;
display: grid;

This way IE will see the CSS specifically for that and modern browsers will skip over it and use the newer specification below.

TIP: Often, I will extract both of these display settings into a SASS mixin so that I can always ensure that the -ms- prefix is applied.

I find this helpful, especially when using CSS Grid in multiple places, because even though I could add these two lines to bigger grid mixins (i.e. if I’m defining a layout of posts or a footer layout etc.) there will always be times it is needed outside of other mixins.

There are a number of other subtle differences in how the properties are used as well. 

Using the grid-template-columns and grid-template-rows properties.

Now that we have set the display property to grid, we need to set how many columns and/or rows there will be inside of it. One way to do this is using the grid-template-columns and grid-template-rows properties. 

Autoprefixer can automatically update these for us. So

grid-template-columns: 1fr 1fr 1fr 1fr;

Would become:

-ms-grid-columns: 1fr 1fr 1fr 1fr;

Which is pretty nice and can save us a job! 

The problem here though is that if all of the columns are the same width, you wouldnā€™t manually write out the value for each column, you would use the repeat() function that was introduced as part of the CSS grid spec instead. Like this:

grid-template-columns: repeat( 4, 1fr );

Autoprefixer would then update that to:

-ms-grid-columns: repeat( 4, 1fr );

Which unfortunately is invalid. This is because although Autoprefixer can fix the grid columns property, but the syntax for repeat() is different. You could write out the values for the columns manually instead.

For example: 

grid-template-columns: repeat( 4, 1fr );

Would have to become:

-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr;

But, if you have a twelve column grid or something even bigger, the gets messy and is pretty laborious. Instead you could use the IE syntax, which would look like:

-ms-grid-columns: 1fr[4];

Instead of using repeat(), we use [ ] and specify the number of times we wish to repeat 1fr. Which is much nicer!

Using the `grid-column` and `grid-row` properties

There is now only one key area left to address, and that is placing items in the grid.

We can do this using the grid-column-start, grid-column-end, grid-row-start and grid-row-end properties, or by using the shorthand properties grid-column and grid-row. For example:

grid-column: 2 / 4;

Or 

grid-column: 2 / span 2;

This tells a content item within the grid to start on column track line number 2 (see further reading if you are unsure of what grid track lines are) and end at track line number 4 and therefore spanning 2 columns.

However, the prefixed version -ms-grid-column only requires and applies a start value. If you rely on Autoprefixer to fix this, you will end up with an invalid property because it would get updated to:

-ms-grid-column: 2 / 4;

when it should actually be 

-ms-grid-column: 2;

This still only goes part of the way to solving the problem of providing a fallback, we have now set a start point, but we still need to tell the grid item that it needs to span 2 columns. In the original property we did that by setting the endpoint to 4 or setting span 2, for IE we need to set a span number using a different property instead like this:

-ms-grid-column-span: 2;

This would make our property and our IE fallback look like:

-ms-grid-column: 2;
-ms-grid-column-span: 2;
grid-column: 2 / 4;

If you wanted your grid item to only span one column you can omit the -ms-grid-column-span property but it still looks pretty ugly.

Add in some row information as well, for example: 

-ms-grid-column: 2;
-ms-grid-column-span: 2;
grid-column: 2 / 4;

-ms-grid-row: 1;
-ms-grid-row-span: 3;
grid-row: 1 / 4;

And suddenly you have a lot of lines of CSS. This is pretty ugly, so I always like to add the  šŸ˜¢šŸ”„šŸ—‘emojis in a comment to pretty it up again..

Of course, you don’t have to use the shorthand properties, you could use the longhand versions, but autoprefixer still wouldn’t be able to fix these. -ms-grid-column isn’t a prefixed version of grid-column-start and -ms-grid-column-span sets how many columns to span rather than the column track line to end on. You would end up with even more lines of code:

-ms-grid-column: 2;
grid-column-start: 2;
-ms-grid-column-span: 2;
grid-column-end: 4;

Which, when you add in the row information as well, makes it look even more like code soup:

-ms-grid-column: 2;
grid-column-start: 2;
-ms-grid-column-span: 2;
grid-column-end: 4;

-ms-grid-row: 1;
grid-row-start: 1
-ms-grid-row-span: 3;
grid-row-end: 4;

Using the shorthand version and then providing IE11 fallbacks, may only save one line of code per property but I like to think that every line of code saved, saves a kittens life somewhere in the world!

Finished?

For simple CSS Grid layouts, this is pretty much the extent of what you need to do to ensure they display as expected in IE11. There are no hacks (depending on whether you consider prefixes hacks) and no polyfills needed.

Providing support for IE11 can be tricky but in most cases, many of the problems can be avoided simply by not relying on Autoprefixer to fix it for you. Once you know and understand the differences between the current specification and the IE10 & IE11 specification providing support for older browsers becomes much easier to achieve.


Further Reading:


Using CSS to honour visual preferences

At the beginning of October, I attended both ViewSource and Fronteers Conferences in Amsterdam (write up to come still). One of the many takeaways from those conferences was from a talk by Melanie Richards, a member of the Microsoft Edge platform team and participant of the W3C web standards communities, including the CSS Working Group. During her talk, she introduced some new CSS media queries to help websites honour peoples visual preferences.

Some of the media queries she covered are a little way out yet because the standards for them are still under discussion, but one that we can use now is:

@media ( prefers-color-scheme: value ) {}

This media query honours which theme you have chosen for your OS, light or dark, and will allow you to adjust a websites colour scheme accordingly. This means that with only a few additional lines of CSS, we can have a massive impact on a user’s visual experience of the sites we build.

Using prefers-color-scheme

@media ( prefers-color-scheme: value ) {} works, pretty much the same way as any other media query, but will only accept one of three values: no-preference | light | dark.

So, if we want to make some changes to our themes colour scheme that would only take effect if the operating system is using dark mode, we could set some custom properties like this:

:root {
    --bg-color: white;
    --color-brand: red; 
    --color-text: black;

    @media ( prefers-color-scheme: dark ) {
        --bg-color: black;
        --color-brand: yellow; 
        --color-text: white;
    }
}

Our base CSS would then look like:

body {
    background-color: var( --bg-color );
    color: var( --color-text );
}

a {
    color: var( --color-brand );
}

When the operating system is set to light mode or it’s not specified, this example website would have a white background, black text and red links. But when changed to dark mode it would have a black background, white text and yellow links. Pretty neat right?

Using this technique we can do other things to help honour visual preferences as well, like reducing the brightness of images when in dark mode by applying filter:

@media ( prefers-color-scheme: dark ) {
    filter:
    brightness(.8)
    contrast(1.2);
}

If changing the brightness and contrast didn’t help enough, we could instead swap out the image and replace it with another one by using the media query within the <picture> element instead.

<picture>
    <source srcset="image-dark.jpg" media="(prefers-color-scheme: dark)">
    <img src="image-light.jpg" alt="light image">
</picture>

Something that is also extremely useful is using currentColor to control the colour of inline SVGs. If we had an SVG on our site that was wrapped in <a> tag, maybe a company logo, like this:

<a href="">
    <svg />
</a>

We could set the CSS for that SVG as:

svg {
    fill: currentColor;
}

instead of specifying a hex value for the fill.

currentColor works by inheriting the specified colour value of an outer container, if nothing is specified it will default to black. It gets used a lot on SVGs, but it can be used anywhere a colour value can be specified.

In this example, because a colour has been set for the <a> tag already using custom properties and the @media ( prefers-color-scheme: dark ) {} media query, we don’t need to write any extra lines of CSS to change the colour of the SVG depending on the light or dark mode. If we apply currentColor to any strokes or fills, the SVG will take on the colours of the surrounding <a> tag. Awesome šŸ™‚

Hopefully, you all agree that this is already pretty powerful, as more new features get added to operating systems, more CSS will be introduced allowing us to tailor the visual experience to the user’s individual needs more and more.

And what I really like about it is, we don’t need to worry about browser compatibility either. If the browser does not support this media query then it will most probably be an older browser on an old operating system that doesn’t have the option to switch between light and dark mode anyway, so it will just be ignored. Awesome! šŸŽ‰

If you would like to have a look at the CodePen I used to experiment with this, it can be found here: https://codepen.io/kirstyburgoine/pen/GRRJmBK View the pen and change your colour scheme in your operating systems to see the changes.