How to Replicate the Bootstrap 3 Grid Using CSS Grid

The past few years have seen a wide variety of methods for creating web page layouts. CSS Grid is one of the newest and probably the most game-changing layout technique at our disposal. If you haven’t begun tinkering with it yet, now’s the time. It is a wildly different way of thinking about positioning content, and it currently has nearly full support across all popular web browsers.

In order to replicate the majority of the features of the Bootstrap 3 grid system, we only require a small portion of the features that CSS Grid has to offer.

The key concept introduced in the Bootstrap 3 grid system, which we will be replicating, is the ability to explicitly define a grid container’s proportions for each responsive breakpoint. In comparison, Bootstrap 2 only set the proportions for desktop, and any viewport smaller than 767px would render all grid items at full width, stacked vertically, in a single column.

To begin, we can define our class names similar to those used in Bootstrap 3:

  • .row for a grid container
  • .col-[screenSize]-[numColumns] for a grid item where [screenSize] is one of our size abbreviations (xs,sm,md,lg,xl) and [numColumns] is a number from 1 to 12

To use CSS Grid, we simply apply display: grid to our row class:

.row{
 display: grid;
}

Next, we can define the number of columns in our grid and the size of the gutters (the space between items/columns). Bootstrap uses 12 columns with 15px gutters:

.row{
 display: grid;
 grid-template-columns: repeat(12, 1fr);
 grid-gap: 15px;
}

repeat(12, 1fr) is shorthand for “1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr, 1fr” where ‘fr’ is a fractional unit. Setting all 12 of our columns to 1fr means they will all be the same width. By changing these values, we could easily create a grid with a different number of columns, or with columns of varying widths.

We now have our grid container defined, and it is time to set the grid items that will go into it. To do so we need to only set the grid-column-end property for each variation of the grid item. Setting it to a value of span 1 would make the item one column wide. span 6 would make it 6 columns wide, half of our 12 column grid.

There is much more that we could achieve with this property. I encourage you to explore the possibilities and understand that we are only scratching the surface in this demo.

The most complicated task we have to do is fill out all of the different span sizes at all of the different breakpoints. The pattern is as follows:

@media (min-width: 0) {
 .col-xs-1 {
   grid-column-end: span 1;
 }
 .col-xs-2 {
   grid-column-end: span 2;
 }
 .col-xs-3 {
   grid-column-end: span 3;
 }
 ...up to .col-xs-12
}
@media (min-width: 768px) {
 .col-sm-1 {
   grid-column-end: span 1;
 }
 .col-sm-2 {
   grid-column-end: span 2;
 }
 .col-sm-3 {
   grid-column-end: span 3;
 }
 ...up to .col-sm-12
}
...repeat for 'md' at 992px and 'lg' at 1200px

Once we understand the pattern, it is simple enough to build it with a nested loop in Sass, like so:

// Loop through responsive breakpoints
@each $size, $abbr in (0,xs),(768px,sm),(992px,md),(1200px,lg){
 @media (min-width: $size){
   // Loop through col classes
   @for $i from 1 through 12{
     .col-#{$abbr}-#{$i}{
       grid-column-end: span $i;
     }
   }
 }
}

All that remains is to set a full width default for situations where the width is not defined. For example, a grid item with the classes “col-md-4, col-sm-6” does not have a width defined when the viewport is smaller than 768px (the sm breakpoint).

However, it is defined for viewports larger than 992px (the md breakpoint) because the media query will continue applying the width for all viewports wider than 992px unless it is overridden by defining the lg width.

Rather than requiring devs to assign xs width to every item, we can safely make it full width as a default that the user can override if they choose to.

[class^=col-]{
 grid-column-end: span 12;
}

This style rule will apply to any element with a class that begins with “col-” and set a 12 column width. The rule will be placed above our nested loop to ensure that the other grid styles override it.

See it all in action:

Advantages Over Bootstrap 3

This CSS Grid implementation has several advantages over Bootstrap 3’s grid:

1. All items in a row match the height of the tallest item.

  • In Bootstrap 3, varying item heights would cause wrapping items to be improperly positioned, and it was a big headache.

2. No need for element inside item to utilize gutter.

  • Bootstrap 3’s gutter was applied to content within the item container not to the container itself. If you wanted a border or background color on the items to have the gutter space between them, you’d have to include another element within the grid item.
  • In CSS Grid, you can apply borders and backgrounds directly to the item and it will leave the gutter empty.

3. No awkward rounded percentages.

  • Bootstrap 3 relied on meticulously rounded percentages with repeating decimals.
  • CSS Grid uses explicitly defined fractions and does the math for us.

4. No negative margin hacks.

  • Bootstrap 3 gutters were carefully crafted with padding on each item and negative margins applied to the row to negate the padding on the first item of each row.
  • CSS Grid provides proper gutters out of the box.

5. No clear-fix hacks.

  • Bootstrap 3 grid items were floated left for wrapping and relied on the clearfix hack to push down content below.

Start using CSS Grid today!

(1 Posts)

Chris Wachtman

Chris Wachtman is an experienced front-end software engineer with deep expertise in creating responsive designs that are engaging, as well as 508-compliant. Chris has led efforts in creating the front-end for USA.gov, GobiernoUSA.gov, and new.export.gov. He regularly contributes his talent to nasa.gov, and has created multiple front-end widgets for the new NASA website. Chris is an Android enthusiast and holds a B.S. in Computer Science (with a Minor in Math) from Virginia Tech. He has written this article for Mobomo.

Comments