Positioning elements with Grid
Tags: css, grid, basics, usecases
Published: 2021-07-27 09:37:25

In this post, I will show you the Grid basics and how I use it to place the content in common situations.

{% tweet 1419954287355043842 %}

## What is Grid?

Grid ([CSS Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout)) is defined as a tool to divide a page into main regions or to define the relationship in terms of size, position and layer.

> The Grid layout is compatible with the vast majority of browsers, some like Opera Mini and IE do not support it, in [Can I use](https://caniuse.com/?search=grid) you can see what properties are supported by which browsers.

It is also known as the two-dimension layout system that provide us with the best alternative to the tables we used in the past, and has taken our user interfaces to the next level.

The grid layout allows us to align the elements in columns and rows, space the elements from the container element, position the child elements by overlapping them or forming layers, among other features.

This facilitates the creation of dynamic and responsive layouts, as we will see throughout the article.

## Where to learn more?

Although in this article we will see the initial concepts and a couple of use cases, tips and tricks, I recommend that if you are interested in knowing the ins and outs of Grid, you should take a look at these resources.

In these courses and articles they explain Grid, show you different use cases and the little details they have learned from experience.

- [Understanding CSS Grid](https://www.smashingmagazine.com/2020/01/understanding-css-grid-container/) Series by Rachel Andrew at Smashing Magazine.
- [Learn CSS Grid](https://cssgrid.io/) course by Wes Bos (free).
- [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by Chris House at CSS-Tricks.

## Grid properties

Now that you know the Grid concept, we are going to see the **properties** we need to shape our layout, distinguishing between the properties of the *parent* or *child* element.

Being the ***parent*** element, the one that contains one or more ***child*** elements that will be sized, aligned, layered and redistributed by the available space. Let's see an example:

```html
<div class="parent grid">
  <p class="child grid-item"></p>
  <p class="child grid-item"></p>
  <span class="child grid-item"></span>
</div>
```

> The parent will be in charge of defining the grid and the children will be in charge of positioning or aligning themselves in specific places, if necessary.

**Parent** (grid *container*) properties:

- **display** - specifies the type of rendering box of an element. With the value *grid*, every direct child will be in a grid context.

  ```css
  display: grid;
  ```

- **grid-template** - a shorthand property for defining grid columns, rows, and areas at once.

  ```css
  grid-template: none|grid-template-rows / grid-template-columns|grid-template-areas grid-template-rows / grid-template-columns
  ```

  But let's take a look at each property individually to see how to define them.

  - **grid-template-rows** - specifies the line names (optional) and track size of the grid rows (horizontal tracks).

  ```css
  grid-template-rows: none|[line-name] track-size [line-name-2];
  ```

  ![Defining grid row tracks size and line names](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iscul9zxx6dufihyqe4d.jpeg)

  - **grid-template-columns** - specifies the line names (optional) and track size of the grid columns (vertical tracks).

  ```css
  grid-template-columns: none|[line-name] track-size [line-name-2];
  ```

  > A **grid track** is the space between any two lines on the grid. As we can see in the image below, between linename and linename2 we have defined a column track of 1fr in size.

  ![Defining grid column tracks size and line names](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vn36vwk141v19snje1w3.jpeg)

  To give value to the size of each row/column track, we must specify the values separating them by spaces and using different units:

  - **By common units**: length (px, rem, ...), percentage (%) and fr.

  > The **fr** unit represents a fraction of the available space in the grid container.

  - **By grid items content**: *min-content,* minimum size of the content, *max-content*, maximum size of the content and *auto*, similar to minmax(min-content, max-content).

  - **By functions**:
    - *minmax(min-size, max-size)* - It defines a size range, greater than or equal to *min*, and less than or equal to *max*.
    - *repeat(n-columns, track-size)* - It allows defining numerous columns that exhibit a recurring pattern in a more compact form.
    - *fit-content(track-size)* - It uses the space available, but not less than the *min-content* and not more than the *max-content* of the children.

```css
/* Common units */
grid-template-columns: [linename] 1fr [linename2] 2fr [linename3] 1fr [linename4];
grid-template-rows: [linename] 1fr [linename2] 1fr [linename3] auto [linename4];

/* Grid items content */
grid-template-columns: 1fr max-content 2fr;
grid-template-rows: 1fr min-content max-content;

/* Functions (& combined) */
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-rows: minmax(60px, 1fr) fit-content(75%);
```

  - **grid-template-areas** - specifies named grid areas by setting the grid cells and assigning names to them.

    No grid item is associated to these areas, but any child element can reference any area with the grid placement properties (grid-row/grid-column, grid-area), which we will see below.

  ```css
  grid-template-areas: none|.|area-strings;
  ```

  The best way to understand this property is to exemplify it, and you will see it clearly.

  ```css
  grid-template-columns: 300px repeat(3, 1fr);
  grid-template-rows: minmax(60px, 1fr) 4fr minmax(60px, 1fr);
  grid-template-areas:  "sidebar header  header  header"
     			"sidebar content content content"
        	        "sidebar footer  footer  footer";
  ```

  The defined **strings** in grid-template-areas are the **row tracks,** and the times that a name is repeated is the **columns** that occupies that area in that row. As you can see in the image below, the header occupies 3 columns and 1 row:

  ![Defined grid areas in a grid container](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zrn008y4rehjbldolqzp.jpeg)

- **grid-auto-columns** - specifies the **size** of an **implicitly** created (auto-created) grid **column track**.

  > By definition, if we haven't explicitly defined in grid-template-columns the size of a column track where a grid item has been positioned, implicit grid tracks are created to contain it.

  ```css
  grid-auto-columns: implicit-tracks-size;
  ```

  The size unit can be any of the ones we have used for grid-template-columns and grid-template-rows.

  ```css
  grid-template-columns: 300px;
  grid-auto-columns: 1fr;
  ```

  ![Defined grid auto columns size](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2e5x2vh8rb6wrebyao9.jpeg)

- **grid-auto-rows** - specifies the **size** of an **implicitly-created** grid **row track**.

  ```css
  grid-auto-rows: implicit-tracks-size;
  ```

  As *grid-auto-columns*, we will use any size unit for the implicit row tracks:

  ```css
  grid-auto-rows: 6rem;
  ```

- **grid-auto-flow** - controls how the auto-placement algorithm works, specifying exactly how auto-placed items get flowed into the grid (*we can think of it as the flex-direction of grid*).

  ```css
  grid-auto-flow: row|column|dense|[row|column] dense;
  ```

  While **row** and **column**, we can guess where the children of the grid will be placed:

  - ***row*** placing the items in the **available horizontal track**, if the current row becomes full then a new row will be started.

    ![Result of setting row as a grid-auto-flow value](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oinnk1stuyoq2ji255kk.jpeg)

  - ***column*** in the **available vertical track**, once the items have filled all the rows in that particular column, then a new one will be created.

    ![Result of setting column as a grid-auto-flow value](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80i7xtx3xey8eshha4pt.jpeg)

  Instead, **dense** tries to **fill in the gaps** earlier in the grid. In the image below, you can see how the third element (blue) is placed in the space left between the first and second element.

  ![Result of setting dense as a grid-auto-flow value](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfd0swfs9irpt306hupv.jpeg)

  > WARNING - **grid-auto-flow: dense;** can cause items to appear visually out of order, causing accessibility problems.

- **gap** - sets the gaps (gutters) between rows and columns. It is a shorthand for row-gap and column-gap.

  ```css
  gap: row-col-gap|row-gap column-gap;
  ```

  > (row-col-gap) As in *padding,* if we specify a single value it will be set for both row and column.

  - **row-gap** - sets the size of the gap in y-axis, between row tracks.

  ```css
  row-gap: 20px;
  ```

  - **column-gap** - sets the size of the gap in x-axis, between column tracks.

  ```css
  column-gap: 5%;
  ```

**Child** (grid *item*) properties:

- **grid-row** - specifies where a child is placed within the grid row tracks and how much it occupies.

  It can be a **line** (placed in 1 row), a **span** (placed in more than 1 row), or **auto** (original placement), thereby specifying the inline-start and inline-end edge of the grid area it occupies.

  ```css
  grid-row: grid-line|grid-row-start / grid-row-end;
  ```

  Let's see what possibilities we have to define the start or end of the child item with the *-start and *-end properties.

  - **grid-row-start** - specifies a grid item’s start position within the grid row.

  ```css
  grid-row-start: [number|name]|span [number|name]|auto;
  ```

  **line**: *number* to refer to a numbered grid line, or *name* to refer to a named grid line.

  **span [number|name]**: the child item will occupy the number of grid rows provided, or until it reaches the line with the specified name.

  **auto**: automatic placement on the original position, with a span of 1.

  ```css
  grid-row-start: span 2; /* The item occupies 2 rows */
  ```

  - **grid-row-end**: specifies a grid item’s end position within the grid row. The values that can be specified are the same as for grid-row-start.

  ```css
  grid-row-end: number|name|span [number|name]|auto;
  ```

  Combining both would look like:

  ```css
  grid-row: span 2 / 5; /* Fit 2 rows and end in the numbered line 5 */
  ```

  ![Result of setting grid-row as span 2 / 5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cmze74pm3h8rpexo5fd.jpeg)

- **grid-column** - specifies where a child is placed within the grid column tracks and how much it occupies. Same as *grid-row* but this time with the vertical tracks.

  ```css
  grid-column: grid-line|grid-column-start / grid-column-end;
  ```

  A shorthand for the CSS properties:

  - **grid-column-start** - specifies a grid item’s start position within the grid column by specifying a line, a span, or auto.

  ```css
  grid-column-start: [number|name]|span [number|name]|auto;
  ```

  - **grid-column-end** - specifies a grid item’s end position within the grid column, also by specifying a line, a span, or auto.

  ```css
  grid-column-end: [number|name]|span [number|name]|auto;
  ```

- **grid-area** - specifies where a child is placed within the grid and its size.

  Its value can be expressed as a shorthand of grid-row-start / grid-row-end / grid-column-start / grid-column-end or with the name of the area created in grid-template-areas.

  ```css
  grid-area: named-area|grid-row-start / grid-row-end / grid-column-start / grid-column-end; 
  ```

  Let's see a simple example for each case:

  ```css
  /* Given grid-template-areas: "content content sidebar"; */
  grid-area: content;

  /* Specifying line numbers:
  grid-row-start: 1
  grid-column-start: 1
  grid-row-end: auto
  grid-column-end: 3
  */
  grid-area: 1 / 1 / auto / 3; /* OR grid-area: 1 / span 2; */
  ```

And these would be the properties that will help us to define the structure of our grid and position its elements individually. Now let's see how to align the elements in the same way, globally or from themselves.

## Alignment properties

Whenever we want to align our layout elements, which are located in cells, we will have to use different properties from the parent but sometimes also from the children, depending on their behavior.

> A **grid cell** is the smallest unit on a grid. Once a grid is defined as a parent, the child items will lay themselves out in one cell each of the defined grid.

![What is a grid cell visually explained](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xef9bnhf415xmt1trf5.jpeg)

Let's see the possibilities we have to align our content by the container or child item.

**Parent** (grid *container*) properties:

- **place-items** - allows you to align child items along the block (y-axis/column) and inline (x-axis/row) directions at once. A shorthand for align-items and justify-items.

  ```css
  place-items: align-items justify-items;
  ```

  To see the values that can be defined, let's take a look at each one of the properties:

  - **align-items** - specifies the alignment of grid items on the block direction (y-axis). It sets the *align-self* value on all child items as a group (we will see this property in the child properties section).

  ```css
  align-items: normal|center|start|end|stretch;
  ```

  - **center** causes the elements to be aligned to the center of themselves (grid item cell).
  - **start** & **end** causes the elements to be aligned at the beginning of themselves (cell top) or end (cell bottom).
  - **stretch** causes the grid items to have the same height as their cell, filling the whole space vertically. The value by default (*normal*).

  ![Align items values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tdv1d15yhq2opcos3pw.jpeg)

  - **justify-items** - specifies the alignment of grid items on the inline direction (x-axis). It sets the *justify-self* value on all child items as a group.

  ```css
  justify-items: normal|center|start|end|stretch;
  ```

  - **center** causes the elements to be aligned to the center of themselves horizontally.
  - **start** & **end** causes the elements to be aligned at the beginning or the end of themselves in the x-axis.
  - **stretch** causes the grid items to have the same height as their cell, filling the whole space horizontally. The value by default (*normal*).
  
  ![Justify items values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/91w1mm5wlb272xuzlofu.jpeg)

- **place-content** - allows you to align the content along the block (y-axis/column) and inline (x-axis/row) directions at once. A shorthand for align-content and justify-content.

  ```css
  place-content: align-content justify-content;
  ```

  Let's take a closer look at the possible values:

  - **align-content** - specifies the distribution of space between and around content items in the block direction (y-axis).

  ```css
  align-content: normal|center|start|end|space-around|space-between|space-evenly|stretch;
  ```

  - **center** causes the elements to be aligned at the center of the grid with respect to the y-axis.
  - **start** & **end** causes the elements to be aligned at the beginning (top) or end (bottom) of the grid with respect to the y-axis.
  - **space-between** causes the grid items to be distributed evenly, being the first item at the start of the grid, and the last at the end.
  - **space-around** causes the grid items to be distributed evenly, having half-size space on top/bottom.
  - **space-evenly** causes the grid items to be distributed evenly, having equal space around them.
  - **stretch** causes the grid auto-sized items to have their size increased equally so that the combined size exactly fills the alignment container.

  ![Align content values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zxijfqjd4neusddrqc5m.jpeg)

  - **justify-content** - specifies the distribution of space between and around content items in the inline direction (x-axis).

  ```css
  justify-content: normal|center|start|end|space-around|space-between|space-evenly|stretch;
  ```

  - **center** causes the elements to be aligned at the center of the grid with respect to the x-axis.
  - **start** & **end** causes the elements to be aligned at the beginning (left) or end (right) of the grid with respect to the x-axis.
  - **space-between** causes the grid items to be distributed evenly, being the first item at the left of the grid, and the last at the right.
  - **space-around** causes the grid items to be distributed evenly, having half-size space on left/right.
  - **space-evenly** causes the grid items to be distributed evenly, having equal space around them.
  - **stretch** causes the grid auto-sized items to have their size increased equally so that the combined size exactly fills the alignment container.

  ![Justify content values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwt0amzr83mpqekak2sx.jpeg)

**Child** (grid *item*) properties:

- **place-self** - allows you to align an individual child item along the block (y-axis/column) and inline (x-axis/row) directions at once. A shorthand for align-self and justify-self.

  ```css
  place-self: align-self justify-self;
  ```

  - **align-self** - overrides the align-items value and aligns the item inside the grid area or cell along the block direction (y-axis).

  ```css
  align-self: center|start|end|stretch;
  ```

  - **center** aligns the content to the center of the grid cell in the y-axis.
  - **start & end** aligns the content to the start/end of the grid cell in the y-axis.
  - **stretch** fills the grid cell in the y-axis (normal value).

  ![Align self values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykwnkqt3mh5xug2f9dxo.jpeg)

  - **justify-self** - overrides the justify-items value and aligns the item inside the grid area or cell along the inline direction (x-axis).

  ```css
  justify-self: center|start|end|stretch;
  ```

  - **center** aligns the content to the center of the grid cell in the x-axis.
  - **start & end** aligns the content to the start/end of the grid cell in the x-axis.
  - **stretch** fills the grid cell in the x-axis (normal value).

  ![Justify self values visual examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j80vfu8azqtmvhvjl1ot.jpeg)

> **BONUS** - [Masonry Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout) is an experimental feature, a layout method where 1 axis uses common values (usually columns), and the other the masonry value. In the axis of the masonry (usually the row), instead of leaving gaps after the small elements, the elements of the next row move up to fill the gaps. (AWESOME, isn't it?)

## Real use cases

Now, I am going to show you how I usually solve, with CSS Grid layout, different situations that I found in website I've developed:

### Situation 1 - Grid sidebar layout

Imagine you are developing a layout that includes a sidebar on the left, which follows you as you scroll, and the rest of the website, header, content and footer, on the right.

Here I show you an example of what I mean and how it could be distributed:

![Situation 1 - Schema on how the grid should look](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uan6kzvpa17xikvuyhbk.jpeg)

To do this, we will first define the grid container and the cells or areas we will need to place our elements, and then the position of the child items in the grid:

```html
<div class="grid grid-cols-[300px,minmax(0,1fr)] grid-rows-[60px,1fr] min-h-screen">
  <aside id="sidebar" class="sticky top-0 h-screen">Sidebar</aside>
  <header class="row-span-1 col-start-2">Header</header>
  <section role="main" class="col-start-2">Content</section>
  <footer class="col-start-2">Footer</footer>
</div>
```

- **CSS Parent**

  ```css
  .grid {
    display: grid;
  }
  .grid-cols-[300px,minmax(0,1fr)] {
    /* 2 column tracks, 1st 300px, 2nd max the space available */
    grid-template-columns: 300px minmax(0, 1fr); 
  }
  .grid-rows-[60px,1fr] {
    /* 2 row tracks, 1st 60px, 2nd the space available */
    grid-template-rows: 60px 1fr;
  }
  .min-h-screen {
    min-height: 100vh; /* Fill the full screen */
  }
  ```

  > **Why is it important to define minmax(0, 1fr) instead of 1fr?** Because by defining minmax and adding the possibility to have a smaller size than 1fr, the content does not overflow. This way, elements like a slider can be added to that responsive column without any problem.

- **CSS Children**

  ```css
  /**
  * Aside - Sidebar
  */
  .sticky {
    position: sticky; /* Follow you when scrolling */
  }
  .top-0 {
    top: 0px;
  }
  .h-screen {
    height: 100vh; /* Fill the screen vertically */
  }

  /**
  * Header
  */
  .row-span-1 {
    grid-row: span 1 / span 1; /* Position: first row track */
  }
  .col-start-2 {
    grid-column-start: 2; /* Position: second column track */
  }

  /**
  * Content & Footer
  */
  .col-start-2 {
    grid-column-start: 2; /* Position: second column track (original position for the row) */
  }
  ```

> Note: The examples will be styled with TailwindCSS using JIT mode, but I'm still going to add the generated CSS for those who don't use it.

### Situation 2 - Grid post thumbnail layout

In this situation, our goal is to represent the thumbnail of our article, showing the image, the title, the description, the date and a like button to save it in our list of interests.

Let's imagine that the image below is the outline of how we want to represent it:

![Situation 2 - Example grid post thumbnail layout](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdv0lmtezpqq3qlispyu.jpeg)

The first thing will be to define our elements in semantic HTML and start defining the grid in the parent, in this case the children will not need to specify their position because they will occupy the space that corresponds to them by location in the HTML.

```html
<article class="grid grid-cols-[120px,minmax(0,1fr),64px] grid-rows-1 gap-4">
	
  <!-- Figure: By default will be added in the first column of 120px -->
  <figure>
    <img src="image_url" alt="image_alt" width="120" height="120" />
  </figure>

  <!-- Header (Title, excerpt and date): By default will be added in the second (available space) column -->
  <header class="py-4">
    <h2>Heading</h2>
    <p class="pb-8">Description or excerpt</p>
    <p>Date</p>
  </header>

  <!-- Like button: By default will be added in the last column of 64px -->
  <button class="w-8 h-8 p-4">
    <svg width="32" height="32">Like Icon</svg>
  </button>

</article>
```

As before, let's differentiate between the style applied to the parent and the one applied to the children:

- **CSS Parent**

  ```css
  .grid {
    display: grid;
  }
  .grid-cols-[120px,minmax(0,1fr),64px] {
    /* 3 column tracks, 1st fixed of 120px, 2nd responsive from 0 to 1fr, and 3rd fixed of 64px */
    grid-template-columns: 120px minmax(0, 1fr) 64px;
  }
  .grid-rows-1 {
    	/* 1 row track responsive from 0 to 1fr */
    grid-template-rows: repeat(1, minmax(0, 1fr));
  }
  .gap-4 {
    gap: 1rem; /* gap between row and column tracks of 1rem (16px) */
  }
  ```

- **CSS Children**

  ```css
  /**
  * Header: Internal padding
  */
  .py-4 {
    padding-top: 1rem;
    padding-bottom: 1rem;
  }

  /**
  * Button: Size and internal padding
  */
  .w-8 {
    width: 2rem; /* (32px) */
  }
  .h-8 {
    height: 2rem; /* (32px) */
  }
  .p-4 {
    padding: 1rem;
  }
  ```

### Situation 3 - Grid responsive layout

Another quite common situation that I usually find is the grid responsive by nature, that as the screen grows more elements are added to the previous rows, automatically defining the columns.

In this way, when the element of x pixels fits in the previous row it moves up and the next one moves to the position of this one.

If the width of the grid in the image below were larger, item 5 would be part of the first row.

![Situation 3 - Responsive layout made with grid](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6or5tdvfhniskqxfrd1r.jpeg)

In this situation it is even easier to define the grid container, with just *grid-template-columns* we will be able to get that result, but in order to have space between the items we will add the gap property as well:

- **HTML**

  ```html
  <div class="grid grid-cols-[repeat(auto-fit, 150px)] gap-8">
    <article>Item 1</article>
    <article>Item 2</article>
    <article>Item 3</article>
    <article>Item 4</article>
    <article>Item 5</article>
  </div>
  ```

- **CSS**

  ```css
  .grid {
    display: grid;
  }
  .grid-cols-[repeat(auto-fit, 150px)] {
    grid-template-columns: repeat(auto-fit, 150px);
  }
  .gap-8 {
    gap: 2rem; /* (32px) */
  }
  ```

Basically, in this article I intended to have listed what I will need to review in the future when defining a new grid. And a couple of use cases to keep it fresh.

I hope you find it as useful as I did and have a wonderful week full of grids and layout!