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:


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s