Understanding CSS Grid Systems from the Ground Up

Ryan Morr
Share

Over the past few years CSS grid systems have grown a lot in popularity, quickly becoming considered best practice for rapid layout scaffolding. As a result, there has been no shortage of frameworks popping up offering their own grid systems trying to garner favor.

If you’re the curious type, such as myself, than you may be asking yourself what exactly grid systems bring to the table? How do they work? And how might you go about creating your own? These are just some of the questions I will be trying to answer as I explore the various concepts at play while stitching together a basic grid system from the ground up.

What is a Grid System?

In case you’re new to CSS grid systems, we’ll start with a quick definition. In basic terms, a grid system is a structure that allows for content to be stacked both vertically and horizontally in a consistent and easily manageable fashion. Additionally, grid system code is project-agnostic giving it a high degree of portability so that it may be adopted on new projects.

The Benefits

  • They increase productivity by providing simple and predictable layout scaffolding to HTML design. The structure of a page can be formulated quickly without second guessing its precision or cross-browser compatibility.
  • They are versatile in how layouts can be constructed, being adaptable in varying combinations of rows and columns. They even support nested grids for more complex use cases. No matter your layout requirements, a grid system is almost certainly well suited.
  • They are ideal for responsive layouts. This is where grid systems reign supreme. They make it incredibly easy to create mobile friendly interfaces that are adaptable to different sized viewports.

The Primary Components

Grid systems include two key components: rows and columns. Rows are used to accommodate the columns. Columns make up the final structure and contain the actual content. Some grid systems will additionally include containers, which serve as wrappers for the layout.

Resetting the Box Model

First and foremost, it is important for any grid system to reset the box model. By default, the browser does not include the padding and border within the declared width and height of an element. This does not bode well for responsiveness. Thankfully, this can be fixed by setting the box-sizing property to border-box for both rows and columns:

.row, 
.column {
    box-sizing: border-box;
}

Now we can leverage percentages for the widths of the columns. This allows the columns to scale upwards and downwards within different viewports while maintaining the structure.

Clearing Floats

In order to align the columns horizontally, grid systems will float the columns. This means you need to clear the floating elements on the row to maintain the structure of the layout. This is where a clearfix comes in:

.row:before,
.row:after {
    content: " ";
    display: table;
}

.row:after {
    clear: both;
}

By applying the clearfix to the row in your CSS, it will cause the row to stretch to accommodate the columns it contains without adding to the markup.

Defining Columns

For columns, the styles need to be defined in 2 parts: the common styles and the widths. First the common:

.column {
    position: relative;
    float: left;
}

Here, the column is given a relative position to allow any absolutely position content within the column to be positioned relative to that column. The column is then floated left for horizontal alignment, which will cause the element to become display: block even if it did not start out that way.

Creating Gutters

Gutters help to create separation between columns for greater legibility and aesthetics. There are 2 schools of thought when approaching gutters; defining paddings within each column or using a percentage-based left margin for each column.

I prefer the latter approach because it facilitates responsive gutters that will remain relative to the columns and the viewport as a whole with different screen sizes. It also lets you define additional paddings for columns for further flexibility. The biggest advantage of padding-based gutters is in how they simplify calculations for column widths, which will become evident in the next section.

Using the percentage-based margin approach, we can target columns that are an adjacent sibling to a preceding column. This will create a left margin for every column except the first one, which we’ll define at 1.6% using the margin-left property:

.column + .column {
    margin-left: 1.6%;
}

Calculating Column Widths

Before we can begin making calculations, we need to determine the maximum amount of columns per row. A popular choice is 12 as it boasts flexibility given that it is divisible by 1, 2, 3, 4, and 6. This permits a variety of different combinations that still allow for evenly distributed columns of the same size.

It’s important to understand that by going with a maximum of 12 columns per row, you need to fulfill that amount for every row regardless of how many columns you want. For example, if you wanted only a row of 3 equal columns, you would use 3 elements that each span 4 columns (4×3=12). Exceeding the sum of 12 will result in the extra column(s) wrapping to a new line.

Now that we know the maximum number of columns, next we need to determine the width of a single (1/12) column using the following formula:

scw = (100 – (m * (mc – 1))) / mc

Where:

  • scw = single column width
  • m = margin (1.6%)
  • mc = maximum columns (12)

When we plug in the numbers, we get a single column width of 6.86666666667%. From here we can use this number to calculate the rest of the column widths. The formula for this is:

cw = (scw * cs) + (m * (cs – 1))

Where:

  • cw = column width
  • scw = single column width (6.86666666667%)
  • cs = column span (1-12)
  • m = margin (1.6%)

Applying this formula for each of the 12 columns results in the following CSS.

.column-1 {
    width: 6.86666666667%;
}

.column-2 {
    width: 15.3333333333%;
}

.column-3 {
    width: 23.8%;
}

.column-4 {
    width: 32.2666666667%;
}

.column-5 {
    width: 40.7333333333%;
}

.column-6 {
    width: 49.2%;
}

.column-7 {
    width: 57.6666666667%;
}

.column-8 {
    width: 66.1333333333%;
}

.column-9 {
    width: 74.6%;
}

.column-10 {
    width: 83.0666666667%;
}

.column-11 {
    width: 91.5333333333%;
}

.column-12 {
    width: 100%;
}

Optimizing for Mobile Devices

Despite the fact that the grid system is responsive, it can only go so far. For devices with small viewports, such as smartphones, the width of the columns need to be adjusted to allow the content they contain to still appear legible and visually appealing. Media queries help with this:

@media only screen and (max-width: 550px) {
    .column-1, 
    .column-2, 
    .column-3, 
    .column-4, 
    .column-5, 
    .column-6, 
    .column-7, 
    .column-8, 
    .column-9, 
    .column-10, 
    .column-11, 
    .column-12 {
        width: auto;
        float: none;
    }

    .column + .column {
        margin-left: 0;
    }
}

Here, we are telling the grid to allow every column to take up the full width of its container for devices with a viewport smaller than 550px pixels wide. Since gutters are no longer necessary here, we remove those too.

Alternatively, you could opt for a mobile first strategy that takes the opposite approach, scaling upwards to a 12-column layout. In such a case, columns start as full-width, then we establish the column widths and floats to allow them to align horizontally as the screen resolution reaches a specified threshold. This is the preferred approach for Bootstrap’s grid system, which doesn’t institute the column widths until the viewport reaches a minimum width of 992 pixels. This may be a more favorable approach for your use case, and should be something to look out for when evaluating a grid system.

Pulling it all Together

When we combine all the concepts and CSS, we can write HTML layout scaffolding like so:

<div class="row">
    <div class="column column-4"></div>
    <div class="column column-4"></div>
    <div class="column column-4"></div>
</div>

<div class="row">
    <div class="column column-2"></div>
    <div class="column column-4"></div>
    <div class="column column-4"></div>
    <div class="column column-2"></div>
</div>

Check out the CodePen demo below to see the entire grid system in action, including nested grids:

See the Pen Understanding CSS Grid Systems by SitePoint (@SitePoint) on CodePen.

You can also try the full screen demo for a better impression. Don’t forget to play around with the screen dimensions to see how the grid handles different viewports.

Conclusion

As you can see, it doesn’t take much to put together a basic grid system. The math is probably the most complex part. Despite its simplicity, the grid continues to be a powerful and flexible tool for layout scaffolding. With the various concepts I’ve discussed here, hopefully you have a better understanding of how grid systems work. This should help you evaluate different grid systems moving forward, and choose the right one for your next project, or even create your own.