CSS Grid in IE: Faking an Auto-Placement Grid with Gaps

Avatar of Daniel Tonon
Daniel Tonon on (Updated on )

📣 Freelancers, Developers, and Part-Time Agency Owners: Kickstart Your Own Digital Agency with UACADEMY Launch by UGURUS 📣

This is the third and final part in a three-part series about using CSS grid safely in Internet Explorer 11 (IE11) without going insane.

In Part 1, I covered some of the common misconceptions that people have about IE11’s native CSS grid implementation. In Part 2, I showed the world how easy it actually is to write IE-friendly CSS grid code.

Today, I’m going step away from CSS grid for a moment to show you a flexbox technique that replicates basic CSS grid auto-placement functionality. This CSS grid replica will even look like a grid-gap has been applied to it. I need to be super clear though: this is not about how to make actual CSS grid auto-placement work in IE.

Article Series:

  1. Debunking common IE Grid misconceptions
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps (This Post)
  4. Duplicate area names now supported!

How to make a fake grid with cell gaps

Step 1: HTML

I’ll use this basic HTML as an example:




<div class="grid-wrapper">




<div class="grid">



<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>



</div>



  
</div>

Step 2: Border-box box sizing

The first thing that we need to do in the CSS is make sure that all of the boxes are being sized based on border-box rather than content-box. The best way to do that is using the box-sizing: border-box inheritance technique:

html {
  box-sizing: border-box;
}

*, *::before, *::after {
  box-sizing: inherit;
}

That will be applied globally. If you are working on an an existing project that doesn’t have box-sizing set to border-box, then change html in the snippet to a selector that targets the element you want to turn into a grid.

Step 3: Flex

Next, you will need to turn on some flexbox settings:

.grid {
  /* Forces equal cell heights */
  display: flex;
  flex-wrap: wrap;
}

Step 4: Widths

Now, set up your column widths. We’ll make ourselves a simple three-column grid:

.grid-cell {
  /* Sets column count */
  width: calc(100% / 3); /* calc() method */
  width: 33.33%; /* percentage method */
}

The calc() method allows the column widths to be changed a bit more easily. You state how many columns you want and the browser does the math for you. This is especially handy for when you need a larger number of columns, like 7 or 8. The browser support for calc() is strong but not as strong as a raw percentage value which has been supported by browsers since the dawn of CSS.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeFirefoxIEEdgeSafari
19*4*11126*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1221231226.0-6.1*

The percentage method has slightly better browser support and can be a bit more stable in IE. If you don’t need to support Opera Mini, I would still recommend going with the calc() method first. Test in IE, and if the layout breaks, first try using 99.999% instead of 100% in the calc function (calc(99.999% / 3)). If that doesn’t work, then try switching to the percentage method. I will be using the calc() method in all of my examples. Note that if you are using a CSS pre-processor like SCSS, you can have the best of both worlds by getting the pre-processor to do the math for you. This comes at the cost of not being as easily able to edit or review the column counts in browser dev tools.

/* Set column count using SCSS */
.grid-cell {
  width: (100% / 3);
}

/* CSS output into the browser */
.grid-cell {
  width: 33.3333333333%;
}

Let’s give the grid cells some height and an inner box-shadow so that we can see what’s going on. I’m not adding border — I’ll be using that later. 😉

.grid-cell {
  /* So that we can see the grid cells */
  box-shadow: inset 0 0 0 1px #000;
  height: 100px;
}

.grid-wrapper {
  /* Allows us to see the edges of the grid */
  box-shadow: 0 0 10px 2px green;
}

You should now have something that looks like this:

A basic 3 x 2 grid with no gaps

That’s boring though, right? Everyone knows how to do that. Where are these grid gaps I keep talking about? I want my gaps!!!

Step 5: Border

Here’s where we get to the interesting part. Since we set box-sizing to border-box, the 33.33% width now includes the border. What this means is that we can start safely mixing fixed and percentage based units! 😃

.grid {
  /* Creates an equal outer gap */
  padding: 20px 0 0 20px;
}

.grid-cell {
  /* Creates gaps */
  border: 0 solid transparent;
  border-width: 0 20px 20px 0;
}

This results in something that looks like a grid with equal spacing everywhere:

A 3 x 2 grid with equal space between each cell and the outer edges of the grid

To help give you a better idea of what is going on, take a look at the following image:

Color-coded diagram of the grid

The blue area on the top and left sides of the grid is the padding for the .grid element. The yellow outlines show the area that each .grid-cell element takes up. The red areas on the bottom and right sides of each cell are the border for each .grid-cell element.

That might be the look that you actually want. On the other hand, that isn’t what a grid with a grid-gap setting looks like. That is why we have another step.

Step 6: Margin and overflow

In order to get the grid pressing hard up against the edges of its container, we need a bit of help from negative margins and overflow: hidden:

.grid {
  /* Pulls grid cells hard against edges */
  margin: -20px;
}

.grid-wrapper {
  /* Prevents odd margin behavior */
  overflow: hidden;
}

We need to apply overflow: hidden to prevent this from happening:

Top and bottom negative margin is ignored if overflow is not hidden

Applying the negative margin and overflow: hidden will get us to this beautiful recreation of basic grid-gap functionality:

A 3 x 2 grid that looks identical to a CSS grid with a gap setting

The top and left padding on the grid is actually optional. You can opt to leave off the padding and change the margin value as shown below if you prefer:

.grid {
  /* Margin needs to be this if leaving off the top and left .grid padding */
  margin: 0 -20px -20px 0;
}

But, hold on! The job isn’t quite over yet. Take a look at what happens if we add a background color to one of the grid cells:

A pink background applied to the top left cell overflows into the grid gap

Not exactly what we want, so there is one more step.

Step 7: background-clip

In order to prevent the grid cell background from bleeding into our fake grid-gap, we need to add background-clip: padding-box to it.

.grid-cell {
  /* Prevents background bleed */
  background-clip: padding-box;
}

Now we have this:

The background bleed has been fixed!

If you have never heard of the background-clip property before, you might be worried about browser support… well don’t be. background-clip has been around since IE9!

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeFirefoxIEEdgeSafari
1549127

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1221234.47.0-7.1

Step 8: Media Queries!

Most of the time, grids need to be able to change the number of columns that they have as they grow and shrink. Using other methods can be a massive pain. You might have to calculate a bunch of nth-childs so you can remove the right margin or whatever. With this method, you only have to change a single value! 😃

.grid-cell {
  /* Sets the default column count */
  width: calc(100% / 1); /* 1 column */
}

@media (min-width: 400px){
  .grid-cell {
    width: calc(100% / 2); /* 2 columns */
  }
}

@media (min-width: 600px){
  .grid-cell {
    width: calc(100% / 3); /* 3 columns */
  }
}
3 x 2 grid with gaps
2 x 3 grid with gaps
1 x 6 grid with gaps

Here’s how it looks when we put it all together:

See the Pen Fake grid by Daniel Tonon (@daniel-tonon) on CodePen.

Ain’t nobody got time for dat!

That’s a lot of work compared to what modern Grid can do in just three lines of CSS! To make the task easier, I created an SCSS-powered mixin I call Gutter Grid. Once Gutter Grid is installed in the project, you can quickly create a three-column grid with 20px gaps using the following SCSS code:

.grid-wrapper {
  overflow: hidden; /* Need this for the chrome bug */
}

.grid {
  @include grid($cols: 3, $gutter: 20px);
}

You can write it even shorter like this if that feels too verbose:

.grid-wrapper {
  overflow: hidden;
}

.grid {
  @include grid(3, 20px);
}

Gutter Grid comes pre-built with a few sets of breakpoints so you may not have to write any breakpoints at all if your grid spans the whole page! If you do need custom breakpoints, though, then Gutter Grid lets you easily customize them like so:

// Verbose custom breakpoints
@include grid($cols: 7, $gutter: 20px, $breakpoints: (
  4 : 960px, // At 960px or below, there will be 4 columns
  2 : (max, 600px), // You can use mq-scss syntax here as well
  1 : 480px,
));

// Short version  
@include grid(7, 20px, (
  4 : 960px,
  2 : 600px,
  1 : 480px,
));

As you might have noticed in the example, Gutter Grid also supports the same media query syntax that this thing called mq-scss uses. If you are wondering what that is, well, it’s a Sass mixin that I created that makes writing and managing media queries about a million times easier. Using mq-scss statements to dictate column count allows for very fine control over when the column count changes.

Adding shadows to the grid cells

Since we are working with shadows now, I’ll take the box shadow off of the example image. Our starting grid looks like this now:

A basic 3 x 2 grid with gaps and a green border around the outside

If we try to add an outer box-shadow to each grid cell right now… well it doesn’t look so good:

Adding shadows to the grid cells causes the shadows to be out of alignment

Let’s fix that.

Step 1: New HTML

In order to create nice shadows, we need to add an extra div inside each grid cell. You can’t really use ::before or ::after for this since they are unable to contain HTML content inside of them.



<div class="grid-wrapper">



<div class="grid">




<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>




</div>



</div>

Step 2: Flex it

Now, we need to make each grid cell a flex container. This will allow the inner part of the grid cell to take up the full height of its parent. We will also need to set the inner element to a width of 100%. This ensures that it will take up the full dimensions of its parent, both horizontally and vertically:

.grid-cell {
  /* Forces inner to take up full grid cell height */
  display: flex;
}

.grid-cell-inner {
  /* Forces inner to take up full grid cell width */
  width: 100%;
}

Let’s see what we get if we try adding box shadows to the inner elements:

.grid-cell-inner {
  box-shadow: 0 0 10px 3px blue;
}
Box shadows appear around grid cells but are getting cut off

That’s much nicer, but it is still not quite there yet. The hidden overflow that we are using to prevent the Chrome bug is getting in the way.

Step 3: Hacky padding

So, we need to allow overflow but still avoid this odd margin behavior. The only other safe way I’ve found to do that is with padding. By adding 1px of padding to the top and bottom of the outer grid wrapper element, it will fix the Chrome bug.

.grid-wrapper {
  /* Prevents odd margin behaviour in Chrome */
  padding: 1px 0;
}

This comes at the expense of having an extra 1px of space at the top and bottom of the grid. The image below demonstrates how this ends up looking. The shadows have been lightened to show the 1px gap more clearly.

1px of padding at the top and bottom of the grid

Note: You can avoid the 1px of top padding by opting not to include the top padding gap value on the grid element. The 1px of bottom padding can’t be avoided though.

A border width applied to the outer grid wrapper will also work, so technically I didn’t need to apply the padding to the example above. Most of the time, if we are applying a shadow to grid cells, then we probably don’t want to see a border wrapped around them. The above example was more demonstrating how minor the padding is.

Update: You can avoid the odd margin behavior completely by using 0.1px worth of padding rather than 1px. This will get rounded down to 0px in the browser but still prevent the odd margin behavior from occurring. This means that the edges of the grid can sit hard up against the edges of it’s container whilst still allowing overflow content to be visible! Thanks to Lu Nelson for his suggestion in the comments! 😁

This is what the grid looks like without the outer border:

3 x 2 shadow cell grid
2 x 3 shadow cell grid
1 x 6 shadow cell grid

Here is a Pen showing the final product:

See the Pen Fake grid with shadows by Daniel Tonon (@daniel-tonon) on CodePen.

Gutter Grid shadows

Let’s cover how to add shadows on Gutter Grid cells. You can use the same HTML structure we used in the previous example.

Now, apply this SCSS to create a three-column grid that has a 20px gutter:

.grid {
  @include grid(3, 20px, $inners: true);
}

This new $inners: true property tells Gutter Grid that the grid cells each have a single child element that needs to take up the full height and width of its parent grid cell.

Instead of using overflow: hidden, use 0.1px of bottom padding on the wrapper element (updated based on Lu Nelson’s suggestion).

.grid-wrapper {
  padding-bottom: 0.1px;
}

Gutter Grid will not output a top outer gutter if it doesn’t need to. This helps avoid issues around the negative margin quirk. After all, if there is no top outer gutter to negate with a faulty negative margin, then there is no bug to worry about. The bottom outer gutter is still a problem, though, and that is why we need the 0.1px of bottom padding. This 0.1px of bottom padding gets rounded down to 0px in the browser while still fixing the margin quirk leading to no gap at the bottom of the grid.

Now, add your shadows and you’ve got yourself a Gutter Grid with shadow cells!

.grid-cell-inner {
  box-shadow: 0 0 10px 3px blue;
}
3 x 2 shadow cell grid

I’ve only scraped the surface of what Gutter Grid can do in this article. Make sure to read the full documentation to learn what else it’s capable of.

We come to the end of our IE grid adventure

I hope you have enjoyed this foray into the world of IE and CSS grid. Make sure to read through Part 1 and Part 2 if you haven’t already. Having read all three articles, you will now be fully equipped to make some truly stunning layouts that look just as good in IE as they do in modern browsers.

If you ever see anyone complaining about not being able to use CSS grid because of IE, you know what to do. Playfully slap them on the head for being so foolish and send them here to get the truth.

Now go forth, my friends, and build some grids! 😃🎉

Article Series:

  1. Debunking common IE Grid misconceptions
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps (This Post)
  4. Duplicate area names now supported!