Harmony Between CSS Grid and Data Attributes
Tags: css, html, beginners, webdev
Published: 2019-12-04 19:00:42

Building a complex responsive layout with one or two CSS declarations is beyond useful. In fact, CSS Grid has worked like magic for our team of UX Developers at DockYard. The only thing missing was a traditional 12-column grid that could be applied across the app suite we were working on.

I wanted to describe a 12-column grid while retaining our CSS naming methodologies, and I wanted to make sure it didn’t lead to code bloat. I turned to data attributes as a unique solution. The theory was: each column 1 through 12 could be thought of as data, which CSS could then use to make decisions. 

In this post, I will demonstrate how this works, but ultimately, what I found is that this 12-column grid offers a consistent pattern developers can use in their web applications. Doing so brings balance and harmony to the look and feel of the application, and it’s a performance win: the HTML/CSS are reusable and repeatable, and when code is compressed, users will have smaller, faster assets to download.

Currently we can do this work in about 200 lines of CSS, but in the future we could condense this to around 20 lines if data attributes get the ability to pass integers in CSS.

## Overview of Grid Attributes
We use custom data attributes that define a mobile-first grid layout using CSS Grid properties. Our 12-column grid is dependent on these attributes.   Small, medium, or large data attributes define the value of grid columns for small, medium, or large viewports in the web app. We call our grid, `narwin-grid`. 

### narwin-grid Required Classes
* `narwin-grid` is the block-level class name that acts as the container for the items. For example, `<form class=“narwin-grid”>` will apply the grid system to the form.
* `narwin-grid__item` is the element-level class name that belongs on the element that will be sized by the grid. For example, `<fieldset class=“narwin-grid__item”>` without any data attributes will default to a span of 12 columns.

### Optional Data Attributes for narwin-grid Items
The data attributes below are directly associated with `class=“narwin-grid__item”`. The data attributes must be defined on the grid item, as seen in the code snippet below.
* `data-grid-small=“”` takes values 1 through 12. This represents how many columns an element can span across within the grid layout. For example, `data-grid-small=“6”` defines that the item will span 6 columns for small viewports and above.
* `data-grid-medium=“”` takes values 1 through 12. For example, `data-grid-medium=“4”` defines that the item will span 4 columns for medium viewports and above.
* `data-grid-large=“”` takes values 1 through 12. For example, `data-grid-large=“8”` defines that the item will span 8 columns for large viewports.
* `data-grid-item-start=“”` takes values 1 through 12. For example, `data-grid-item-start=“2”` states that the item will start on the second column in the grid, giving the item an offset of 1. `data-grid-item-start=“1”` will move an item to a new row if it is not the first item on an existing row.
* Note: please use caution when using `data-grid-item-start=“”` to ensure that the grid layout does not create implicit columns beyond the desired 12 column layout. For example, using `data-grid-item-start=“8”` in conjunction with `data-grid-large=“8”` will cause 3 implicit columns to be generated (the item occupies columns 7–12, plus 3 implicit columns to accommodate a span of 8 columns, starting at column 7). This will disrupt the grid layout and cause misalignment per CSS Grid spec.

## The Code
The grid systems full code examples are available on CodePen ([narwin-grid](https://codepen.io/team/DockYard/pen/pMrEzB)) as a boilerplate. This boilerplate will allow you to use the grid relative to your project by giving you the flexibility to set up breakpoints, gutters, and naming.

Note: the following code examples use CSS nesting. At DockYard, we use PostCSS to handle the CSS processing to nest CSS.


### CSS:
```scss
/* 12 column grid system */
.narwin-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);

  @media (max-width: 575px) {
    grid-column-gap: 12px;
  }

  @media (min-width: 576px) {
    grid-column-gap: 24px;
  }
}

.narwin-grid__item {
  /* Default layout when [data-grid-small] is not declared */
  &:not([data-grid-small]) {
    grid-column-end: span 12;
  }

  /* Data attributes that control the amount of columns an item will span within the 12 column layout for all viewports */
  &[data-grid-small="1"] {
    grid-column-end: span 1;
  }
  &[data-grid-small="2"] {
    grid-column-end: span 2;
  }
  &[data-grid-small="3"] {
    grid-column-end: span 3;
  }


  /* Data attributes that control the amount of columns an item will span within the 12 column layout for "medium" viewports and up */
  @media (min-width: 576px) {
    &[data-grid-medium="1"] {
      grid-column-end: span 1;
    }
    &[data-grid-medium="2"] {
      grid-column-end: span 2;
    }
    &[data-grid-medium="3"] {
      grid-column-end: span 3;
    }
  }

  /* Data attributes that control the amount of columns an item will span within the 12 column layout for "large" viewports and up */
  @media (min-width: 1024px) {
    &[data-grid-large="1"] {
      grid-column-end: span 1;
    }
    &[data-grid-large="2"] {
      grid-column-end: span 2;
    }
  }

  /* Grid item start values that position elements on the 12 column grid, this is just like setting an offset for grid items */
  &[data-grid-item-start="1"] {
    grid-column-start: 1;
  }
  &[data-grid-item-start="2"] {
    grid-column-start: 2;
  }
  &[data-grid-item-start="3"] {
    grid-column-start: 3;
  }
}


```

### HTML Example:
```html
<form class="narwin-grid">
  <fieldset class="narwin-grid__item" data-grid-small="4" data-grid-medium="4" data-grid-large="6" data-grid-item-start="2">
    ...
  </fieldset>

  <fieldset class="narwin-grid__item" data-grid-small="1" data-grid-medium="7" data-grid-large="5">
    ...
  </fieldset>

  <fieldset class="narwin-grid__item" data-grid-small="3" data-grid-medium="4" data-grid-large="7" data-grid-item-start="1">
    ...
  </fieldset>
</form>
```

![Grid example](https://i.imgur.com/wacmA6l.jpg)
_Visual example of the HTML example above on a medium 930px viewport_

Set up and use your own 12-column grid system with these easy-to-understand data attributes and class names! You won’t need complicated calculations, and there are no negative margins, and you have the added benefit of knowing that it’s built with future proof HTML/CSS specs at it's core.


*This post originally appeared on [DockYard](https://dockyard.com/), where I currently work as a Senior UX Developer. DockYard is a digital product agency offering exceptional strategy, design, full stack engineering, web app development, and custom software services, consulting, and training.*