Book Image

Mastering CSS Grid

By : Pascal Thormeier
4.3 (3)
Book Image

Mastering CSS Grid

4.3 (3)
By: Pascal Thormeier

Overview of this book

CSS Grid has revolutionized web design by filling a long-existing gap in creating real, dynamic grids on the web. This book will help you grasp these CSS Grid concepts in a step-by-step way, empowering you with the knowledge and skills needed to design beautiful and responsive grid-based layouts for your web projects. This book provides a comprehensive coverage of CSS Grid by taking you through both fundamental and advanced concepts with practical exercises. You'll learn how to create responsive layouts and discover best practices for incorporating grids into any design. As you advance, you'll explore the dynamic interplay between CSS Grid and flexbox, culminating in the development of a usable responsive web project as a reference for further improvement. You'll also see how frameworks utilize CSS Grid to construct reusable components and learn to rebuild and polyfill CSS Grid for browsers that don't fully support it yet. The concluding chapters include a quick reference and cheat sheet, making this book an indispensable resource for frontend developers of all skill levels. By the end of this book, you'll have thoroughly explored all aspects of CSS Grid and gained expert-level proficiency, enabling you to craft beautiful and functional layouts for web projects of any size.
Table of Contents (16 chapters)
1
Part 1–Working with CSS Grid
5
Part 2 – Understanding the CSS Grid Periphery
9
Part 3 – Exploring the Wider Ecosystem
12
Part 4 – A Quick Reference

Understanding special grid-related units, keywords, and functions

Let’s now look at the units and CSS functions that CSS Grid has introduced. Many of these are specifically for CSS Grid; however, some might be useful for Flexbox layouts and other use cases.

The fractional unit

The only actual unit that was introduced with CSS Grid is fr—this stands for fractional unit and denotes a fraction of the total space. Think of it like a cooking recipe—for example, two parts of oil mixed with three parts of flour. So, when we want to have a total mixture of 500 grams, we can divide it by five and multiply by the number of parts. So, with 500 grams, we have 200 grams of oil (two parts) and 300 grams of flour (three parts). Now, replace parts with fr, and you’ve understood how the unit works.

When defining grid templates, we can mix in other units, such as px or rem, to denote fixed-size grid cells. CSS Grid will then take the total width, deduct the fixed-size cells, and then calculate the parts again. Returning to the cooking example, say that our recipes tell us to mix two parts of oil with three parts of flour, bake, and then add 100 grams of rosemary as decoration.

If our finished product weighs 600 grams, and we need to calculate the amount of flour and oil, we first subtract the 100 grams of rosemary from the 600 grams and then calculate the weight of the parts again.

The main difference between percentages and fractional units is their basis of calculation. While percentages use the entire size of the grid to calculate their exact values, fr uses what is left over after all fixed-size elements are subtracted.

Sizing keywords and functions

Not only can we use units when defining grid column and row sizes, but we can also give them a general behavior. For that, CSS Grid offers four different keywords and three functions we can use. Most of them are related to the content of the grid cell and will be calculated once the size of the content is known, allowing us to have different-sized grids for each content variant.

The four keywords are min-content, max-content, fit-content, and auto. We can use these keywords as values for grid-template-columns and grid-template-rows instead of using any value with a unit.

The three functions are min(), max(), and minmax(). We can also use these as a substitute for any value with a unit.

First, we can tell the cell to always fit its absolute possible minimum size with min-content. This can be useful if we have images and text aligned in a grid, and the image sizes should define the grid sizes. For the following screenshot, we used an image with a fixed width of 200x200 pixels.

The grid columns are defined as min-content 1fr 4fr. The min-content sizing keyword ensures that the grid cell’s width does not go below 200px, the smallest non-wrappable content:

Figure 1.19 – An image resizing a grid cell

Figure 1.19 – An image resizing a grid cell

As well as images, min-content also takes text into account. If the minimum width of a grid cell, for example, is determined by the longest word in that cell, that word’s pixel width will then be the minimum size. This can have funny effects when paired with word-break: break-all; as the minimum width is then calculated by the widest character:

Figure 1.20 – CSS Grid breaks the text—the widest character, “W”, defines the cell’s width

Figure 1.20 – CSS Grid breaks the text—the widest character, “W”, defines the cell’s width

The second keyword we can use is max-content, which will calculate the maximum possible content size and use this as the grid-cell sizing. So, instead of using the longest word, this will calculate the width of the entire sentence and use that. When paired with images, it will use the image’s max-width or max-height value, depending on if we’re sizing a row or column.

The third keyword is fit-content, a mixture of min-content and max-content. It will behave like the fr unit, but with a minimum value of min-content and a maximum value of max-content.

To illustrate, let’s think about a grid with four columns and a total of 200px width. Each column is evenly spaced with 1fr, except for the first column, which has a sizing of fit-content(50px). We now put an image of 80px width in that first column. Instead of resizing the image to 50px width, it will increase the size of the cell to 80px and reduce the size of all the others by 10px each.

To summarize, we would use the following CSS code:

.fit-content-grid {  display: grid;
  width: 200px;
  grid-template-columns: fit-content(50px) 1fr 1fr 1fr;
}

And we apply it to the following HTML structure:

<div class="fit-content-grid">  <img src="assets/80.png" alt="80x80">
  <div>A</div>
  <div>B</div>
  <div>C</div>
</div>

We can see how the image stays the same size in the following screenshot:

Figure 1.21 – A grid using fit-content to allow a cell to grow if the content does not fit

Figure 1.21 – A grid using fit-content to allow a cell to grow if the content does not fit

We can see that the entire width stays at 200px. The columns containing letters are significantly smaller than the one containing an image. The cell has expanded to fit the content.

However, if we removed the image—for example, with JavaScript—the cell size would go back to 50px. If we used max-content instead, it would result in a column width of 0px since there is no content.

The last keyword is auto. This also behaves a lot like the fr unit but with a little twist. It is interchangeable with 1fr if only 1fr is used. Consider the following grid declaration:

.grid {  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

This declaration behaves the same as the following one:

.grid {  display: grid;
  grid-template-columns: auto auto auto;
}

The following screenshot shows the equivalence:

Figure 1.22 – Two grids: one of them uses fr units, and the other uses the auto keyword

Figure 1.22 – Two grids: one of them uses fr units, and the other uses the auto keyword

Both grids are the same width and share the same number of columns. The top one uses fr units, and the bottom one uses the auto keyword. We can see that all columns are the same size.

However, when we mix the two, auto receives a different share of the available space than the columns using fr: instead of taking up a unit of space, the auto-sized cell will resize to fit its content and the fr cells will take up that remaining space. This behavior is equivalent to using a fixed unit value: fr will always divide the leftover space.

To illustrate this behavior, let’s consider the following declaration:

.grid {  display: grid;
  width: 500px;
  grid-template-columns: auto 1fr 3fr;
}

The size of the first column depends on its content. An image with a width of 120px means that the grid cell will be 120px wide. 1fr of space would therefore be 95px, a quarter of the remaining space. Likewise, if we use an image with a size of 40px, the first column will be 40px wide and 1fr of space would equal 115px, a quarter of the remaining 460px of the entire grid.

The same applies to text. When we consider the previous grid definition and apply it to the following HTML, CSS Grid will make the first column the largest and squeeze in the other two, which will only take up as much space as their content needs:

<div class="grid">  <div>
    Lorem ipsum dolor sit amet
    Lorem ipsum dolor sit amet
    Lorem ipsum dolor sit amet
  </div>
  <div>
    Short
  </div>
  <div>
    Text
  </div>
</div>

The result looks like this:

Figure 1.23 – Spacing with auto and the fr unit

Figure 1.23 – Spacing with auto and the fr unit

If we want to explicitly state a minimum and maximum size for our grid cells, we can use a function called minmax(). This function does precisely what one would think: it sets a minimum and a maximum for the size of a value. When paired with the fr unit, we can give cells relative sizes but keep them at a minimum and maximum size. Remember the example with word-break: break-all;?

The min-content keyword, in combination with word-break: break-all;, resized the column to the width of the largest character, which is undesirable. We can mitigate such issues by using minmax() and assigning it a minimum value, as shown here:

<style>.container {
   width: 500px;
   display: grid;
   grid-template-columns: minmax(50px, min-content) 1fr 3fr;
   gap: 25px;
}
div {
   word-break: break-all;
}
</style>
<div class="container">
  <div>
    Hello, World!
  </div>
  <div>
    Some other column
  </div>
  <div>
    Some other column
  </div>
</div>

From this code, the first column has a width of 50px, the defined minimum size:

Figure 1.24 – Spacing with minmax

Figure 1.24 – Spacing with minmax

However, if larger content is found within the cell, such as an image, it will be enlarged:

Figure 1.25 – Spacing with minmax and larger content in the first cell

Figure 1.25 – Spacing with minmax and larger content in the first cell

We can also use the min() and max() functions for grid sizing. min() takes the smaller of two values and is often used with a relative and an absolute value, while max() takes the larger of two values, respectively.

For example, a column with min(50vw, 200px) sizing would result in a width of 50% up to a screen size of 400px. From 401px onward, the column would stay at 200px since that would be smaller than 50% of 401px, behaving like a combination of max-width and width.

Likewise, a column with max(50vw, 200px) sizing would result in a 200px-wide column for all screen sizes smaller than 400px. It thus behaves like a combination of min-width and width.

Repetitive column and row definitions

Imagine a gallery of images: it should be 800px wide and 1600px tall. Each image should take up 100px by 100px, resulting in 8 columns and 16 rows, all equally sized. If we wrote out this grid definition, it would look like this:

.gallery-container {  width: 800px;
  height: 1600px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr
    1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

This grid definition has several issues. The first is its readability. The brain can only quickly count about four items at a glance—a concept known as subitizing—and so when more than four or five similar items occur at once in an unfamiliar pattern, the brain doesn’t immediately know the number of items and has to count manually.

The second problem is its maintainability. Code repetition is usually not good for maintainability since it forces us to change the same thing multiple times. For example, imagine that we now got the requirement to fix the image width to 100px but keep the container at 100vw.

To do that, we would adjust every row and column to be 100px instead of 1fr. The resulting code would be even less readable since each cell now takes five instead of three characters to define. The result would look roughly like this:

.gallery-container {  width: 100vw;
  display: grid;
  grid-template-columns: 100px 100px 100px 100px 100px
    100px 100px 100px;
  grid-template-rows: 100px 100px 100px 100px 100px 100px
    100px 100px 100px 100px 100px 100px 100px 100px 100px
      100px;
}

Grid definitions such as these do work—don’t get me wrong—but there’s a tool that allows us to define multiple columns and rows in a much cleaner way: the repeat() function. Instead of writing 100px 24 times, we would rewrite the code using repeat(number, size definition), as shown in the next code snippet:

.gallery-container {  width: 100vw;
  display: grid;
  grid-template-columns: repeat(8, 100px);
  grid-template-rows: repeat(16, 100px);
}

Essentially, the repeat() function replaces the use of multiple identical columns.

We can even mix it with other cell definitions. For example, a grid-column-template value of 100px repeat(10, 1fr) 100px would result in 10 equally sized columns, surrounded by 2 columns of 100px width each:

Figure 1.26 – The repeat() function mixed with other sizing definitions

Figure 1.26 – The repeat() function mixed with other sizing definitions

When we need to define large amounts of alternating sizes, such as 50px 100px 50px 100px 50px 100px, we can also use the repeat() function: repeat(3, 50px 100px). Any valid size definition works, except repeat() itself. Sadly, we cannot nest repeat() calls, so something such as repeat(3 100px repeat(3, 1fr) 100px) won’t work.

The repeat() function already seems very useful, but it gets much fancier with its two accompanying keywords, auto-fill and auto-fit. We use these instead of numbers to define how many grid cells we want. So, instead of repeat(3, 100px), we would write repeat(auto-fill, 100px) or repeat(auto-fit, 100px).

The auto-fill value will add as many grid cells as possible to a row or column. For example, if a container is 375px wide and we define the grid-template-columns rule as repeat(auto-fill, 100px), there will be three columns with a left-over value of 75px. The number of rows and columns is, therefore, dependent on the size of the container. The following code example illustrates this:

<style>  .container {
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px);
    gap: 5px;
    height: 50px;
    margin-bottom: 100px;
  }
  .small {
    width: 375px;
  }
  .large {
    width: 750px;
  }
  .container div {
    background-color: darkred;
    height: 20px;
  }
</style>
<p>Width: 375px;</p>
<div class="container small">
  <div></div>
  <!-- Repeat 10x -->
</div>
<p>Width: 750px;</p>
<div class="container large">
  <div></div>
  <!-- Repeat 10x -->
</div>

The result of the previous code would look like this:

Figure 1.27 – The repeat() function mixed with other sizing definitions and using auto-fill

Figure 1.27 – The repeat() function mixed with other sizing definitions and using auto-fill

On the other hand, we have auto-fit. This keyword tries to fill the entire grid width (when used for grid-template-columns) or height (when used for grid-template-rows). This value is generally practical when working with minmax() and fr as the size definitions, as we allow the grid cells to grow and shrink.

The repeat(auto-fit, minmax(100px, 1fr)),)) value, for example, will result in a minimum column width of 100px. If the container is smaller than the current amount of columns times 100px, it will remove one column, rearrange the layout, and fill the entire width again by enlarging the columns. These values already allow us to build very responsive grids that are useful for article listings or image galleries.

The following screenshot shows the difference in behavior:

Figure 1.28 – The repeat() function using auto-fit

Figure 1.28 – The repeat() function using auto-fit

We can see that the columns now fill the entire container, whereas they were the same size when using auto-fill, auto-fit adapts the width of all columns.

CSS Grid offers us many possibilities to define the sizes of grid rows and columns and even allows us to add responsiveness without the need for media queries. To summarize, CSS Grid offers us an extra unit to define relative sizes, keywords to react size grid cells according to their content, and functions to keep sizes in defined ranges and to simplify repetitive grid definitions, with even more keywords to steer the number of grid cells.