Skip to content

Web-Development-Tutorials/cssgrid-course

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

31 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Table of Contents generated with DocToc

CSS Grid

My notes from CSS Grid course with Wes Bos.

#griddyup

Course will use Firefox - best CSS Grid debugging tools. Recommend Developer Edition.

Setup

Starter Files + Solutions

Will use browsersync to auto refresh browser.

Run npm install, then npm start to open FirefoxDeveloperEdition at localhost:7777

Note base stylesheet uses css variables:

code:root {
  --yellow: #ffc600;
  --black: #272727;
}

CSS Grid Fundamentals

Example

Take any element such as <div> and add display: grid in css. Then you can slice/dice grid into a grid of rows and columns, where items can be placed anywhere in grid. Can also span multiple rows/cols.

Rows/cols are tracks. Content can be laid out within tracks without css positioning.

Emmet trick to get 10 divs with values 1 through 10 inside of them:

.container>.item{$}*10
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

When putting display: grid on a div (container), all its direct children become css grid item (no need to add display property on the direct children).

Define columns, for example to specify 3 columns each of width 100px:

.container{
  display: grid;
  grid-template-columns: 100px 100px 100px;
}

three cols

Rows are automatically created as child items fill up the columns (more on implicit grid later).

grid-gap: 20px will add space between each column and row. Similar to margin, adds space between each track.

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 100px 100px 100px;
}

gap

If column width is defined as wider than content inside it, by default, items inside will stretch to column width.

Can mix and match units on column widths, for example, rem, percentages (but don't use, will have fr unit to replace that).

Can also use auto for column widths:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 100px auto 500px 50px;
}

auto col

Second column will automatically take up whatever leftover space after the fixed width columns are laid out. Can use for fluid/responsive layout. Good for common layout such as fixed sidebar (eg: 300px), then main content area, "the rest" of the view.

Can use repeat function, for eg: 5 columns of 100px each:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(5, 100px);
}

repeat 5 100

Can also specify rows:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-rows: 100px 50px 200px;
}

rows no cols

Note this will make items go all the way across because there are no more columns specified. If you don't specify number of columns, then only get one.

CSS Grid Dev Tools

Example

Difficult to visualize because grid parts such as columns, rows, tracks, gaps etc are not DOM elements so they can't be inspected like regular DOM elements.

Right-click to inspect grid element. In Rules tab where display: grid is shown, can click on grid icon to toggle CSS Grid Highlighter.

Also on Layout tab, shows all the grids. Clicking the checkbox beside the grid in Layout tab will also toggle CSS Grid Highlighter. Displays lines overlapping on grid. Displays where tracks are.

In Grid Display Settings:

  • always check Display line numbers - shows row and column numbers as tags,
  • Display area names - we don't have any yet, will get to that later.
  • Extend lines infinitely - extends track lines to end of viewport, can be difficult to see on top of what you already have, but can modify the line colors by clicking on color circle beside grid item in Layout tab. Easiest to see in most layouts is black.

To distinguish various patterns in the lines (can be subtle), use Mac zoom accessibility (Cmd Option +/-) to zoom entire display in/out.

Note if create a grid with two columns, numbered labels from dev tools will show: 1, 2, 3. Tracks are numbered not by column/row itself, but by lines that start and stop them, so will always be one more number displayed than actual number of columns or rows.

Notice there are different kinds of lines:

  • Solid line: Start and stop of explicit grid.
  • Dashed diagonal line: Gaps
  • Dashed line: Explicit track (eg: dark dashed lines going vertical are explicitly created columns)
  • Dotted lines: Implicit track (eg: if only have columns but enough items that it creates new rows, those are implicit)

Implicit vs Explicit Tracks

In the example below, there are explicitly defined columns, but rows have not, therefore the rows are implicit:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 200px 400px;
}

So if html has more than two grid items to be placed in the grid container, for eg:

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

Browser will place:

  • first item in first column (explicit)
  • second item in second column (explicit)
  • third item gets wrapped, creating a second row (implicit)
  • fourth item gets wrapped, creating second row, (implicit)

Note how the dotted lines in dev tools for implicit change to dashed lines for explicit if css is modified to also explicitly define rows:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 200px 400px;
  grid-template-rows: 100px 200px;
}

If more items are added than can fill the explicit grid, will expand grid beyond the explict end point (solid line), and create an implicit row to place the additional items.

To size implicity created rows:

.container {
  ...
  grid-auto-rows: 500px;
}

Note: Open FF issue - unable to define size of multiple implicit rows, this will get crossed out, but it does work in Chrome:

.container {
  ...
  grid-auto-rows: 500px 200px;
}

Also have grid-auto-columns: 100px;

But just adding that doesn't do anything in this example. By default, define explicit columns, and any extra items are turned into rows. grid-auto-flow can change this behaviour (more in next section).

Grid auto-flow Explained

Example

Set whether another row or column should be added after explicit items have been laid out and getting into implicit items. Default is grid-auto-flow: row. Then additional items create new implicit rows. But grid-auto-flow: column will place additional items in new columns (enough new columns will scroll horizontally).

Given grid-auto-flow: column, then can also use grid-auto-columns: 200px; to specify how wide implicitly created columns should be.

Similar to flex-direction in Flexbox.

Sizing Tracks

Example

Trying to use percentage sizing on columns will create some horizontal scroll, due to gaps, eg:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 25% 25% 25% 25%;
}

A better approach is fr (fractional) unit. fr represents the amount of space left after all elements are laid out. eg, below will use 100% of remaining width for 3rd column, after first two columns of 200px each are laid out.

.container {
  .container {
    height: 600px;
    border: 10px solid var(--yellow);
    display: grid;
    grid-gap: 20px;
    grid-template-columns: 200px 200px 1fr;
  }
}

one fr

Below will first lay out first column of 200px, then divide remaining space equally between 2nd and 3rd columns.

.container {
  height: 600px;
  border: 10px solid var(--yellow);
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 200px 1fr 1fr;
}

one fr one fr

fr units work similarly to flex-grow and flex-shrink in Flexbox. i.e. fr units are in proportion to how much free space is left.

Below, 2nd column will get twice as much of the free space left as first column.

.container {
  height: 600px;
  border: 10px solid var(--yellow);
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 200px 2fr 1fr;
}

two-fr-one-fr.png

If want all columns evenly distributed across free space, don't use pixels at all, use fr units:

.container {
  height: 600px;
  border: 10px solid var(--yellow);
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 1fr 1fr 1fr;
}

cols even

Note adding grid-template-rows: 1fr 1fr 1fr 1fr; won't immediately change anything. Because default height of grid is however high the content is, but default width is viewport width.

To see effect of grid-template-rows, can add explicit height to grid, in this case 2nd row will take up 10x more free space than the others, distributed across a height of 600px, minus grid gap:

.container {
  height: 600px;
  border: 10px solid var(--yellow);
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
}

Can also use auto keyword combined with fr. auto will adjust column to max size of the content (i.e. ALL items in the column will get wider), then 1fr will use all of the remaining free space:

.container {
  .container {
    border: 10px solid var(--yellow);
    display: grid;
    grid-gap: 20px;
    grid-template-columns: auto 1fr;
  }
}

col auto 1fr

Repeat Function

Example

Instead of specifying 1fr four times to get four columns:

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

Use repeat function to specify how many times you want to repeat and what should be repeated, eg:

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

repeat 4

To get 8 columns alternating between 1fr and 2fr:

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr 2fr);
}

repeat 8

Can mix and match regular columns with repeat function:

.container {
  display: grid;
  grid-template-columns: 100px repeat(2, 1fr auto) 200px;
}

Sizing Grid Items

Example

Setting an explicit width on an item within a grid (or placing longer content in it) will make the entire column that wide, not just that item:

.item9 {
  background: mistyrose;
  width: 500px;
}

width 500

To only affect a single item, use spanning, to tell an item to be a specific width. eg, for a single item in a grid to take up two columns: Will start where it naturally starts and then flow into next slot:

.item9 {
  background: mistyrose;
  grid-column: span 2;
}

span 2

If you set span to value greater than there is space on that row, it will bump item down to next row and leave a gap:

.item9 {
  background: mistyrose;
  grid-column: span 2;
}

span 3

Can also span rows:

.item9 {
  background: mistyrose;
  grid-column: span 2;
  grid-row: span 2;
}

span row col

If you span more columns than are available, will force grid to be larger. eg: 5 column grid, but span 10:

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

.item9 {
  background: mistyrose;
  grid-column: span 10;
}

col 5 span 10

Placing Grid items

Example

grid-column: span 2 is actually shorthand of two values: grid-column-start: span 2 and grid-column-end: auto.

To specify grid-column-start and end explicitly, can use track values. For example, to start a particular item at column 2, it will layout all the items before it, then start the item at 2:

.poop {
  grid-column-start: 2;
  background: #BADA55;
}

col start 2

Can also specify end:

.poop {
  background: #BADA55;
  grid-column-start: 2;
  grid-column-end: 5;
}

col start 2 end 5

Short hand version of start/end:

.poop {
  background: #BADA55;
  grid-column: 2 / 5;
}

Can also combine start/end with span, eg: start at track 2 and then span for 2 columns:

.poop {
  background: #BADA55;
  grid-column: 2 / span 2;
}

col start 2 span 2

If don't know how many tracks there will be, can specify to end at last track, eg: start at 1 and go to end (roughly like width: 100%)

.poop {
  background: #BADA55;
  grid-column: 1 / -1;
}

col start to end

To go to second last track, use -2:

.poop {
  background: #BADA55;
  grid-column: 1 / -2;
}

col start to second last

Can mix and match this with rows:

.poop {
  background: #BADA55;
  grid-column: 1 / -4;
  grid-row: 3 / span 3;
}

place col and row

Note that -1 for grid-row will only go to end of explicit grid (in this example, 5 rows):

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
}

.poop {
  background: #BADA55;
  grid-column: span 2;
  grid-row: 1 / -1;
}

row to end

Spanning and Placing Cardio

Example

Given html:

<div class="container">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  ...
  <div class="item poop">πŸ’©</div>
  <div class="item item9">9</div>
  <div class="item item10">10</div>
  <div class="item item11">11</div>
  ...
  <div class="item item30">30</div>
</div>

And css:

.container {
  display: grid;
  grid-gap: 20px;
}

NOTE: Exercises are cumulative!

Make the grid 10 columns wide, every other taking up twice the free space

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(5, 1fr 2fr);
}

10 wide every other 2x

Make the grid have 10 explicit rows, 50px high each

.container {
  display: grid;
  grid-gap: 20px;
  /* Make the grid 10 columns wide, every other taking up twice the free space */
  grid-template-columns: repeat(5, 1fr 2fr);
  /* Make the grid have 10 explicit rows, 50px high each */
  grid-template-rows: repeat(10, 50px);
}

Notice lots of extra explicit rows created (depicted by solid lines in dev tools).

10 rows 50 high

With Item 1, start at col 3 and go until 5

.item1 {
  grid-column: 3 / 5;
}

col 3 to 5

With Item 2, start at col 5 and go until the end

.item2 {
  grid-column: 5 / -1;
}

col 5 to end

Make Item 5 double span 2 cols and rows

.item5 {
  grid-column: span 2;
  grid-row: span 2;
}

col row span 2

Make Item 8 two rows high

.item8 {
  grid-row: span 2;
}

row span 2

Make Item 15 span the entire grid width

.item15 {
  grid-column: 1 / -1;
}

entire width

Make item 18 span 4 widths, but end 9

.item18 {
  grid-column: span 4 / 9;
}

span 4 end 9

Make item 20 start at row 4 and go for 3

.item20 {
  grid-row: 4 / span 3;
}

row 4 span 3

auto-fit and auto-fill

Example

With auto-fill, do not specify how many columns, just tell grid to "figure it out" based on however much content is in each item.

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fill, 150px);
}

auto fill

As viewport is resized, items will jump to next line if there's no more space for them on current line.

auto fill narrow

At first glance, auto-fit doesn't seem to do anything different than auto-fill. Difference is when there are not enough items to fill width or height of grid. In this case, auto-fit will stop explicit grid at last item, whereas auto-fill will continue adding more tracks to end of viewport.

Eg, if there are only 4 child items in grid:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fit, 150px);
}

Notice how explicit grid ends at 4th item, i.e. it makes the grid just wide enough to "fit" the content:

auto fit

Whereas with auto-fill, the grid tracks keep going to fit as much of the view port as possible:

auto fill less items

auto-fill is useful for example, have a few buttons on left side, then want to place some content at the right-most of grid:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fill, 150px);
}

.item4 {
  grid-column-end: -1;
}

auto fill item end

Note this would NOT work with auto-fit because that does not tack on any extra columns:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fit, 150px);
}

.item4 {
  grid-column-end: -1;
}

auto fit item end

Using minmax() for Responsive Grids

Example

Combination of auto-fill/auto-fit/minmax replaces many media queries because it makes grid responsive by design.

Problem: Given this base layout:

<div class="container">
  <div class="item item1">Item 01</div>
  <div class="item item2">Bonjour!</div>
  <div class="item item3">Item 03</div>
  <div class="item item4">Item 04</div>
</div>
.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fill, 150px);
}

min max base

Suppose columns were only 100px wide:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fill, 100px);
}

Then any content wider than 100px starts to spill out of column:

content spill

Don't want to have to calculate how wide columns should be, want them to "flow" as wide as they need to be to fit content.

Solution, use minmax function to specify the min and max column widths for the grid. Max of 1fr means max is entire width of grid. Note don't need to explicitly tell it how many columns.

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

Now as viewport gets narrower, items will wrap to next line when they no longer fit:

min max

Using minmax in combination with auto-fit, the 4 tracks will expand to fill all available space:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  /* grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); */
  grid-template-columns: 150px 150px 150px 150px;
}

min max auto fit

AND as view port shrinks, will wrap, until eventually get a single stacked column:

min max auto fit narrow

Given 4 columns all 150px in a wider viewport:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: 150px 150px 150px 150px;
}

four cols 150

Then changing first column width to auto makes it take up all leftover space:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: auto 150px 150px 150px;
}

first col auto

That auto width column also resizes as viewport width gets smaller:

viewport first col auto

Instead of using auto, use fit-content function, which accepts a clamp value, i.e. max width (for column) or max height (for row) that this auto grid item can grow to. eg:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: fit-content(100px) 150px 150px 150px;
}

fit content

Grid Template Areas

Areas Example

Another way to size and place grid items is to give specific names to areas on grid.

To build "standard" website layout, sidebar on left, another sidebar on right, content in the middle and footer across the bottom, use 3 column grid.

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 500px 1fr;
}

three col grid start

Now add some rows to create a 3x3 grid:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 500px 1fr;
  grid-template-rows: 150px 150px 100px;
}

three by three

Now name areas such that:

  • two squares down left hand side are: sidebar 1
  • two squares down right hand side are: sidebar 2
  • center column is: content
  • strip along bottom: footer

For each area, provide set of quotes, then type name of area you want it to be:

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

Note dev tools will overlay area name on grid:

grid template areas

If want more items to participate in an area, need to be explicit. Recommend breaking out each row in its own line so css matches grid:

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

more template areas

If you want some item not in area, use .

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

dot template area

Optionally, to make css easier to read, tab align the template areas:

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

To place items in areas, given following markup:

<div class="container">
  <div class="item item1">
    <p>I'm Sidebar #1</p>
  </div>
  <div class="item item2">
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, sed.</p>
    <p>Lorem ipsum d</p>
  </div>
  <div class="item item3">
    <p>I'm Sidebar #2</p>
  </div>
  <div class="item footer">
    <p>I'm the footer</p>
  </div>
</div>
.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 500px 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;
}

This will size footer and place it in matching area by name. Note no need to specify how big the item should be or explicitly state where it should go:

place footer

To place remaining items:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr 500px 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;
}

place all items

For responsiveness, use media queries to switch up where areas should go. Also note, for best responsive results, use only fr units for column widths, not px:

.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;
}

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

template areas responsive

When creating grid areas, also get line names.

[Example](14%20-%20Grid%20Template%20Areas/area-line-names-START.html14%20-%20Grid Template Areas/area-line-names-START.html)

Make a grid without explicitly defining any columns or rows:

<div class="container">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  ...
  <div class="item item30">30</div>
</div>
.container {
  display: grid;
  grid-gap: 20px;
  grid-template-areas:
    "πŸ’© πŸ’© πŸ’© πŸ’© πŸ” πŸ” πŸ” πŸ”"
    "πŸ’© πŸ’© πŸ’© πŸ’© πŸ” πŸ” πŸ” πŸ”"
    "πŸ’© πŸ’© πŸ’© πŸ’© πŸ” πŸ” πŸ” πŸ”"
    "πŸ’© πŸ’© πŸ’© πŸ’© πŸ” πŸ” πŸ” πŸ”"
}

area lines start

To make item3 fill up entire :poop: area:

.item3 {
  grid-area: πŸ’©;
}

item 3 poop

Note that grid template area in above example defines 32 slots (8 across x 4 down). But making item-3 fill up all :poop: areas takes up 16 (4x4), which means there are not enough defined slots for the 30 items in markup. Turning on lines in dev tools can see explicit grid areas defined for poop and hamburger. After that, remaining items will be placed in additional rows, which are implicitly created.

To place items using line names, use grid area name, plus -start or -end. These are line names that come for free once you start using grid template areas:

.item3 {
  grid-column: πŸ’©-start / πŸ’©-end;
}

place line names

Can combine different area names in item placement:

.item3 {
  grid-column: πŸ’©-start / πŸ”-end;
}

line name combo

Can also specify row end in this manner. Note item will move down to where row where last poop area is specified and spill into hamburger area:

.item3 {
  grid-column: πŸ’©-start / πŸ”-end;
  grid-row-end: πŸ’©-end;
}

line name poop end

Naming Lines in CSS Grid

Example

In addition to the "free" lines you get from naming template areas, can also explicitly name lines.

Given the following markup:

<div class="container">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  ...
  <div class="item item30">30</div>
</div>

Want to place item3 in the middle, spanning all the way to the top. The way we learned previously is:

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

An alternate approach is to name the lines rather than using numbers. Recall the line numbers do not refer to the columns, they are the lines between the columns. To name the lines, use [] square brackets when defining rows and columns, then refer to those names when defining start and end positions for item(s):

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

.item3 {
  background: slateblue;
  grid-column: content-start;
  grid-row: content-top / content-bottom;
}

col start 2 row 1 span 10

Can also assign multiple line names:

.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];
}

Note: For now, dev tools do not display line names.

grid-auto-flow dense Block Fitting

Example

Recall grid-auto-flow specifies what to do when there are more items than explicitly defined grid can contain. Values can be either row or column. There is 3rd option dense.

Given markup of 70 items

```html
<div class="container">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  ...
  <div class="item item70">70</div>
</div>

This css will create gaps because first 6th item starting at 6th column and spanning 6 is wider than grid has available.

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

.item:nth-child(6n) {
  background: cornflowerblue;
  grid-column: span 6;
}

span 6 gaps

Solution is to use grid-auto-flow: dense, which will fill all available slots:

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

.item:nth-child(6n) {
  background: cornflowerblue;
  grid-column: span 6;
}

grid auto flow dense

Now alter more elements to make them take up more space and comment out dense:

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

.item:nth-child(6n) {
  background: cornflowerblue;
  grid-column: span 6;
}

.item:nth-child(8n) {
  background: tomato;
  grid-column: span 2;
}

.item:nth-child(9n) {
  background: #2f5c62;
  grid-row: span 2;
}

more gaps

If don't care about order in which gaps are filled in, just uncomment dense:

no gaps no order

If want a specific item in a specific slot, css will first layout items that have explicit positioning, then fit in the rest:

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

.item:nth-child(6n) {
  background: cornflowerblue;
  grid-column: span 6;
}

.item:nth-child(8n) {
  background: tomato;
  grid-column: span 2;
}

.item:nth-child(9n) {
  background: #2f5c62;
  grid-row: span 2;
}

/* hackety hack */
.item18 {
  background: greenyellow !important;
  grid-column-end: -1 !important;
}

dense explicit place

Note in this case worked out well with no gaps, but it's NOT a masonry layout, sometimes will get gaps.

CSS Grid Alignment + Centering

Example

CSS Tricks Guide

Even if not using css grid for entire site, still useful for centering content, even easier than flexbox.

There are six properties for alignment:

  • justify-items (default: stretch, other values: center, start, end)
  • align-items (default: stretch, other values: center, start, end)
  • justify-content (default: start, other values: center, start, end, space-around, space-between)
  • align-content (default: stretch, other values: center, start, end, space-around, space-between)
  • align-self
  • justify-self

justify-* controls x axis, i.e. row axis, horizontal axis align-* control y axis, i.e. column axis (top to bottom), vertical axis

Unlike flexbox, these never switch.

Markup:

<div class="container">
  <div class="itm itm1">1</div>
  <div class="itm itm2">2</div>
  <div class="itm itm3">3</div>
  ...
  <div class="itm itm40">40</div>
</div>

Basic css with no centering, this is equivalent to default value on grid container: justify-items: stretch

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

.itm {
  background: white;
}

no center

justify-items and align-items affect the direct children of the grid container.

Example of using justify-items: center:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  justify-items: center;
}

.itm {
  background: white;
}

justify items center

Notice each item becomes only as wide as it needs to be. Modify markup so one item has more content:

<div class="itm itm6">Some very long content yada yada yada... woohoo....</div>

justify items center long content

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  justify-items: center;
}

.itm {
  background: white;
}

Example of using justify-items: start:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  justify-items: start;
}

.itm {
  background: white;
}

justify items start

And justify-items: end:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  justify-items: end;
}

.itm {
  background: white;
}

justify items end

Can also use justify-items: flex-start and justify-items: flex-start because those were flexbox values but recommend sticking with just start/end.

align-items operates along y axis, therefore to see the effect, need to have some row height. First start with default behaviour, i.e. align-items: stretch:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 100px);
}

.itm {
  background: white;
}

align items default

Now try align-items: start:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 100px);
  align-items: start;
}

.itm {
  background: white;
}

align items start

And: align-items: end:

align items end

And: align-items: center:

align items center

To center both horizontally and vertically:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 100px);
  justify-items: center;
  align-items: center;
}

.itm {
  background: white;
}

perfectly centered

Use place-items as shorthand for align-items and justify-items, for example, this would have exact same effect as above:

.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 100px);
  place-items: center center;
}

.itm {
  background: white;
}

justify-content and align-content are concerned with extra space in grid container. For example, if have a grid container that is wider than the content within it:

Note that default is: justify-content: start

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 100px);
  grid-template-rows: repeat(5, 100px);
  place-items: center center;
}

.itm {
  background: white;
}

container wider content

Now try justify-content: end:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 100px);
  grid-template-rows: repeat(5, 100px);
  place-items: center center;
  justify-content: end;
}

.itm {
  background: white;
}

justify content end

And justify-content: center

justify content center

Very useful feature is from flexbox: justify-content: space-around distributes extra space evenly in between columns:

.container {
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 100px);
  grid-template-rows: repeat(5, 100px);
  place-items: stretch stretch;
  justify-content: space-around;
}

.itm {
  background: white;
}

justify content space-around

If you don't want extra space outside left and right-most columns, use justify-content: space-between:

justify content space-between

For next examples, reduce number of items to 10. Suppose grid container has explicit height:

<div class="container">
  <div class="itm itm1">1</div>
  <div class="itm itm2">2</div>
  <div class="itm itm3">3</div>
  <div class="itm itm4">4</div>
  <div class="itm itm5">wes is cool</div>
  <div class="itm itm6">6</div>
  <div class="itm itm7">7</div>
  <div class="itm itm8">8</div>
  <div class="itm itm9">9</div>
  <div class="itm itm10">10</div>
</div>
.container {
  height: 500px;
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 130px);
  place-items: stretch stretch;
  justify-content: space-between;
}

.itm {
  background: white;
}

In this case default behaviour of items is to stretch vertically:

container height

To change this, try align-content: center:

.container {
  height: 500px;
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 130px);
  place-items: stretch stretch;
  justify-content: space-between;
  align-content: center;
}

.itm {
  background: white;
}

align content center

align-content: start:

align content start

align-content: end:

align content end

align-content: space-around:

align content space-around

align-content: space-between:

align content space-between

align-self and justify-self allow for overriding alignment on individual items. Example:

.container {
  height: 500px;
  display: grid;
  grid-gap: 20px;
  border: 10px solid var(--yellow);
  grid-template-columns: repeat(5, 130px);
  place-items: stretch stretch;
  justify-content: space-between;
  align-content: space-between;
}

.itm {
  background: white;
}

.itm5 {
  justify-self: center;
}

Note that itm5 (wes is cool) is centered horizontally whereas all the other items are stretched:

justify self center

align-self works the same way, on individual element, but need to have height to see effect.

Center div

Neat trick to center any div - use grid without defining any rows or columns:

<div class="foo">
  I will be centered!
</div>
.foo {
  display: grid;
  justify-content: center;
  align-items: center
}

Re-ordering Grid Items

Example

Given the following markup and styles:

<div class="container">
  <div class="item logo">LOGO</div>
  <div class="item nav">NAV</div>
  <div class="item content">
    <p>I'm the Content!</p>
  </div>
</div>
.container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(10, 1fr);
}

.logo {
  grid-column: span 2;
}

.nav {
  grid-column: span 8;
}

.content {
  grid-column: 1 / -1;
}

reorder items start

Now for smaller viewport, eg: phone, would like Nav to go above Logo. Use order property. Note default value is 0. So if place it on only one item such as order: 1, will go last because others are 0:

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

.logo {
  grid-column: span 2;
  order: 1;
}

.nav {
  grid-column: span 8;
}

.content {
  grid-column: 1 / -1;
}

logo last

Applying order to all elements:

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

.logo {
  grid-column: span 2;
  order: 2;
}

.nav {
  grid-column: span 8;
  order: 1;
}

.content {
  grid-column: 1 / -1;
  order: 3;
}

order all

Order Gotchas:

  • Accessibility: Modifying order will affect order in which screen reader reads items aloud.
  • Changes order in which items are highlight/selected as user drags with a mouse.

Nesting Grid with Album Layouts

Demo

Real world example building a media layout - grid of cards with photo to left and title/description text to right. It's fully responsive with no media queries!

Markup:

albums markup

For responsive grid, use combination of auto-fit with minmax:

.albums {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  grid-gap: 20px;
}

Add some basic styling for album items:

.album {
  background: rgba(255, 255, 255, 0.2);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
  padding: 20px;
}

albums progress 1

To make album text line up beside album photo, make each album child item of albums grid also be a grid container - i.e. nested grid.

NOTE: To force 300x300 images (natural) into 150px wide column, need to add width: 100% on image container. This will also shrink down image height to 150px since the images are proportional:

.albums {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  grid-gap: 20px;
}

.album {
  background: rgba(255, 255, 255, 0.2);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
  padding: 20px;
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-gap: 20px;
}

.album__artwork {
  width: 100%;
}

albums progress 2

Now make content within each album item vertically centered, final styles:

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

.album {
  background: rgba(255, 255, 255, 0.2);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
  padding: 20px;
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-gap: 10px;
  align-items: center;
  color: white;
  font-weight: 100;
}

.album__artwork {
  width: 100%;
}

albums 3 cols

As viewport shrinks or increases, number of columns will auto adjust:

albums 3 cols albums 2 cols albums 1 cols albums 4 cols

CSS Grid Image Gallery

Demo

Using grid auto-flow dense to build image gallery. As wide or narrow as gallery gets, images just "fit into" eachother.

Gallery section content will be generated by Javascript.

Note all images are 500x500 but will be displayed as 100px wide.

Will also make each individual item where photo is displayed, a 1x1 grid. Reason for this is css grid is very useful for overlapping elements, rather than position: absolute. In this example want to make an overlay for each image item.

To overlap items in a grid container, simply give them the same positioning, eg:

.item img {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.item__overlay {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}

Flexbox vs CSS Grid

Conventional wisdom has been flexbox is suitable for layout in one dimension whereas grid is good when two dimensional layout required. However, grid can do everything flexbox can.

One benefit of flexbox over css grid is transitions. eg, flex-grow can be animated. With grid, only grid-gap can be transitioned.

Grid is more consistent across browsers and doesn't have as many bugs as flexbox.

Following sections has examples of things that can be done in flexbox, and how to do in css grid.

Axis Flipping

In flexbox, have ability to flip flex direction from column to row. In grid, simply change number of columns to 1.

[Controls on Right](cssgrid-course/21%20-%20Flexbox%20vs%20CSS Grid/controls-on-right-START.html)

Media/text on left, controls on right. Any space left in between want to allocate to media/text. Use one column grid. Then grid-auto-flow: column to make additional items get added as columns.

<div class="tracks">
  <div class="track">
    <h2>The Future (Ft. The R.O.C.)</h2>
    <button>⭐</button>
    <button>❀️</button>
    <button>❌</button>
  </div>
  ...
</div>
.track {
  background: white;
  padding: 10px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-flow: column;
}

controls on right

Flex on Item

Media controls for video player. Some control buttons on left and right, and scrubber bar in the middle. Have buttons take up as much space as they need, and remainder of space for scrubber bar.

<div class="controls">
  <button>⏯️</button>
  <button>🐒</button>
  <button>🐰</button>
  <div class="scrubber"></div>
  <button>πŸ’¬</button>
  <button>πŸ”½</button>
</div>

Flexbox solution, in this case, better than CSS Grid:

.controls {
  margin: 200px 0;
  display: flex;
  /* vertical center */
  align-items: center;
}

.scrubber {
  background: #BADA55;
  height: 10px;
  min-width: 100px;
  border-radius: 10px;
  /* flex grow scrubber to take all extra space */
  flex: 1;
}

CSS Grid solution is more brittle because must specify each column to match a button:

.controls {
  margin: 200px 0;
  /* display: flex; */
  display: grid;
  grid-template-columns: auto auto auto 1fr auto auto;
  align-items: center;
}

.scrubber {
  background: #BADA55;
  height: 10px;
  min-width: 100px;
  border-radius: 10px;
  /* flex: 1; */
}

media controls flexbox

Perfectly Centered

Common use case - have an area with height such as hero, and want to center any number of items within it.

<div class="hero">
  <h2>Something Big Is Coming</h2>
  <p>Get Ready...</p>
</div>

First, the flexbox solution:

.hero {
  height: 200px;
  background: rgba(255, 255, 255, 0.2);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

hero center flex

Now grid solution (increased height)

.hero {
  height: 400px;
  background: rgba(255, 255, 255, 0.2);
  /* display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center; */
  display: grid;
  justify-items: center;
  align-content: center;
}

hero centered grid

With centering, either solution flex or grid is good, pick whichever you prefer.

Next example only doable with grid:

[Self Control](cssgrid-course/21%20-%20Flexbox%20vs%20CSS Grid/self-control-START.html)

To align items in each of 4 corners of a box. Practical use?

<div class="corners">
  <div class="corner item">1</div>
  <div class="corner item">TWO</div>
  <div class="corner item">3</div>
  <div class="corner item">4</div>
</div>

Start by making a 2 x 2 grid, this example uses shorthand syntax:

.corners {
  display: grid;
  height: 200px;
  width: 200px;
  border: 10px solid var(--yellow);
  /* make a 2 x 2 grid */
  /* grid-template-columns: 1fr 1fr;
  grid-template: 1fr 1fr; */
  /* shorthand version of above */
  grid-template: 1fr 1fr / 1fr 1fr;
}

By default content is stretching:

two by two

Make each item align in its respective corner:

.corners {
  display: grid;
  height: 200px;
  width: 200px;
  border: 10px solid var(--yellow);
  /* make a 2 x 2 grid */
  /* grid-template-columns: 1fr 1fr;
  grid-template: 1fr 1fr; */
  /* shorthand version of above */
  grid-template: 1fr 1fr / 1fr 1fr;

  /* put items in bottom right hand corner of each cell */
  align-items: end;
  justify-items: end;
}

/* override alignment */
.corner:nth-child(1),
.corner:nth-child(2) {
  align-self: start;
}

/* override alignment - justify-self is grid only, cannot do in flexbox */
.corner:nth-child(1),
.corner:nth-child(3) {
  justify-self: start;
}

align corners

Stacked Layout

Only doable in flexbox, because grid columns are rigid, can't have rows that are different sizes.

<!-- Stacked Layout -->
<div class="stacked">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>
.stacked {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
}

.stacked>* {
  width: 30%;
  margin-bottom: 20px;
}

stacked layout flex

[Unknown Content Size](cssgrid-course/21%20-%20Flexbox%20vs%20CSS Grid/unknown-content-size-START.html)

Use this technique when you know how many columns you have but not width of content in each:

<div class="container known">
  <div class="item">Short</div>
  <div class="item">Longerrrrrr</div>
  <div class="item">
    <img src="https://source.unsplash.com/300x200" alt="">
  </div>
  <div class="item">πŸ’©</div>
</div>
.known {
  margin: 100px 0;
  display: grid;
  grid-template-columns: repeat(4, auto);
  justify-content: center;
  grid-gap: 20px;
}

Unknown Number of Items

Want columns to take up as much space as available, but don't know in advance how many columns there will be.

Given this markup:

<script>
  function addItem() {
    const unknown = document.querySelector('.unknown');
    unknown.innerHTML += `<div class="item">${unknown.childElementCount+1}</div>`;
  }
</script>
<button onClick="addItem()">+ Add</button>
<div class="unknown">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>

Use repeat, auto-fit and min-max:

.unknown {
  display: grid;
  grid-template-columns:  repeat(auto-fit, minmax(50px, 1fr));
  grid-gap: 20px;
}

unknown num items

When items reach 50px, since that's the min, will start to wrap if add more items:

unknown num items wrap

[Variable widths each row](cssgrid-course/21%20-%20Flexbox%20vs%20CSS Grid/variable-widths-each-row-START.html)

In this case flexbox is better.

<div class="flex-container">
  <div class="item">Short</div>
  <div class="item">Longerrrrrrrrrrrrrr</div>
  <div class="item">πŸ’©</div>
  <div class="item">This is Many Words</div>
  <div class="item">Lorem, ipsum.</div>
  <div class="item">10</div>
  <div class="item">Snickers</div>
  <div class="item">Wes Is Cool</div>
  <div class="item">Short</div>
</div>
.flex-container {
  display: flex;
  flex-wrap: wrap;
}

.flex-container>* {
  /* make each item fit in as perfectly as possible */
  flex: 1;
}

variable widths each row

Reacreating Codepen

Codepen Markup | Codepen Styles

CSS grid well suited for application - multiple windows in view, some scrolling, all need to fit in however big viewport is. Codepen is good example, 4 main parts:

codepen main parts

Overall approach: Outer container will be a grid, where header and footer take up as much space as they need, then split the difference between code editor and preview windows:

.codepen {
  display: grid;
  grid-template-rows: auto 1fr 1fr auto;
}

NOTE: To make grid-template-rows auto and 1fr work, need a height on .codepen, make it 100% of viewport with height: 100vh;

codepen final

Bootstrappy Grid with CSS Variables

Demo

Bootstrap style grid more rigid compared to css grid that can flex to whatever the viewport size and extra space. But there's still valid use cases for bootstrap style, 12 column grid.

Use css variables for a flexible grid (rather than explicitly defiing classes such as span1, span2 etc):

<!-- override default num cols of 12 with 10 -->
<div class="grid" style="--cols: 10;">
  <div class="item">1</div>
  <!-- override default span of 1 with 3-->
  <div class="item" style="--span: 3;">longer text</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
.grid {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(var(--cols, 12), minmax(0, 1fr));
}

.item {
  width: 100%;
  grid-column: span var(--span, 1);
}

grid with vars

Responsive Website

Demo Markup | Demo Styles

Typical website with hero image, calls to action on the side, responsive navigation, feature columns, instagram pics at bottom.

Use grid template areas to name sections, useful for responsive layout.

Note that ::before and ::after psuedo elements are considered grid items.

Full Bleed Blog Layout

Example

In addition to app layout, CSS Grid also useful for laying out text. eg - tips to right or left, imags that "full bleed" - width goes past where text is.

Approach: Make post class a grid with 3 columns, where content in center taking up the most space. Some images will span all 3 columns across.

Full bleed image:

.post > figure {
  margin: 0;
  grid-column: 1 / -1;
}

.post figcaption {
  font-size: 10px;
}

blog full bleed image

Tips right and left:

.tip {
  background: #FAFAFA;
  padding: 10px;
  align-self: start;
}

.tip-left {
  grid-column: 1 / span 1;
  text-align: right;
  border-right: 2px solid var(--yellow);
}

.tip-right {
  grid-column: span 1 / -1;
  border-left: 2px solid var(--yellow);
}

blog tip right

blog tip left

About

Learning CSS Grid with Wes Bos

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • HTML 90.2%
  • CSS 9.8%