Getting started with Neat 2.0, a lightweight and flexible Sass grid

An illustration of cartoon sushi celebrating
  the release of Neat 2.0 from thoughtbot

Neat 2.0 is all new!! The latest version is more flexible, easier to use, and straightforward to maintain. In this article, I’ll add a bit of context to the main features of the Neat API, beyond the reference docs. Enjoy!

Much style.   very css…   website!     wow    doge

Neat 2.0 in a nutshell

Neat 2.0 utilizes a push left system to position objects within the layout. This system determines the width of a grid object, then uses the calc() property to predict and accommodate for the object’s gutter and the gutter of its siblings. The “push left” comes from the concept that, instead of a column using its margin-right to push the next column away, these columns use margin-left to push themselves away from the row or their preceding children. You can find a more detailed explanation on how this works in “Neat 2.0 Building the future of floated Sass grids.”

The core benefits are:

  • As few attributes defined on a single element as possible
  • No :nth-child() child selectors
  • Works in conjunction with flexbox
  • Has the ability to push/pull columns as well as reorder them

Another important distinction is that, similar to many other grid systems, Neat 2.0 columns have the gutters on the exterior of the object. Basically this means that if you had a series of 12 columns in a 12 column grid, there will be gutters between each of the grid columns as well as gutters to the left of the leftmost column and the right of the rightmost column. This particular attribute is distinct from how the original Neat 1.X grid worked. Overall this means that upgrading an existing site from 1.X to 2.0 is a significant undertaking. It’s also worth noting that if you like the way 1.X works, 1.X (currently at 1.8.0) will continue to be maintained for bug fixes and other issues. Overall 2.0 is a significant improvement in many ways, and I’m super pumped to talk a little bit more about it.

Traditionally grid systems are incredibly difficult to pick up and work with. Neat 2.0 features a diverse set of capabilities while only using seven mixins! The interface for using these mixins has also been standardized across all of them, so that once to get the general idea of how the system works its easy to scale your knowledge to use every feature to it’s fullest extent. The core mixins are as follows:

The mixins of Neat (excluding a few special cases) follow this basic logic

grid-mixin( relevant argument, grid map)

Each mixin name is prefixed with “grid-” and only takes two arguments. The first argument always pertains to this specific mixin. An example of this would be for the grid-column mixin, which is the mixin that creates a grid object, the first argument is how many columns wide the object should be. Alternately the grid-push mixin defines how many columns you want to push your object over.

Neat grid

An illustration of a grid column with a margin-left

The second argument is a grid map. Sass maps are great for storing sets of complex information that can be kept together in a single place. Neat utilizes Sass maps, to store all of the attributes about the grid in a map called $neat-grid. Here’s the default values and what this’ll look like in code.

$neat-grid: (
  columns: 12,
  gutter: 20px,
  direction: ltr,

Let’s run through a few of these and how they affect the grid. columns is a pretty typical attribute. This is the total number columns in full width grid. After that we have the gutter property, which is the space between columns. Because of the way the grid is calculated, Neat 2.0 supports a lot of different options for these gutter values. You can define gutters in pixels (px), percentages (%), ems (em), rems (rem), even more obscure units like viewport width (vw). The last major setting is direction. Neat 2.0 supports both left to right and right left layouts. This means that you can easily switch between text direction depending on the written language of your project. All of the settings of $neat-grid will default to the settings you see above. If you want to change them, you only need to write what you want to change!

$neat-grid: (
  columns: 7,
  direction: rtl,

All the mixins in Neat default to the $neat-grid. If the design of your project needs multiple grid layouts, you can define your own grid maps and pass them directly in to the second argument of the mixin as follows.

$neat-grid: (
  columns: 14,

$my-custom-grid: (
  columns: 3,
  gutter: 3rem,

Grid column

an illustration of 3 grid columns, each with a left margin

The grid-column mixin is the most basic feature of the grid. You can use it to create a grid column on the page. The number you pass in will set how many columns the object spans across the total grid system. Here’s a basic example using the default grid.

SCSS for grid column

.example {
  @include grid-column(8);

CSS Output for grid column

.element {
  width: calc(25% - 25px);
  float: left;
  margin-left: 20px;

Grid container

Next up we have the grid-container mixin. It outputs a straightforward clearfix, which is needed because Neat objects are floated.

SCSS for grid container

.element {
  @include grid-container;

CSS Output for grid container

.element::after {
  clear: both;
  content: "";
  display: block;

Grid Push

An illustration of 2 grid columns,
the right most of which had pushed 1 column over to the right

grid-push is used on objects with grid-column applied to them. Using grid-push will override the margin-left defined by grid-column. column and pushes the grid object left or right by a number of columns. grid-column(3) pushes the grid column to the right. Using grid-column(-4) pulls the grid column 4 columns to the left using negative margin. grid-push is great for making layouts and adding negative space to your designs.

Quick note: I’m using “left” and “right” here but assume the opposite direction if your grid is set to direction: rtl.

SCSS for grid push

.element {
  @include grid-push(3);

CSS Output for grid push

.element {
  margin-left: calc(25% - 25px + 40px);

Grid Shift

An illustration of two columns switching places

Shift behaves similarly to to grid-push allowing columns to be shifted left or right. While grid-push uses margin, grid-shift uses relative positioning to move columns within their container. This makes grid-shift great for reordering columns in your layout, especially when changing layouts from mobile to desktop.

Grid Collapse

An illustration of 2 columns nested inside a larger column

Nested layouts are important for the flexibility of a grid system. When you are putting columns within columns, you often still want to only have one gutter between each object in your grid. You can use grid-collapse to have your container eat the columns on either side of itself. You’ll often want to make these objects grid containers.

.grid-column {
  @include grid-column(3);

.grid-collapse {
  @include grid-collapse();
  @include grid-container();
<div class="grid-column">
  <div class="grid-collapse">
    <div class="grid-column"><div>
    <div class="grid-column"><div>

Grid Media

An illustration of grid columns on a desktop, tablet, and phone

And now… on to the awesome! One recurring issue with many grid systems is different grids at different break points. One example of this might be that you may want one width of gutters on desktop but a different width on mobile. Alternatively, you might want a different amount of columns on one screen size versus another. Historically there was really not a great way to do this within the 1.X. Because of Neat’s use of Sass maps, creating custom grids on various breakpoints is now super simple. Similar to how you define the default $neat-grid, you can also define arbitrary custom grids and assign them a breakpoint. This will look something like the following.

$my-custom-grid: (
  columns: 12,
  gutter: 32px,
  media: 1200px,

The media attribute is used by the grid media mixin to define the local media query. You then pass the map directly in to the media query mixin like this.

@include grid-media($my-custom-grid) {
  .example {
    @include grid-column(2);

When the grid-media mixin is used, the grid you defined and passed in to the mixin replaces the default grid within the scope of the media query. Any other grid mixin that is called within the block, will assume the custom grid’s property.

The media property of the mixin can handle a bunch of different inputs. If you only pass in a united value like 1200px it is assumed that the value is to be assigned as min-width:. Alternatively you can write the full expression of what how the media query is scoped.

$max-width-grid: (
  media: "(max-width: 1200px)",

$small-only-grid: (
  media: "(min-width:10px) and (max-width: 700px)",

$print-only-grid: (
  media: "print",

Getting started

Neat is available in a bunch of different ways. First off, if you are using Ruby on Rails, Middleman, or Jekyll, install Neat using RubyGems. Just add the following to your Gemfile .

gem "neat"

Alternatively, you can install Neat with Bower, Ruby, or npm. You can also use the Neat CLI tool to install Neat in the current directory.

gem install neat
neat install

Next up just import Neat in to your SCSS files by placing the @import in to the top your SCSS file.

@import "neat";

You’re all set from there! If you need more info you can check out the detailed installation instructions in the README or check the documentation on how to get started. Otherwise, you can follow the project on GitHub and follow the team on Twitter.

Sincerely yours,
Will H McMahan

Illustrations by Qian Sun.

Neat 2.0