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 like2rem
or16px
- 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 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 matched the growing future of the fluid multi-device world so well.
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 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:
- Simple to use
- As few attributes defined on a single element as possible
- No
:nth-child()
child selectors - Plays nicely with flexbox
- The ability to push/pull columns and to reorder them (as best as floats can handle)
- 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:
- Its base width in percentage, for example a column that is
3
out of a total columns of12
would be25%
- Its own
margin-left
, aka 1$grid-gutter
- 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.
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.
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