CSS108 - CSS Grid Layout

CSS Grid Layout is an incredibly powerful layout module in CSS. It is two-dimensional, so it can handle columns and rows.

It has some similarities to flexbox, but there is a fundamental difference between the two. Flexbox is also very powerful, but it is largely one-dimensional. Flexbox handles columns or rows. CSS Grid handles rows and columns.

Together, Grid and flexbox can help us create layouts that were previously impossible to build in CSS.

  1. The Basics

    It all starts by creating a grid container. We do this by declaring display:grid; on an element. As soon as we do this all the direct children of that element will become grid items. It works in the same way as flexbox. You'll notice with CSS Grid that all of the styles are placed on the parent element.

    .parent
      .child 1
      .child 2
      .child 3
    .parent
      display: grid

    1
    2
    3

    All of the direct children are now grid items. This will not change how the items are displayed yet because it has just created a single column grid for the items. We need to define grid tracks to add more columns.

    Grid track

    A grid track is the space between two adjacent grid lines, so essentially the columns or rows of the grid. The green area below is a track.

    Add rows and columns

    Quite simply we use the grid-template-columns and grid-template-rows properties to add rows and columns.

    .parent
      display: grid
      grid-template-columns: 100px 100px 200px

    1
    2
    3

    Now we have three columns. We have specified the width of those columns to 100px 100px and 200px. If we add more children to the grid, it will continue to place all children in the order of 100px 100px 200px like this:

    1
    2
    3
    4
    5
    6

    Grid gap

    Do you want some space around those grid items? We use grid-gap for that.

    .parent
      display: grid
      grid-template-columns: 100px 100px 200px
      grid-gap: 10px

    1
    2
    3
    4
    5
    6

    Styling rows

    If we want to we can style rows too using grid-template-rows. In the example below, the first row is 50px tall, the second row is 200px tall, the third will be 50px tall when some items are added to it.

    .parent
      display: grid
      grid-template-columns: 100px 100px 200px
      grid-template-rows: 50px 200px 50px
      grid-gap: 10px

    1
    2
    3
    4
    5
    6

  2. 'But I want a flexible grid', you say.

    Meet the fr unit. fr represents a fraction of the available space in the grid container. So we can switch px to fr.

    .parent
      display: grid
      grid-template-columns: 1fr 1fr 1fr
      grid-gap: 10px

    1
    2
    3

    Three things are happening here.

    • The columns are equal size (they are all 1 fraction)
    • The columns are flexible (1 fraction of the screen width)
    • Grid calculates the width of each column based on the available space and the width of the gap (if specified), which in this case is 10px.

    Resize the browser width and see it in action.

    notation

    Note: There is an easier/more DRY way to write grid-template-columns: 1fr 1fr 1fr; Both declarations below mean exactly the same.

    grid-template-columns: 1fr 1fr 1fr
    grid-template-columns: repeat(3, 1fr) 

    Grid template units

    Perhaps we don't want our columns to be equal sizes. Then we can change the fractions.

    .parent
      display: grid
      grid-template-columns: 1fr 2fr 1fr
      grid-gap: 10px

    1
    2
    3

    We can also mix units. In this example, the second item is 200px. This means that it will always be 200px even if you resize the browser, but the fr items will still resize to fit the space.

    .parent
      display: grid
      grid-template-columns: 1fr 200px 1fr
      grid-gap: 10px

    1
    2
    3

    Auto-fill

    'But I want to fit as many items as will fit into the width of the browser.'

    Sure thing! We need to use the auto-fill or auto-fit keywords for this.

    So when we change the value in the grid-template-columns to the below, it will auto fill as many 200px tracks as possible. Then it will wrap the rest onto a new line.

    .parent
      display: grid
      grid-template-columns: repeat(auto-fill, 200px)
      grid-gap: 10px

    1
    2
    3
    4
    5
    6

    Nice! But it means that we've lost the flexible widths of items.

    minmax

    To add flexibility we can use the minmax keyword. Now we can set a minimum width of items to 200px and maximum to 1fr. Like before, there will be as many 200px columns as will fit into the browser, but if there is space left over it will be distributed between them equally (1 fraction each).

    .parent
      display: grid
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))
      grid-gap: 10px

    1
    2
    3
    4
    5

    auto-fit

    There's just one more problem with this if you're looking for a completely balanced grid. If you expand the browser wide enough to fit all the items in one row, you're left with an empty space at the end. This is because Grid makes tracks (columns) of a minimum of 200px wide even if there is nothing to put in them. How do we make items fit the entire browser width? We can use auto-fit instead of auto-fill like this:

    .parent
      display: grid
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))
      grid-gap: 10px

    1
    2
    3
    4
    5

    Now give the browser a squish. With auto-fit, empty tracks are removed and items fit the entire space.

    That's an entirely responsive grid with one line of CSS! No media queries. How awesome is that?! :-D

  3. Exercises

    In this exercise we are going to build a simple responsive grid containing some cards.

    1. Create the content
      • Set up a new folder with the appropriate .pug file and .styl file.
      • In the .pug file create a parent element and six children.
      • Inside each child element create a card component that looks like the card below. Note: The image is a placeholder, so you can use this image source for all of your cards src=http://fillmurray.com/400/600.
      • Now you should have something that looks like this. Note: the cards are supposed to look huge (apols for the extreme close up) because we haven't built our grid yet. If your cards don't look like the example yet, then add the appropriate styles to make sure the card contents fit the width of their containers.
    2. Style the grid using CSS Grid!
      • Give the grid a max-width of 800px and move it to the center of the page.
      • Give the grid four columns which have equal widths.
      • Add a gap of 10px around each item.
      • Make the grid responsive, so that items auto fit the available space in the browser. They should have a minimum width of 200px.
    3. Looking further
      • Add some more text to some of the card captions so that some cards have more lines of text than others. What do you notice about the grid items?
        In the end your page should look something like this. Use the inspect tool if you are stuck or to check your answers.
        link(href='style.styl' rel='stylesheet')
          
        .parent
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
        
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
        
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
        
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
        
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
              
          .child
            .card
              img(src='http://fillmurray.com/400/600' alt='Bill Murray')
              div.caption Card caption text
              
                
        .parent
          max-width: 880px
          margin: 0 auto
          display grid
          grid-gap: 10px;
          grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))
          .child
            background-color: lightgrey
        
        .card
          .caption
            padding 10px
          img
            width 100%
        
    4. Play Grid Garden, the game for learning CSS Grid.
    5. Further reading: A Complete Guide to Grid.