Moving from a Bootstrap Layout to CSS Grid

For decades we have been hacking our layouts. No more!

Bob Visser
9 min readApr 24, 2018

Ever since the dawn of the web world, controlling the layout has been cumbersome and difficult. We started with approximately positioning the page elements as illustrated by the screenshot of an early Yahoo.

Using tables for layout provided us with a bit more structure. We moved on from working with tables to mimicking them and called the result grid systems.

We were building these systems by setting a fixed width for the page, and created rows <div class=”row”> and columns <div class=”col-6”> in HTML. The row and column sizes were managed with CSS. Then, the content elements were placed inside of these columns. This creative layout hack was the core of float based grid frameworks such as 960.gs.

When the web went mobile, we adapted that approach. In order to make the layouts flexible, we replaced the pixels with percentages. But that was not all—to make the layout fit all screens, from a small mobile screen to a large desktop, we had to restructure it at intervals. And that is where the problem started…

Part of the Bootstrap 3 grid system.

Code, code, code and more code…all for layout management

To create a column that takes up the full width on extra-small devices, half of the width on medium-small devices and 2/3 of the width on medium screens you would have to add something like class="col-xs-12 col-sm-6 col-md-8" to your HTML.

Repeat that for each possible column width and for each possible column width change — col-xs-1 col-xs-2 etc. | col-sm-1 col-sm-2 etc. | col-md-1 col-md-2 etc. | col-l-1 col-l-2 etc. —and you will feel a serious case of classitis coming up.

But that’s not all, each of these classes corresponds to a bit of CSS to manage the width. For example, the 2/3 width on medium screens for the very first column corresponds to:

@media (min-width: 992px) {
.col-md-8 {
width: 66.66666667%;
}
}

Classitis, a ton of CSS, complex calculations, continuous testing and a lot of work overall. But there was a solution in sight: pre-created and well-tested layout code, also known as responsive grid frameworks. A whole slew of these frameworks were created, the most famous one of them all was the almighty Bootstrap (where the above example comes from).

Mommy, why do all websites look the same?

Using Bootstrap came at a price. Customizing all that code to craft unique experiences was not easy. In addition it was error prone, so people started falling back on using Bootstrap templates. The most famous of them all?

Right, the result was the same (responsive) website, over and over and over again. The good news is that with CSS Grid this is a thing of the past…or at least it should be. Let’s see why.

Using CSS Grid, the code to manage layout is just a small fraction of what it used to be. What the HTML would look like when using CSS Grid? So sweet and simple that you might be surprised! All that is needed is the grid parent, plus each of the five grid children (the 5 columns from the example above).

The grid children now only have two classes. The .grid-element class is for applying common styles such as backgrounds and borders. The classes with a number can be used to define element specific styles, including telling them to go to a specific part of the grid. This allows us to manage all types of layout variations. All with just a few lines of CSS. At small screens the Bootstrap layout looks as follows:

CSS Grid offers various methods to place the elements, the most visual and intuitive one is Template Areas. In essence you simply create a semantic map of your layout.

Semantic Layout Map (create with CSS Grid Builder).

Or in code:

Let’s quickly dissect this little piece of code. It starts with setting the display property to grid for the grid parent (.grid-example). Then the areas are defined through the grid-template-areas property—I made sure that the code formatting resembled the visual map above.

If you find it hard to see through formatting, just have a glance at the edited version of the previous image below and compare that one to the visual map above. Totally clear now, right?

You will see that each grid cell either gets a name, or a dot. An area can be a single cell, or a connected cell like the Container-1 area. The dot means that the cell is not part of any grid area.

The columns are defined next, I am creating 2 columns (repeat(2) of equal width (1fr). Finally I am creating four rows (repeat (4, auto) with an ‘automatic’ height. This is enough to create my semantic grid structure, but I will still need to tell the grid children where to go. Kids…they are all the same!

It is really straightforward though, and the good thing about grid children is that they are guaranteed to listen. Just connect each of the class selectors to a grid area using the grid-area property.

.grid-element-1 {
grid-area: Container-1;
}

That little piece of code tells the element with class .grid-element-1 to go to the grid-area named Container-1. Super intuitive! The screenshot below shows the full code.

With in total about 25 lines of code, including the 6 lines with a single character, the same Bootstrap layout is created. And no, I am not going to prove this with a screenshot. Not yet at least…

First I want to show you that updating this layout for wider screens is even easier.

With all element (selectors) already connected to the template areas, restructuring the layout at intervals is super easy. It is just a matter of rewriting the grid-template-areas rule at a media query (aka breakpoint). Yep, only that one, no need to touch the grid-area mapping as we will see below.

The Bootstrap layout we saw at the beginning of this article—2/3 for the first column, 1/3 for all others—is created when the screen width is 992px or wider. The code for creating the updated grid structure is straightforward.

For screens wider than 993px (yes, 1px more than 992, I explain this below) a new grid-template-area structure is defined. From that point onwards there are three columns, and two rows.

Which corresponds to the following visual structure:

Explaining the 1px difference:

I am using a min-width of 993 px because I am experimenting with the Materialize Framework which uses a breakpoint at that width. Please note that I am NOT using Materialize for creating the Layout. I chose this framework because I love their components and scripts. For layout production I am always using CSS Grid.

And you should too —as stipulated during my presentation Designing for Dynamic Content using CSS Grid at Wordcamp 2018*:

Feel free to use any frontend framework, just don’t use their grid system. If you use CSS Grid for that part, the design can be more flexible, is easier to maintain and switching to another framework in the future will be way less work.

*(yep, it is actually me on stage there)

The proof

There is one more layout change that happens at a smaller breakpoint. Again, just updating the grid structure makes that happen. If you’re interested in that part of the code or want to see the full code example, I suggest hopping over to the Codepen. And here’s the proof:

Replication of the Bootstrap Layout in CSS Grid (create with CSS Grid Builder).

So, that creates the exact same layout. But, now you know that you can do it, does that mean you should? I would be really really careful there—doing the same thing in a different way easily leads to the same results. Looking too much to the past will obscure the creative possibilities of the new methods.

Maybe your content looks better and message would be clearer in a layout like this:

Or a layout like this:

The point is, with CSS Grid it is fast and easy to prototype layout variations. Just reorder the template areas and the elements will follow suit. Don’t let the limitations and rigidness of the past hold you down!

Convert to CSS Grid—section by section

When converting an existing project to CSS Grid, it does not have to be an all or nothing approach. You can start with sections—groups that contain related content or functionality—that most benefit from a rejuvenated layout first. The approach I take can be broken down in roughly 5 steps.

1. Start with removing all the layout related classes in your HTML. New classes can be assigned if needed—I suggest making them as semantic as possible. In short a semantic class conveys what the element represents, what its role is.

At this point the content should mainly stack.

2. Regroup and prioritize the elements. Often the actual content can be taken out of their column wrappers and the row wrapper can serve as the grid parent (providing the layout context). Sometimes you will want to combine the content from several rows into one. The row class can often be renamed to something more semantic like .hero-section.

The content will still mainly stack. Now also make sure that the order (priority) in which the content is presented makes sense. This helps with accessibility (screen readers) and creating fallbacks.

3.Time to reimage the layout! Start with the smallest screen, and draw a semantic map of how you want to visualize your story. The layout possibilities will be limited but it helps to start thinking ‘small’. When there is more room to work with, redraw your layout map for wider screens. Assuming you used the template area approach (CSS Grid offers also other methods) all elements should automatically reposition.

While doing so don’t forget that other layout techniques—flex, position, margin—are still totally valid and can be easily combined with the CSS Grid!

4. Refine (if needed) by going back to step 2. Regroup the content and add class selectors if needed. Redraw the map until you are happy with how your section looks, feels and how your content comes across.

What about the Flex Grids?

Yea, about that... They were introduced in Bootstrap 4 (and Foundation 6) just as browser support for CSS Grid was skyrocketing. They offer a bit more layout functionality, although not as much as CSS Grid. The approach is very similar, content is wrapped in row and column <div>s which are managed through classes such as .col-sm-6 and .col-md-4.

They will try to seduce you with stories about better cross browser compatibility. Don’t fall for them! CSS Grid in combination with Feature Queries allows for creating solid fallback scenarios for older browser with a minimal amount of extra work. In the meantime your work will be future proof and ready for continued improvements as we discover more of the possibilities our new technique offers.

Let’s not lament the layout past—the future looks bright and griddy. So rip out that old layout code, and start updating, section by section by section.

--

--

Bob Visser

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