CSS Grid in IE: Duplicate area names now supported!

Autoprefixer is now up to version 9.3.1 and there have been a lot of updates since I wrote the original three-part CSS Grid in IE series — the most important update of which is the new grid-areas system. This is mostly thanks to Bogdan Dolin, who has been working like crazy to fix loads of Autoprefixer issues. Autoprefixer’s grid translations were powerful before, but they have gotten far more powerful now!

Article Series:

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

How Autoprefixer supports duplicate area names

In Part 2 of the series, I pointed out why Autoprefixer wasn’t able to handle duplicate area names that were used across multiple selectors.

To summarize, this is the example I gave in the article:

.grid-alpha { grid-template-areas: "delta echo";
} .grid-beta { grid-template-areas: "echo delta";
} .grid-cell { /* What column does .grid-cell go in? */ -ms-grid-column: ???; grid-area: echo;
}

We thought that since Autoprefixer didn’t have access to the DOM, there was no way of knowing what grid the grid cell belonged to and thus which column the grid cell should go in.

However, I realized something. Grid cells are only ever affected by their direct parent element (ignoring display: contents). That meant that if the grid cell exists, it will always be a direct child of the grid template element. This gave me an idea for how we can solve the grid-area name conflict! 😁

.grid-alpha { grid-template-areas: "delta echo";
} .grid-beta { /* Uh oh, duplicate area names! */ grid-template-areas: "echo delta";
} .grid-cell { /* We will use the first occurrence by default */ -ms-grid-column: 2; grid-area: echo;
} /* We have detected a conflict! Prefix the class with the parent selector.
*/
.grid-beta > .grid-cell { /* NO MORE CONFLICT! */ -ms-grid-column: 1;
}

The entire grid-areas system needed to be re-written to achieve this, but it was totally worth the effort.

The way this new system works is that .grid-cell will default to using the first grid-template-areas property that it comes across. When it hits a conflicting grid template, it will create a new rule placing the parent selector in front of the child selector like so:

[full parent selector] > [direct child selector]

This is what we know purely from looking at the CSS and knowing how CSS Grid works:

  • A grid cell must be a direct descendant of the parent grid container for CSS Grid to work (assuming display: contents isn’t used).
  • grid-beta > .grid-cell will only work on .grid-cell elements that have been placed directly inside a .grid-beta element.
  • .grid-beta > .grid-cell will have no effect on .grid-cell elements placed directly inside .grid-alpha elements.
  • .grid-beta > .grid-cell will have no effect on .grid-cell elements nested deeply inside .grid-beta elements.
  • .grid-beta > .grid-cell will override the styling of the lonely .grid-cell CSS rule both because of rule order and specificity.

Because of those reasons, Autoprefixer can pretty safely resolve these conflicts without having any access to the DOM.

That last point in the list can be a little bit dangerous. It increases specificity which means that it may cause some IE styles to override others in a way that is different from how modern overrides are working. Since the generated rules only hold IE-specific grid styles, and they only apply under very specific circumstances, this is unlikely to cause an issue in 99.999% of circumstances. There is still potential for edge cases though.

If you ever find yourself needing to increase the specificity of the grid cell selector, here’s how to go about it.

Instead of writing this:

.grid { grid-template-areas: "area-name";
} .grid-cell { grid-area: area-name;
}

…we write the rule like this:

.grid { grid-template-areas: "area-name";
} .grid > .grid-cell { grid-area: area-name;
}

Autoprefixer will retain the selector and output something like this:

.grid { grid-template-areas: "area-name";
} .grid > .grid-cell { -ms-grid-column: 1; -ms-grid-row: 1; grid-area: area-name;
}

The exciting new possibilities!

So why is duplicate area name support so exciting?

Well, for one, it was just plain annoying when accidentally using a duplicate area name in older versions of Autoprefixer. It would break in IE and, in older versions of Autoprefixer, it would fail silently.

The main reason it is exciting though is that it opens up a whole new world of IE-friendly CSS Grid possibilities!

Use modifier classes to adjust a grid template

This was the use case that really made me want to get duplicate area name support into Autoprefixer. Think about this. You have a typical site with a header, a footer, a main area, and a sidebar down either side.

See the Pen Basic website layout by Daniel Tonon (@daniel-tonon) on CodePen.

Sometimes we want both sidebars, sometimes we want one sidebar, and sometimes we want no sidebars. This was very difficult to manage back when Autoprefixer didn’t support duplicate area names since we couldn’t share area names across multiple grid templates. We would have to do something like this for it to work:

/* Before Duplicate area names were supported - n = no side-bars - f = first sidebar only - s = second sidebar only - fs = first and second sidebars
*/
.main-area { display: grid; grid-template: "content-n" / 1fr;
} .main-area.has-first-sidebar { grid-template: "first-sb-f content-f" / 300px 1fr;
} .main-area.has-second-sidebar { grid-template: "content-s second-sb-s" / 1fr 300px;
}
.main-area.has-first-sidebar.has-second-sidebar { grid-template: "first-sb-fs content-fs second-sb-fs" / 200px 1fr 200px;
} .main-area > .content { grid-area: content-n; /* no side-bars */
} .main-area > .sidebar.first { grid-area: first-sb-f; /* first sidebar only */
} .main-area > .sidebar.second { grid-area: second-sb-s; /* second sidebar only */
} .main-area.has-first-sidebar > .content { grid-area: content-f; /* first sidebar only */
} .main-area.has-second-sidebar > .content { grid-area: content-s; /* second sidebar only */
} .main-area.has-first-sidebar.has-second-sidebar > .content { grid-area: content-fs; /* first and second sidebars */
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.first { grid-area: first-sb-fs; /* first and second sidebars */
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.second { grid-area: second-sb-fs; /* first and second sidebars */
}
Autoprefixer translation
/* Before Duplicate area names were supported - n = no sidebars - f = first sidebar only - s = second sidebar only - fs = first and second sidebars
*/ .main-area { display: -ms-grid; display: grid; -ms-grid-rows: auto; -ms-grid-columns: 1fr; grid-template: "content-n" / 1fr;
} .main-area.has-first-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 300px 1fr; grid-template: "first-sb-f content-f" / 300px 1fr;
} .main-area.has-second-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 1fr 300px; grid-template: "content-s second-sb-s" / 1fr 300px;
} .main-area.has-first-sidebar.has-second-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 200px 1fr 200px; grid-template: "first-sb-fs content-fs second-sb-fs" / 200px 1fr 200px;
} .main-area > .content { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: content-n; /* no side-bars */
} .main-area > .sidebar.first { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: first-sb-f; /* first sidebar only */
} .main-area > .sidebar.second { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: second-sb-s; /* second sidebar only */
} .main-area.has-first-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: content-f; /* first sidebar only */
} .main-area.has-second-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: content-s; /* second sidebar only */
} .main-area.has-first-sidebar.has-second-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: content-fs; /* first and second sidebars */
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.first { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: first-sb-fs; /* first and second sidebars */
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.second { -ms-grid-row: 1; -ms-grid-column: 3; grid-area: second-sb-fs; /* first and second sidebars */
}

🤢 Oh yeah, and don’t forget media queries! 🤮

That example was based off actual code that I had to write for an actual project… so yeah, I really wanted to get duplicate area name support into Autoprefixer.

Now that we do have duplicate area name support, we can simplify that code down to something much nicer 😊

/* Duplicate area names now supported! This code will work perfectly in IE with Autoprefixer 9.3.1
*/ .main-area { display: grid; grid-template: "content" / 1fr;
} .main-area.has-first-sidebar { grid-template: "first-sb content" / 300px 1fr;
} .main-area.has-second-sidebar { grid-template: "content second-sb" / 1fr 300px;
} .main-area.has-first-sidebar.has-second-sidebar { grid-template: "first-sb content second-sb" / 200px 1fr 200px;
} .content { grid-area: content;
} .sidebar.first { grid-area: first-sb;
} .sidebar.second { grid-area: second-sb;
}
Autoprefixer translation
.main-area { display: -ms-grid; display: grid; -ms-grid-rows: auto; -ms-grid-columns: 1fr; grid-template: "content" / 1fr;
} .main-area.has-first-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 300px 1fr; grid-template: "first-sb content" / 300px 1fr;
} .main-area.has-second-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 1fr 300px; grid-template: "content second-sb" / 1fr 300px;
} .main-area.has-first-sidebar.has-second-sidebar { -ms-grid-rows: auto; -ms-grid-columns: 200px 1fr 200px; grid-template: "first-sb content second-sb" / 200px 1fr 200px;
} .content { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: content;
} .main-area.has-first-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 2;
} .main-area.has-second-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 1;
} .main-area.has-first-sidebar.has-second-sidebar > .content { -ms-grid-row: 1; -ms-grid-column: 2;
} .sidebar.first { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: first-sb;
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.first { -ms-grid-row: 1; -ms-grid-column: 1;
} .sidebar.second { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: second-sb;
} .main-area.has-first-sidebar.has-second-sidebar > .sidebar.second { -ms-grid-row: 1; -ms-grid-column: 3;
}

With that CSS, we are now able to use the has-first-sidebar and has-second-sidebar classes on the grid element to modify what grid template the browser uses. We no longer have to worry about defining exactly what grid grid cells are placed in.

Assign components reusable area names

One of the limitations of being forced to use unique area names was that components could not be given a single, consistent re-usable area name. We were forced to come up with unique area names for every grid.

Now that Autoprefixer has duplicate area name support, that limitation is gone. We can provide every component with a single area name that is based on their component name. We can then reference that one area name whenever we want to place that component inside a grid layout.

/* header.scss */
.header { grid-area: header;
} /* nav.scss */
.nav { grid-area: nav;
} /* sidebar.scss */
.sidebar { grid-area: sidebar;
} /* content.scss */
.content { grid-area: content;
} /* subscribe.scss */
.subscribe { grid-area: subscribe;
} /* footer.scss */
.footer { grid-area: footer;
} /* layout.scss */
.single-sidebar-layout { display: grid; grid-template-areas: "header header" "nav content" "subscribe content" "footer footer";
} .double-sidebar-layout { display: grid; grid-template-areas: "header header header" "nav content sidebar" "nav subscribe sidebar" "footer footer footer";
}
Autoprefixer translation
/* header.scss */
.header { -ms-grid-row: 1; -ms-grid-column: 1; -ms-grid-column-span: 2; grid-area: header;
} .double-sidebar-layout > .header { -ms-grid-row: 1; -ms-grid-column: 1; -ms-grid-column-span: 3;
} /* nav.scss */
.nav { -ms-grid-row: 2; -ms-grid-column: 1; grid-area: nav;
} .double-sidebar-layout > .nav { -ms-grid-row: 2; -ms-grid-row-span: 2; -ms-grid-column: 1;
} /* sidebar.scss */
.sidebar { -ms-grid-row: 2; -ms-grid-row-span: 2; -ms-grid-column: 3; grid-area: sidebar;
} /* content.scss */
.content { -ms-grid-row: 2; -ms-grid-row-span: 2; -ms-grid-column: 2; grid-area: content;
} .double-sidebar-layout > .content { -ms-grid-row: 2; -ms-grid-column: 2;
} /* subscribe.scss */
.subscribe { -ms-grid-row: 3; -ms-grid-column: 1; grid-area: subscribe;
} .double-sidebar-layout > .subscribe { -ms-grid-row: 3; -ms-grid-column: 2;
} /* footer.scss */
.footer { -ms-grid-row: 4; -ms-grid-column: 1; -ms-grid-column-span: 2; grid-area: footer;
} .double-sidebar-layout > .footer { -ms-grid-row: 4; -ms-grid-column: 1; -ms-grid-column-span: 3;
} /* layout.scss */
.single-sidebar-layout { display: -ms-grid; display: grid; grid-template-areas: "header header" "nav content" "subscribe content" "footer footer";
} .double-sidebar-layout { display: -ms-grid; display: grid; grid-template-areas: "header header header" "nav content sidebar" "nav subscribe sidebar" "footer footer footer";
}

Here’s what we’ve got. Note that this should be viewed in IE.

See the Pen component-area-name technique by Daniel Tonon (@daniel-tonon) on CodePen.

Duplicate area name limitation

There is one fairly common use case that Autoprefixer still can’t handle at the moment. When the parent selector of the grid cell does not match up with the grid template selector, it tries to resolve a duplicate area name:

.grand-parent .mother { grid-template-areas: "child";
} .grand-parent .father { grid-template-areas: "child child";
} /* This will work */
.grand-parent .mother .child { grid-area: child;
} /* This does not work because: - ".uncle" != ".grand-parent .mother" - ".uncle" != ".grand-parent .father" - "child" is a duplicate area name
*/
.uncle .child { grid-area: child;
}

Here is a more realistic scenario of the current limitation in Autoprefixer’s algorithm:

.component .grid { display: grid; grid-template-areas: "one two"; grid-template-columns: 1fr 1fr;
} /* This rule triggers duplicate area name conflicts. */
.component.modifier .grid { grid-template-areas: "one ... two"; grid-template-columns: 1fr 1fr 1fr;
} /* This does not work because: - ".component" != ".component .grid" - ".component" != ".component.modifier .grid" - area names "one" and "two" both have duplicate area name conflicts
*/
.component .cell-one { grid-area: one;
} .component .cell-two { grid-area: two;
}

There are really only three ways of resolving this conflict at the moment.

Option 1: Remove the parent selector from child elements

Without any safeguards in place for scoping styles to a particular component, this is by far the most dangerous way to resolve the issue. I don’t recommend it.

.component .grid { display: grid; grid-template-areas: "one two"; grid-template-columns: 1fr 1fr;
} .component.modifier .grid { grid-template-areas: "one ... two"; grid-template-columns: 1fr 1fr 1fr;
} .cell-one { grid-area: one;
} .cell-two { grid-area: two;
}
Autoprefixer translation
.component .grid { display: -ms-grid; display: grid; grid-template-areas: "one two"; -ms-grid-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} .component.modifier .grid { grid-template-areas: "one ... two"; -ms-grid-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} .cell-one { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: one;
} .component.modifier .grid > .cell-one { -ms-grid-row: 1; -ms-grid-column: 1;
} .cell-two { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: two;
} .component.modifier .grid > .cell-two { -ms-grid-row: 1; -ms-grid-column: 3;
}

Option 2: Go back to using unique area names

This solution is pretty ugly, but if you have no control over the HTML, then this is probably the best way of handling the issue.

.component .grid { display: grid; grid-template-areas: "one two"; grid-template-columns: 1fr 1fr;
} .component .cell-one { grid-area: one;
} .component .cell-two { grid-area: two;
} .component.modifier .grid { grid-template-areas: "modifier_one ... modifier_two"; grid-template-columns: 1fr 1fr 1fr;
} .component.modifier .cell-one { grid-area: modifier_one;
} .component.modifier .cell-two { grid-area: modifier_two;
}
Autoprefixer translation
.component .grid { display: -ms-grid; display: grid; grid-template-areas: "one two"; -ms-grid-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} .component .cell-one { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: one;
} .component .cell-two { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: two;
} .component.modifier .grid { grid-template-areas: "modifier_one ... modifier_two"; -ms-grid-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} .component.modifier .cell-one { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: modifier_one;
} .component.modifier .cell-two { -ms-grid-row: 1; -ms-grid-column: 3; grid-area: modifier_two;
}

Option 3: Use a BEM-style naming convention

Yep, if you use the BEM naming convention (or something similar), this will practically never be an issue for you. This is easily the preferred way of dealing with the issue if it’s an option.

.component__grid { display: grid; grid-template-areas: "one two"; grid-template-columns: 1fr 1fr;
} .component__grid--modifier { grid-template-areas: "one ... two"; grid-template-columns: 1fr 1fr 1fr;
} .component__cell-one { grid-area: one;
} .component__cell-two { grid-area: two;
}
Autoprefixer translation
.component__grid { display: -ms-grid; display: grid; grid-template-areas: "one two"; -ms-grid-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} .component__grid--modifier { grid-template-areas: "one ... two"; -ms-grid-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} .component__cell-one { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: one;
} .component__grid--modifier > .component__cell-one { -ms-grid-row: 1; -ms-grid-column: 1;
} .component__cell-two { -ms-grid-row: 1; -ms-grid-column: 2; grid-area: two;
} .component__grid--modifier > .component__cell-two { -ms-grid-row: 1; -ms-grid-column: 3;
}

I have some issues with BEM, but with a few tweaks to the syntax, it can be a really great way to control CSS specificity and scoping.

Other Autoprefixer updates

While I’m here, I’ll give you an update on a couple of other developments that have occurred in Autoprefixer since I wrote the original CSS Grid in IE series.

Before we dive in though, here is how to set things up in CodePen in case you want to follow along with your own experiments.

Using Autoprefixer Grid translations in CodePen

CodePen has already upgraded to version 9.3.1 of Autoprefixer. You will now easily be able to integrate IE-friendly CSS Grid styles into your pens. First, make sure that Autoprefixer is enabled in the CodePen settings (Settings > CSS > [Vendor Prefixing] > Autoprefixer).

Step 1: Turn on Autoprefixer in CodePen

Then add the all new /* autoprefixer grid: on */ control comment to the top of the CSS Panel. I will dive into this awesome new feature a bit more later.

Step 2: Add the control comment

You can now write modern IE-friendly CSS Grid code and CodePen will automatically add in all of the IE prefixes for you.

“View compiled CSS” button
The compiled CSS view

In order to actually test your pens in IE though, you will need to view the pen in “Debug Mode” (Change View > Debug Mode). The pen will need to be saved before you will have access to this view.

Enabling Debug Mode for testing in IE

If you’d like to try out a tool that shows you real-time Autoprefixer output, try the online tool just for that. Input CSS on the left. It will output Autoprefixer’s translated CSS on the right as you type.

autoprefixer.github.io

New Autoprefixer control comments

We don’t always have the ability to alter the Autoprefixer configuration settings. If you have ever tried to do some IE-friendly CSS Grid experiments in CodePen in the past, you will know the pain of not having direct access to the Autoprefixer settings. There are also some frameworks like Create React App and Angular that don’t allow users to alter the Autoprefixer settings. There was also a bit of a skill barrier that prevented some users from using Grid because they were unsure of how to enable Grid translations.

This limitation was causing pain for many users but then Andrey Alexandrov submitted a pull request that introduced a new control comment. This new control comment gave users the ability to easily turn grid translations on and off from inside the CSS file. This was far easier than doing it through configuration settings. It was also accessible to all users no matter how they compile their CSS.

Adding /* autoprefixer grid: on */ will enable grid translations for that entire block while /* autoprefixer grid: off */ will disable grid translations for that block. Only the first grid control comment in a block will be applied.

/* Globally enable grid prefixes */
/* autoprefixer grid: on */ .grid { display: grid;
} .non-ie .grid { /* Turn off grid prefixes but only for this block */ /* autoprefixer grid: off */ display: grid; /* Grid control comments affect the whole block. This control comment is ignored */ /* autoprefixer grid: on */ grid-column: 1;
}

The above code translates into the following (I’ve filtered out the explanation comments):

/* autoprefixer grid: on */ .grid { display: -ms-grid; display: grid;
} .non-ie .grid { /* autoprefixer grid: off */ display: grid; /* autoprefixer grid: on */ grid-column: 1;
}

@supports can disable grid translations

The new control comments aren’t the only way to selectively prevent Autoprefixer from outputting grid translation code.

Autoprefixer will never be able to support implicit grid auto-placement. If you use an @supports statement that checks for something like grid-auto-rows: 0, Autoprefixer will not output Grid translations for code entered inside that statement.

.prefixed .grid { display: -ms-grid; display: grid;
} /* Checking grid-auto-* support prevents prefixes */
@supports (grid-auto-rows: 0) { .modern .grid { display: grid; }
} /* Checking basic grid support still outputs prefixes */
@supports (display: grid) { .still-prefixed .grid { display: -ms-grid; display: grid; }
}

To support IE, Autoprefixer can generate something like 50 lines of extra CSS sometimes. If you are writing Grid code inside an @supports statement, you will want IE translations to be turned off to reduce the weight of your CSS. If you don’t want to use @supports (grid-auto-rows: 0) then you can use a control comment inside the @supports statement instead.

@supports (display: grid) { .prefixed .grid { display: -ms-grid; display: grid; }
} @supports (display: grid) { /* autoprefixer grid: off */ .modern .grid { display: grid; }
}

Autoprefixer now inherits grid-gaps

In the original article series, I said that Autoprefixer was unable to inherit grid-gap values. In version 9.1.1, grid-gap values were able to inherit through media queries. In version 9.3.1, they have become inheritable through more specific selectors as well.

.grid { display: grid; grid-gap: 20px; /* grid-gap is stated here */ grid-template: "one two" / 1fr 1fr;
} @media (max-width: 600px) { .grid { /* grid-gap is now inhereited here */ grid-template: "one" "two" / 1fr; }
} .grid.modifier { /* grid-gap is now inhereited here as well */ grid-template: "one" "two" / 1fr;
} .one { grid-area: one; }
.two { grid-area: two; }
Autoprefixer translation
.grid { display: -ms-grid; display: grid; grid-gap: 20px; /* grid-gap is stated here */ -ms-grid-rows: auto; -ms-grid-columns: 1fr 20px 1fr; grid-template: "one two" / 1fr 1fr;
} @media (max-width: 600px) { .grid { /* grid-gap is now inhereited here */ -ms-grid-rows: auto 20px auto; -ms-grid-columns: 1fr; grid-template: "one" "two" / 1fr; }
} .grid.modifier { /* grid-gap is now inherited here as well */ -ms-grid-rows: auto 20px auto; -ms-grid-columns: 1fr; grid-template: "one" "two" / 1fr;
} .one { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: one;
} .grid.modifier > .one { -ms-grid-row: 1; -ms-grid-column: 1;
} .two { -ms-grid-row: 1; -ms-grid-column: 3; grid-area: two;
} .grid.modifier > .two { -ms-grid-row: 3; -ms-grid-column: 1;
} @media (max-width: 600px) { .one { -ms-grid-row: 1; -ms-grid-column: 1; } .two { -ms-grid-row: 3; -ms-grid-column: 1; }
}

grid-template: span X; now works

In Part 2 this series, I mentioned that the following syntax doesn’t work:

.grid-cell { grid-column: span 2;
}

This was fixed in version 9.1.1. It now translates into the following:

.grid-cell { -ms-grid-column-span: 2; grid-column: span 2;
}

New warning for mixing manual and area based placement

We had a user complain that Autoprefixer wasn’t handling grid areas correctly. Upon further investigation, we realized that they were applying both a grid-area and a grid-column setting within the same CSS rule.

.grid { display: grid; grid-template-areas: "a b";
} /* This doesn't work very well */
.grid-cell { grid-column: 2; grid-area: a;
}

Either use grid-area on its own, or us grid-column & grid-row. Never use both at the same time.

If you are curious, this is what Autoprefixer outputs for the above code:

.grid { display: -ms-grid; display: grid; grid-template-areas: "a b";
} /* This doesn't work very well */
.grid-cell { -ms-grid-row: 1; -ms-grid-column: 1; -ms-grid-column: 2; grid-column: 2; grid-area: a;
}

There is one exception to this. You may need a grid cell to overlap other grid cells in your design. You want to use grid-template-areas for placing your grid cells due to how much easier Autoprefixer makes the overall cell placement. You can’t really create cell overlaps using grid-template-areas though. To create this overlap, you can use grid-[column/row]-end: span X; after the grid-area declaration to force the overlap.

.grid { display: grid; grid-template-areas: "a . ." "a b b" "a . ."; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 1fr;
} .grid-cell-a { grid-area: a; /* place cell span after the grid-area to force an overlap */ grid-column-end: span 2;
}

See the Pen column-span + grid-area experiment by Daniel Tonon (@daniel-tonon) on CodePen.

However if you have declared grid gaps in your grid, you will need to write the column/row span prefix manually while taking the extra columns/rows generated by Autoprefixer into consideration (IE doesn’t support grid-gap). There is an issue for this on GitHub.

.grid { display: grid; grid-template-areas: "a . ." "a b c" "a . ."; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 1fr; grid-gap: 10px;
} .grid-cell-a { grid-area: a; /* IE column span added manually */ -ms-grid-column-span: 3; /* IE spans 2 columns + the gap */ grid-column-end: span 2; /* Modern browsers only span 2 columns */
}

See the Pen column-span + grid-area experiment 2 by Daniel Tonon (@daniel-tonon) on CodePen.

This technique currently produces a warning message in Autoprefixer that can’t easily be hidden. An issue for this is on GitHub.

New warning when using [align/justify/place]-[content/items]

Unfortunately. IE does not have the ability to align grid cells from the parent container. The only way to align grid cells in IE is by using the -ms-grid-row-align and the -ms-grid-column-align properties. These translate to align-self and justify-self in modern day grid syntax.

The following properties will trigger a warning in Autoprefixer if used in conjunction with a CSS Grid property:

  • align-items
  • align-content
  • justify-items
  • justify-content
  • place-items
  • place-content

The align-content, justify-content and place-content properties are pretty much impossible to replicate in IE. The align-items, justify-items and place-items properties, on the other hand, are quite easy to replicate using their self equivalents on the child elements (place-self support was added in 9.3.0).

/* [align/justify/place]-items is *NOT* IE friendly */ .align-justify-items { display: grid; align-items: start; justify-items: end;
} .place-items { display: grid; place-items: start end;
} /*[align/justify/place]-self *IS* IE friendly */ .align-justify-grid { display: grid; }
.align-justify-grid > * { align-self: start; justify-self: end;
} .place-grid { display: grid; }
.place-grid > * { place-self: start end;
}
Autoprefixer translation
/* [align/justify/place]-items is *NOT* IE friendly */ .align-justify-items { display: -ms-grid; display: grid; align-items: start; justify-items: end;
} .place-items { display: -ms-grid; display: grid; place-items: start end;
} /*[align/justify/place]-self *IS* IE friendly */ .align-justify-grid { display: -ms-grid; display: grid; }
.align-justify-grid > * { -ms-grid-row-align: start; align-self: start; -ms-grid-column-align: end; justify-self: end;
} .place-grid { display: -ms-grid; display: grid; }
.place-grid > * { -ms-grid-row-align: start; -ms-grid-column-align: end; place-self: start end;
}

.grid { [align/justify/place]-items } and .grid > * { [align/justify/place]-self } are generally quite interchangeable with one another. This substitution doesn’t always work, but in most cases, the two methods tend to act in much the same way.

Below is a pen demonstrating the difference between the IE friendly alignment method and the IE unfriendly alignment method. In modern browsers they look identical, but in IE one looks the same as the modern browsers and one does not.

See the Pen place-items experiment by Daniel Tonon (@daniel-tonon) on CodePen.

That’s all, folks

I hope you have enjoyed reading about the awesome new improvements the Autoprefixer community has made to the project over the past few months. The new control comments make enabling and disabling grid translations an absolute breeze. The new grid-areas system is also exciting. I love all the new IE-friendly CSS Grid options that the new areas system opens up, and I think you will too. 🙂

Article Series:

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

The post CSS Grid in IE: Duplicate area names now supported! appeared first on CSS-Tricks.