Neat 2.0 Building the future of floated Sass grids

An illustration of the game snakes and ladders made to look like a grid

Version 2.0 of Neat has been released.

New and improved, this change is a substantial departure from its original attributes and behavior. The result is a simpler, more flexible system that allows you to more rapidly create sites and apps. These changes represent over a year’s worth of work and iteration. We have also updated Neat’s website, and documentation. The following is a breakdown of how grids function across the web and just what makes Neat 2.0 different.

tl;dr

As I have worked on the web, I have always been fascinated with grid systems. While I have used and contributed to quite a few libraries, they have never quite met my needs. More often than not, these libraries behave unpredictably, use things like nth-child selectors, and dump huge amounts of unnecessary code to your project. There are a couple of things at play here however. Mostly when people say “grid system” their actual expectations of what a grid system should handle can vary wildly. On top of this, it’s also important that concept and the execution are two separate things. Some libraries will have a great code quality and technical implementation of a mediocre initial idea while others take good concepts but execute them poorly.

I tend to focus on the idea itself: what makes a grid, what problems is it trying to solve, is it flexible, is it simple, does it help me when I need it and stay out of my way when I don’t.

While I use flexbox to some extent on most of my projects, and I look forward to the implementation of the CSS Grid Layout spec, the fact is that most people still use floats to build the page and create layouts. Also, even as new features are added to CSS, it does not mean that features like float go away, and will likely continue to be valid solutions for particular issues.

That said, most float based grid systems fall in to three main categories:

In thinking about this further, I went down quite the “there has to be a better way” rabbit hole, and in doing so created a new paradigm I think is superior to its predecessors, a calc based Push-left grid. Neat 2.0 uses this new system to achieve dynamic responsive layouts that were not possible with the other three.

It is worth mentioning that liking/disliking a particular grid will always come down to a bit of personal flavor and what your expectations of a grid framework are. That said there are few things any grid framework should shoot for:

  • Low selector specificity and no nth-child selectors
  • Gutters that can be defined in relative values like 2% as well as fixed values like 2rem or 16px
  • A simple and understandable codebase with a limited set of well focused features
  • Generate as little code as possible, maintaining flexibility, while not over restricting objects
  • Coexist seamlessly with flexbox objects and containers
  • Be compatible with both Lib Sass and Ruby Sass

The Half-gutter grid

The earliest CSS grid systems were Percentage-grids and Half-gutter grids. Despite the weird name that I’ve given them, Half-gutter grids are probably the most simple. Like all grids, they start with the number of core variables: gutter width, number of columns.

Half-gutter grids work on the basic principle of gutters being shared between all of the objects in the layout. The parent container or row has an internal horizontal padding. The padding on each side is equal to one half of the gutter width. The system then relies on each column also having horizontal padding equal half of the gutter width, which provides the other half of the full gutter. When two columns come together, each of them provides half of the gutter, to make a whole. Similarly, when one side of the interior column comes in contact with the row, each of them has a half a gutter of padding. This means that you end up with a series of columns and a consistent gutter width between them, including a full gutter on each end.

This system has a lot of benefits. One of the biggest is that it allows you to have a fixed value as a gutter width (1rem) and a relative value for your column width (25%). Due to the way widths are calculated, half-gutter grids end up with nice sensible percentages for their width values, like 25%, 33.333%, etc. This feature makes them a little easier to debug when things go awry. It also allows for complex layouts with multiple columns that can also reflow as needed. Examples of this style of grid can be found in Zurb’s older versions of Foundation as well as early versions of Bootstrap. Although it is a more intricate variant, Susy by Oddbird uses half-gutter grids to handle spacing.

Half gutter GridAn illustration of how half-gutter grid objects interact with their surroundingscontainerpaddingpaddingcontainer

Half-gutter grids do however have one significant limitation. Since they rely on multiple objects interacting with each other to create a single gutter, all the objects in layout have to use the grid system. This means that once a row defined, all it’s direct children need to be columns and that custom layouts and modifications to the standard grid become more and more difficult as the project grows. While this is a bit of a philosophical difference, the end result is that the designer is the one who has to serve the needs of the grid instead of the grid serving and empowering the designer.

The Simple-gutter grid

The Simple-gutter grid is a more simplified variant of a half gutter grid which more closely resembles something that you might create manually. These Simple-gutter grids follow the same tools as above, but don’t bother giving their row objects any padding. That means that the spacing between the first column‘s content and the edge of the row is the width of 1 gutter value but the spacing between 1 column’s content and another column’s is 2 gutters.

At the end of the day, hand writing a system like this might look something as simple as:

$gutter: 1rem;

.col-1 {
  float: left;
  padding: 0 $gutter;
  width: percentage(1/3);
}

.col-2 {
  float: left;
  padding: 0 $gutter;
  width: percentage(2/3);
}

// 🎉 You made a grid!

The Percentage grid

I remember the first Percentage grid I saw. It was on the site for Responsive Grid System and was the coolest thing I’d seen. During the rise of responsive design, Percentage grids grew in popularity since they so well matched the growing future of the fluid multi-device world.

Percentage grids are really based around a single idea. All values are percentages, and unlike half-gutter grids, this includes the gutters. There are actually quite a few examples of this out in the wild, including Neat ~1.0 and many others.

Since the gutters are defined as percentages, row objects are often defined with a percentage value of padding on either side, each equal to one gutter (sometimes this is defined as a margin on either side instead).

column widths are then defined with a calculation that resembles the following:

column number / total columns * 100% - (column number / total columns * gutter)

This means that columns are calculated by determining the number of grid columns that a column object should span, excluding the object’s gutters.

Percentage GridAn illustration of how Percentage grid objects interact with their surroundings:nth-child(n){margin-right:0;}margin-rightcontainer

Percentage grids also tend to have another characteristic. Unlike half-gutter grids, Percentage grids tend to only have gutters between columns and not on either end of the row. While there is no technical necessity for this, it can be seen in Responsive Grid System, Neat, and Profound Grid. This attribute has the side effect of often relying on nth() selectors to make sure that the last column in any row does not have any margin. An example of this is Neat’s omega mixin that removes the right margin.

The Push-left grid

I have consistently struggled with grids never quite fitting my needs. In almost any project, I end up hand writing grid styles for each module. As long as you keep things simple this is rarely an issue. However, it can make a code base more prone to fragmentation as well as making it more difficult to onboard new people to work on the project. Often times a system doesn’t need to solve every problem, but instead present a set of simple and unobtrusive defaults that a developer/designer can choose to use or not depending on they needs.

With that, I worked on developing a system I would be comfortable using on production code, that had a few core values:

  1. Simple to use
  2. As few attributes defined on a single element as possible
  3. No :nth-child() child selectors
  4. Plays nicely with flexbox
  5. The ability to push/pull columns and to reorder them (as best as floats can handle)
  6. Seriously… it need to be like stupid simple to use

This lead me to Push-left grids. The basic principle is that you use calc() to determine exactly how wide a grid object should be, and then use this calculation to predict and accommodate for the object’s gutter and the gutter of its siblings. The “push left” comes from the idea that instead of a column using its margin-right to push the following column away, these columns use margin-left to push themselves away from the row or their preceding siblings. This all works thanks to this rather complicated equation.

width: calc(percentage($columns / $grid-columns) - $grid-gutter + ($grid-gutter * percentage($columns / $grid-columns)));

Basically what is happening is that each column is responsible for handling a few items:

  1. Its base width in percentage, for example a column that is 3 out of a total columns of 12 would be 25%
  2. Its own margin-left, aka 1 $grid-gutter
  3. Its share of the extra gutter.

A basic grid will always have 1 extra gutter as compared to the total number of columns: A 4 column grid will have 5 gutters, a 6 column grid will have 7 gutters, a classic 12 column grid will have 13 gutters, and so on. This means that each column has to accommodate space for its own gutter as well as its share of the extra gutter, which is directly relational to its base width percentage. This means that a 6/12 column will have to accommodate for 1 and a half gutters, the 1 being its gutter and the half being it’s share of the extra gutter.

Push-left GridAn illustration of how Push-left grid objects interact with their surroundingsemptyspacecontainermargin-left

This means that the space left over after all the columns in a row have been filled is exactly 1 gutter. The extra nice thing about this is that if one browser choses to round differently, it wont break the layout because the final column is empty space. It is nearly impossible to break layout and have a column pop down to the next row when it wasn’t supposed to (I’m sure this has happened to everyone, haha).

Simplicity

A tool like this has some complicated math. Using calc() in Sass is not the easiest thing in the world. However, this is what makes it great territory for a framework. The complexities of a particular calculation can be abstracted away from the user, allowing them to focus on taking their vision to the digital page. Ultimately there are only a few limited features that should be in a grid framework: push/pull items away or toward each other, relative position reordering or “shifting” for use on responsive layouts, integration with media queries for dynamic responsive grids, and an api that is flexible and easy to use.

As few attributes defined and lowest specificity as possible

This may be the single best feature of a Push-left grid. Grids will always have a bit of complexity. Fortunately for a system like this, all the complexity is hidden within a single easily overridden attribute, width. Other than the width definition, the only required attributes are float: left and margin-left: $grid-gutter which are the same for every element within the system.

Since their is no “you are the last column, make sure you don’t have a margin” issue there is also no need for :nth() selectors at all. This also means that when you change column counts based on screen size, their is nothing to reset via overrides.

Play nicely with Flexbox

There are so few definitions within a push-left system, its easy for a column in a system like this to have flexbox siblings, parents, children, and to even become a flexbox object itself! If you were to have two columns that were predefined with a 4 of 12 column width, and flex was applied to the parent, the object’s behavior would not even change, but would then allow you to use flex attributes to further manipulate the objects within.

Neat v2.0.0

Neat v2.0.0 is an Sass based Push-left grid system that uses these concepts and builds upon them to create a solid scalable grid framework. It is built on clever tactics and the learnings of its predecessors to create simple grids that are flexible enough for any project.

Logos for Rubygems, NPM, and Bower

A grid will never solve every use case and probably shouldn’t, but the most important thing is to create a concise and understandable system that empowers the user to write awesome code and create amazing designs without getting in the way. Ultimately, it is the job of the grid to serve the designer/developer and not the other way around. If you have sat looking at the css that some grid system spit out and thought “What the hell is going on here”, you should probably try the new Neat 2.0. 😘

Thank you to everyone who has contributed to Neat, as it continues to evolve, grow, and thrive in a vibrant community of designers and developers.

Sincerely yours,
Will H McMahan