Layout Design with CSS Grid & Feature Queries

A real world workflow that works.

Bob Visser
12 min readMay 1, 2018

A good workflow for creating cool, modern, CSS Grid layouts? Sounds easy! Without the HTML needed to create all these rows and columns, you can go right ahead and place your content in the document. In the right order (preferably).

Then, use this versatile new layout system to place your elements exactly where you want them to appear. Repeat for a few different viewports widths. Job done…except for that one big little caveat:

What do you do for browsers that do not support display: grid;?

That’s a problem. Or not — one of the strategies I hear is to simply neglect them. Although that can certainly work for those who can afford to ignore roughly 30% of the Internet population, I think there is a much better way.

Enter, Feature Queries

Feature queries, aka Support Queries, provide a way to test if a browser is able to understand a specific CSS feature. Through the @supports rule the browser is asked (queried) whether or not a CSS property is supported. Then, depending on the answer, the browser can be instructed to apply a series of style definitions.

Using the right workflow, a Feature Query can be used to create fallback layouts for browsers that do not support CSS Grid. All of this, with a minimal amount of extra effort, which I am going to prove with a real design case.

An article post using grid with fallback layout.

A few days ago I needed to create a bullet-proof (article) layout for the user guide of CSS Grid Builder. There were several requirements such as the ability to include wide and small images, work with various amounts of text, look great at any screen width (duh!) and a few others. The screenshot below captures the result for modern browsers. The fallback layout can be seen a bit further down in this article. Now, let’s start with the workflow part!

The fallback (automatically) comes first.

It all starts with identifying the different content types and adding them to the canvas. In this case I had to make the layout work with:

  • An article Title (header),
  • An article Subtitle,
  • Regular paragraphs,
  • Wide images,
  • A divider,
  • Tall images, and
  • An unordered list.

This is also largely the order in which these elements are added to the canvas — in the HTML the titles always come first and the unordered list last. But, since there can be multiple instances of the main content, it makes sense to alternate the various paragraphs and the images. The screenshot below shows this basic setup.

Prototype of the content driven layout.

In essence, this is a ‘Content-first’ design approach—it starts with identifying the content types, roles and priorities needed to tell the story. When I introduced this concept to our customers a few years back I described Content-first as:

This is very similar to designing mobile-first. A key argument for designing mobile-first is that the small space forces proper content prioritization. Content-first proposes the same, but independent of screen size.

Now, with that setup in place, what do we need to do to make this look decent on small screens and in IE11? Not a lot actually!

(Clearly there are the basic design styles we need to apply—a background color for the article title, some font and link styling. I would like to keep the focus on CSS Grid, Feature Queries and Fallbacks though. For those interested in these (code) details I added a link to a codepen at the bottom of the article.)

Start with simple layout styles for small screens.

The actual HTML is represented in the code block below. The entire article consists of a container <div class=”section-article"> with another 8 containers inside. One container for each of the content types identified. Plus one extra, since the paragraph content is divided over two places—before and after the wide image. This builds 8 different sections in which the actual content can be dropped.

<article class="section-article">
<div class="article-header">
</div>
<div class="article-sub-title">
</div>
<div class="article-text-block wide-block">
</div>
<div class="figure wide-figure">
</div>
<div class="divider-block">
</div>
<div class="article-text-block small-block">
</div>
<div class="figure">
</div>
<div class="resources-block">
</div>
</article>

At the end of the article, when our layout is ready, I will explain how this approach makes our layout ‘content-agnostic’. The layout will look great independent of the amount of text, image height etc…

Moving on to the layout styles, starting with small screens. Generally speaking, there is not a lot of room on phones to be creative. And frankly, that’s also not something we would like to get into right now. The goal is to create something simple that looks good on small screens first.

Quickly looking back at the prototype layout you will see that a bit of padding was added to the article container to prevent the content from bumping into the edges of the screen. For the same reason some spacing might be needed below the images. These are the styles I used:

.section-article {
padding: 20px 10px 40px;
}
.figure {
margin-bottom: 1rem;
}
.article-sub-title {
padding-top: 10px;
padding-left: 10px;

Just adding space where needed using some margins and padding. This creates a sense of structure for the reader, making the content easier to consume. Simple but solid for mobile, and something that would totally work for IE11 too. But…when I extend the viewport it is clear that some tweaking is needed for wider (e.g. IE11) screens.

The simple mobile layout does not work on wider screens.

Text that stretches too long makes it (really) hard to read. A whole number of articles have already been written about what a good line width is. For this article, let’s stick to my rule of thumb: never make a paragraph extend beyond 760px. Assuming a font-size of 16px that is, if the font is smaller, the width usually will need to be limited more.

With 20px left and right padding this means that we have to restrict the width of the article container to 800px. Even IE11 screens can be way wider than that, so the container will need to be placed in the middle of the screen. Finally I want to center those images on a colored background for a bit more balance. The CSS would look something like*:

/* Centering the article container */.section-article {
margin-right: auto;
margin-left: auto;
}
/* Coloring the image sections */.figure {
background-color: #4b4b4b;
}
/* Centering the images */.responsive-picture {
margin-right: auto;
margin-left: auto;
}

*I recommend to not get into the code too deep here, this article is more about the workflow than the coding details. Again, if you want to know the exact code, I suggest hopping over to the codepen (link at the end of this article).

Fallback, done. It’s been awhile since I added an IE11 screenshot to an article, but below you can see the resulting layout in a real IE11 screenshot!

The fallback layout in Internet Explorer 11.

The key in this part of the process is to keep the layout super simple. Focus on properly organizing the content, making it readable and accessible.

The population on the web with browsers that don’t understand CSS Grid is rapidly shrinking, while, at the same time, the percentage of people using browsers that have solid support for CSS Grid is growing. So don’t get trapped in creating a deluxe design for browsers that make it hairpulling-ly difficult. Instead spend that time on creating an enhanced experience for the growing number of visitors using a modern browser. Which brings us to the last step…

Getting creative with CSS Grid !!

(Just make sure to serve it wrapped in a Feature Query).

Right at the start I had to make a decision here—shall I start using display: grid at the smallest screen? Or do this as soon as there is a bit more room for layout changes?

I decided for the latter, I will start using CSS Grid for screens wider than 640px. Up to now all styles were written to the default breakpoint; no style adjustment were made for wider viewports. Therefore I will now be introducing a Media and a Feature Query at the same time. In the code block below you will see that they have a very similar syntax.

@media screen and (min-width: 640px) {
@supports (display: grid) {
.section-article {display: grid;
}
}
}

Let’s break this down. First, using the ‘at media’ rule I am asking the browser if the screen width is 640px or more through min-width:640px. Then, inside the Media Query, I am using a Feature Query. With the ‘at support’ rule I test if the browser supports display: grid.

In case both conditions are met— if the screen width is 640px or more and the browser understands CSS Grid— I am telling it to actually use CSS Grid for the article container through the .section-article {display: grid;} declaration.

What will happen when IE11 reads these styles? Absolutely nothing! Here is why: browsers have been designed to ignore style rules they don’t understand. So, even if the first screen width test is passed, IE would not know what to do with @support and consequently skip the entire code section wrapped in that rule. The browser will simply continue to render the styles exactly as before.

Now we know where we need to place our grid style rules, wrapped in an ‘at support’ rule, we can start experimenting with the new powers CSS Grid gives us. Admittingly a width of 640px is not a lot to work with for an article layout, but it still allows us to make some nice tweaks.

An updated layout at 640px for browser supporting CSS Grid.

For medium size screens (that support ‘grid’), two layout updates have been made. At the top, the subtitle container is placed on the right of the article title. The text inside has now been right-aligned. To prevent this from happening in the ‘stacked’ layout, this also need to be done inside of the Feature Query.

The other layout change happens at the bottom: the tall image and ‘additional resources’ block are placed next to each other.

Digging into all the powers CSS Grid offers is way beyond this article, for that I suggest to check out this guide. Here I am giving you a quick overview of an intuitive placement technique: template areas.

They are really cool because they allow you to draw a semantic map of your layout. After that it is simply a matter of telling each of the grid elements, which area to go to.

The following code sets up the template areas in the article container:

@media screen and (min-width: 640px) {
@supports (display: grid) {
.section-article {
display: grid;
grid-template-areas:
'article-header article-header aside'
'wide-block wide-block wide-block'
'wide-figure wide-figure wide-figure'
'divider divider divider'
'small-text-block small-text-block small-text-block'
'figure figure resources';
grid-template-columns: repeat(3 , 1fr);
grid-template-rows: repeat(7 , auto);
grid-row-gap: 10px;
grid-column-gap: 10px;
}
}
}

Where it says grid-template-areas you see 6 rows denoted by the ' ‘. Each word inside of a row is a template area name. The first row, for example, consists of two template areas, the article header (repeated twice so taking up 2 columns) and the aside (taking up the last single column). The entire second row corresponds to the ‘wide-figure’ template area. And so on. The whole template area structure is represented in the image below.

Semantic layout map for the article container (created with the free CSS Grid Builder app).

All columns have an equal width of 1fr—each of them takes up an equal part of the remaining available space. The fr is a new unit of measurement introduced by the CSS grid specification. You can learn more about the mighty fr unit in my Guide to CSS grid.

Now all that needs to happen is telling each of the different containers, which grid area they belong to. This is as simple as saying to, for example, the article header container ‘hey, you go to the article-header grid area’ through the grid-area: article-header; style declaration.

When we do that for all containers inside of the ‘supports’ rule, our new layout for the 640px breakpoint is complete.

@media screen and (min-width: 640px) {
@supports (display: grid) {
.article-header {
grid-area: article-header;
}
.small-block {
grid-area: small-text-block;
}
.resources-block {
grid-area: resources;
}
.wide-block {
grid-area: wide-block;
}
.article-sub-title {
grid-area: aside;
}
.figure {
grid-area: figure;
}
.wide-figure {
grid-area: wide-figure;
}
.divider-block {
grid-area: divider;
}

Adding the above code will create the enhanced layout at the 640px breakpoint.

One of the big advantages of using template areas is that making subsequent layout changes for different screen sizes becomes a real piece of cake. With the (above) mapping of the grid elements to areas already done, it is simply a matter of redefining the grid configuration to introduce a new layout at another breakpoint.

@media screen and (min-width: 1024px) {
@supports (display: grid) {
.section-article {
max-width: 1000px;
grid-template-areas:
'aside article-header article-header'
'. wide-block wide-block'
'wide-figure wide-figure wide-figure'
'. divider divider'
'. small-text-block figure'
'. . resources';
grid-template-columns: 200px repeat(2 , 1fr);
grid-template-rows: repeat(6 , auto);
}
}

This code sets up a different template area structure for screens of 1024px and wider. At the top, the maximum width of the article is set to 1000px—from 800px for browsers that do not support ‘grid’. With the first column now set to a fixed pixel width of 200px (from 1fr), this leaves 800px to be equally divided between the other 2 columns. The image below shows a visual representation of the new structure.

The grid template area structure for screens wider than 1024px.

The grey areas correspond to the . (dots) in the code block—these are unnamed areas. All together this creates a very versatile and edgy layout, exactly as we saw at the start of this article. I am sure you can judge the amount of ‘edginess’ yourself…but let me briefly explain why this layout is so versatile.

A content-agnostic layout.

For starters, the amount of text content in these articles varies greatly. As does the height of the tall images. Sometimes there is awide image, sometimes there’s none. Basically this layout will always look good, no matter the variety.

Wrong!

If there is a lot of text, more paragraphs are added to the wide-block, preventing situations where the small text section sticks out far below the image. Or the other way around, additional text can be added to the small block preventing situations where a tall image ‘hangs’ in a big empty space as in this example.

If there is no ‘wide text’ or ‘wide image’, the layout still shows some variation to keep the reader's attention. And in case there is no tall image, the ‘additional resources’ could even be inserted into that container.

A css grid with fallback workflow recap.

As we have seen, creating the layout that works for browsers without CSS Grid support was only marginally more work than setting up the content structure and making that look decent on the smallest screens. And if you wanted to enhance the layout on small screens, that would be a possibility too. Instead of using a minimum-width, simply add a Feature Query to the default styles. To summarize our workflow consisted of:

  1. Identifying and prioritizing the content types or blocks;
  2. Making the layout look good on small screens;
  3. Extending the basic layout for wider screens (we added a max-width and centered the article on the page for IE11);
  4. Getting creative with CSS Grid wrapped in a Feature Query.

Following the workflow described above you will be able to use all the (creative) powers of CSS Grid, while at the same time making your content accessible for everyone that is not using a supporting browser yet. And it is barely any extra work!

--

--

Bob Visser

I help companies make briljant digital products and solid device-agnostic user experiences.