CSS Grid Intro

Reference

I couldn’t hold off! Today I did the CSS Grid course. Start to finish in one day!

For quick reference:

Setting Up A Grid

First step is to create a container which will hold all of the grid items and set its display to grid:

<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>

<style>
.container {
display: grid;
}
</style>

To set the number of columns, add a grid-template-columns property to the container. This can be set by pixels, rems, auto, repeat, etc. To set the number of rows, it’s grid-template-rows:

.container {
display: grid;

/* 4 columns, specific width */
grid-template-columns: 100px 50px 100px 100px;

/* 3 columns, specific outer width, fluid center */
grid-template-columns: 100px auto 100px;

/* 3 columns, 1st clamped to max 100px, 2nd 300px, 3rd auto */
grid-template-columns: fit-content(100px) 300px auto;

/* 2 rows, specific-height 1st, then fluid 2nd */
grid-template-rows: 100px auto;

/* 4 rows, 1 fractional unit each */
grid-template-rows: repeat(4, 1fr);

grid-gap: 20px;
}

Note: auto will be sized automatically based on the content within the largest grid item.

Columns and rows are explicit if you specifically define how many there should be, and what their sizes should be; and implicit if you don’t define this information. When you have more container items than explicitly-defined rows and columns, the extra items will overflow to their best fit.

If you want a bit more control over what that “best fit” will be, you can use grid-auto-rows and grid-auto-columns to define the size of overflow areas. By default, overflow items will be put into the next row in the grid, but you can change the default behavior and make them overflow to a column with grid-auto-flow: column; (default value is row).

Sizing Rows & Columns

To create a gutter/margin within the grid, use grid-gap. An interesting thing about grid-gap: if you have this defined, it makes it so that setting column widths by percentage isn’t great! If you have 4 columns of 25%, it will actually go off the page because of the extra 60px of grid-gap, using the example above. So percentages are ok if used in combination with auto, but the better option is using fractional units fr.

Fractional units works similarly to flex-grow and flex-shrink in Flexbox: they proportionally fill any unused space. So if you have 3 divs: div1 width is set to 50%, div2 is 3fr, and div3 is 1fr, div1 will take up 50% of the screen, then from the remaining unused space, div2 will get 75% of it, and div3 will get 25%.

You can also use a repeat() function to define row and column widths. The grid will repeat whatever you have as the second argument, meaning you can create a mix of repeating grid areas. You can also use repeat in conjunction with other definitions. Some examples:

.container {
/* 3 columns, equal widths */
grid-template-columns: repeat(3, 1fr);

/* 4 columns, alternating 25% to 75% of unused space */
grid-template-columns: repeat(2, 1fr 3fr);

/* 6 columns, you get the picture... */
grid-template-columns: 300px repeat(2, 1fr 2fr) auto;
}

Auto-Fit & Auto-Fill

Another option for sizing columns & rows is to use auto-fit and auto-fill instead of explicit values:

.container {
grid-template-columns: repeat(auto-fit, 1fr);
/* or */
grid-template-columns: repeat(auto-fill, 300px);
}

This says to leave it up to the grid to determine how many columns will be created, based on the viewport width. This enables the site to be responsive!!

There is a slight difference between auto-fit and auto-fill: auto-fill will dynamically create the explicit grid area based on the viewport width, whereas auto-fit will create the explicit grid area based on the number and contents of the grid items. So let’s say you want one grid item to always be on the right-most edge of your viewport: if you use auto-fill this will be possible, but if you use auto-fit, the item will only stay to the right-most side of the other grid items.

Minmax()

Now to get super-duper responsive layouts, minmax() can be used together with auto-fit or auto-fill. Within a minmax() definition, you declare the minimum and maximum widths or heights that the tracks should take up. As a result, the tracks will be determined based on the size of the window. For example:

.container {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

Sizing Grid Items

Individual grid items can also be resized in a different way to their default row/column pattern. To have a grid item go across multiple columns, add a span instruction to that particular grid item: grid-column: span 2. The same span technique works across rows: grid-row: span 4.

Note: if you’re spanning 3 columns, but there are only two columns on that row, by default the 3-column grid item will be pushed down to the next row, leaving empty space: CSS Grid will always push items to wherever they can fit by default. Likewise, if you try to span more columns than are defined in the grid, new implicit columns will be created.

grid-column and grid-row are shorthand for grid-column-start and grid-column-end (and same for rows). So it’s possible to specify and exact location in the grid where the item should begin and end. Or you can condense it into two parts of the same line:

.my-grid-item {
/* Start at 2nd track, end at 5th */
grid-column-start: 2;
grid-column-end: 5;

/* Start at 2nd track, end at 5th */
grid-column: 2 / 5;

/* Span 3 columns, must end at track 5 */
grid-column: span 3 / 5;

/* Must start at track 1, span 4 columns */
grid-column: 1 / span 4;

/* Span all columns!! */
grid-column: 1 / -1;
}

Note that to use the 1 / -1 technique, you have to define your rows or columns—whichever you want to apply this span to. So if you have only defined columns, and then try to set grid-row: 1 / -1;, it won’t work. It’s also important to note that it will only be able to span explicit columns or rows; if other grid items have overflowed into implicit areas, the full-width span may not work in the way you want or expect it to.

Filling Empty Grid Spaces

If you have changed the sizing for some grid items, because of how overflow works, you might end up with holes in the layout—grid areas where the next grid item couldn’t fit. If order isn’t important, you can fill in these empty grid spaces by setting the container to dense; this way, when faced with empty spaces, the grid will check whether there is any grid item that can be used to fit the space.

.container {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(10, 1fr);
grid-auto-flow: dense;
}

Naming Grid Areas

Going back to the layout of columns and rows, it’s also possible to name areas and then assign grid items to a named area, rather than referencing column or row numbers. For example:

.container {
display: grid;
grid-gap: 20px;
grid-template-columns: 1fr 10fr 1fr;
grid-template-rows: 150px 150px 100px;
grid-template-areas:
"sidebar-1 content sidebar-2"
"sidebar-1 content sidebar-2"
"footer footer footer"
}

.footer {
grid-area: footer;
}

.item1 {
grid-area: sidebar-1;
}

.item2 {
grid-area: content;
}

.item3 {
grid-area: sidebar-2;
}

By identifying a name for each area of your grid and then assigning a grid item to that area, grid items will be stretched to fill up the whole area. This is also a good way to completely change the order for a responsive layout. From the example above, you could add a media query to change which sections are displayed where:

@media (max-width: 700px) {
.container {
grid-template-areas:
"content content content"
"sidebar-1 sidebar-1 sidebar-2"
"footer footer footer"
}
}

Another option for setting the layout is to name areas without first defining what those areas are:

.container {
display: grid;
grid-gap: 20px;
grid-template-areas:
"sidebar-1 content sidebar-2"
"sidebar-1 content sidebar-2"
"footer footer footer"
}

.footer {
grid-column: footer-start / footer-end;
}

.item1 {
grid-row: sidebar-1-start / sidebar-1-end;
}

.item2 {
grid-row: content-start / content-end;
}

.item3 {
grid-row: sidebar-2-start / sidebar-2-end;
}

Naming Grid Lines

It’s also possible to name grid lines instead of grid areas, and then use those names to assign grid items. You would set this up by adding the line name inside square brackets [] when defining the column or row widths/heights. You can also give more than one name (separated by a space) to each grid line. For example:

.container {
display: grid;
grid-gap: 20px;
grid-template-columns:
[sidebar-start site-left] 1fr
[sidebar-end content-start] 500px
[content-end] 1fr
[site-right];
grid-template-rows: [content-top] repeat(10, auto) [content-bottom];
}

.my-grid-item {
grid-column: content-start;
grid-row: content-top / content-bottom;
}

Ordering Grid Items

Grid areas can be ordered…especially useful for media queries if you want to change from the default order on smaller screens. We use the order: 1 property to define an order for an individual grid item. The default order for every item is 0, so you can use -1 to move something to the top, or order all of the items.

Note: changing the order with CSS doesn’t change the order for accessibility purposes! If you move text around in the display, a screen reader will still read them in the order they appear in your HTML.

Aligning & Centering Items and Content

CSS Grid comes with 6 properties to help align individual grid items. They start with justify- for items on the row (x) axis, or align- for items on the column (y) axis. Unlike with Flexbox, these designations don’t change. For quick reference, the CSS Tricks Guide shows demos of each, but to quickly explain…

Justify/Align Items

Determines how unused space in a grid area will be allocated for all grid items. Default is stretch which takes up all available space. Other options are start, end, and center. These can be applied individually to the container, or combined in one row with place-items:

.container {
display: grid;
grid-gap: 20px;
height: 500px;
grid-template-columns: repeat(5, 130px);
justify-items: center;
align-items: center;

/* or */
place-items: center center;
}

Justify/Align Content

Determines how unused space in the grid container will be allocated. Default is stretch which takes up all available space. Other options are start, end, center, space-around, space-between, and space-evenly.

Justify/Align Self

Determines how unused space in the grid area for an individual grid item will be allocated. Default is to inherit the definition that was set for the whole grid.

Example of -content and -self is as follows:

.container {
display: grid;
grid-gap: 20px;
height: 500px;
grid-template-columns: repeat(5, 130px);
justify-items: center;
align-items: center;
}

.my-grid-item {
justify-self: start;
align-self: stretch;
}

Cool Fact!

To center text within an individual item, you can set its display to grid and use these properties:

p {
display: grid;
justify-content: center;
align-items: center;
}

Final Tips

So that’s all the basics covered! To wrap up the course we built a few demo sites using a mix of the properties above. Some final highlights & tips:

Nesting Grids

Grids can be nested within each other as much as you want. A good example is for cards, where you want the elements in the card to display a certain way, but also want the cards themselves to display well next to each other. In this case you would put display: grid; on the wrapper containing the cards and on the card container itself. I wrote this example to demonstrate.

Flexbox vs. CSS Grid

Flexbox and CSS Grid can work well together, although there are some things that each can do that the other can’t:

  • Flexbox gives you the option to order rows/columns from right to left or down to up with row-reverse and column-reverse. CSS Grid doesn’t have a built-in option for this.
  • If you want to stack elements in an inverted pyramid (i.e. overflow divs are centered if they’re in a row on their own), you have to use Flexbox; Grid can’t break its column definitions.
  • Likewise if you want variable column widths on each row, Flexbox is the necessary choice.
  • There is no concept of grid-gap automatic margins in Flexbox.

CSS Variables

Finally, not really related to CSS Grid but I also learned how to create and use CSS variables (aka custom properties) thanks to the Net Ninja’s newest YouTube tutorial series. Variables allow you to set a property value which you can then reference throughout your CSS; a good example is for color schemes…you set the color in a variable and then use the variable rather than a hex code. Then if you decide to change your color scheme, you only need to update the variable value, rather than every place that color appears. Brilliant!

CSS variables need to be declared within a selector, and the de facto way to do this is to declare them at the top of your CSS in a root element. Variables are declared and called with double dashes --:

:root {
--theme-color: #EEE;
--theme-highlight: #333;
}

.hero {
background-color: var(--theme-color);
}

.hero hr {
color: var(--theme-highlight);
}

.nav a {
color: var(--theme-color);
}

.nav a:active {
color: var(--theme-color);
}

Imagine this with much much more CSS and it’s pretty awesome to think of just changing the hex colors once. Awesome! Important to note though, not currently supported in IE.

Whew!

So that was a long and productive day!