Now that you have the basics under your belt, in this second tutorial about Neat mixins I’ll dive a little deeper, exploring some other mixins and introducing a function.
We’re going to look at the following:
Over the last couple of years, the importance of flexible designs which respond to the ever-evolving landscape of screen sizes and devices, has been made pretty clear. In this sense, Bourbon Neat has your back, providing you with an elegant approach to manage media queries for your grids. Through the use of clever targeted media queries, your layout can be adapted to a wide range of devices without making a mess. Responsive design is here to stay and a responsible and sustainable use of media queries is king.
Something to avoid is what you might call query spaghetti—a tangled mess of media queries which quickly becomes tricky to maintain. Keeping media queries manageable is of crucial importance. This mixin isn’t a perfect antidote, but it definitly encourages a DRY approach to dealing with media queries sanely—especially when paired with the
new-breakpoint function. How, I hear you ask?
You can write media query blocks which can take grid contexts. Say you have two elements that add up to 12 columns—as defined in
$total-columns within your _grid-settings file. These elements span 3 and 9 columns respectively on desktop size screens, which allow for 1088px wide outer containers. For smaller devices or viewport sizes, allow the
media [query] mixin know at what size the context of 12 columns needs to change to another number and adjust the size for the responsive elements within that new context accordingly. Boom!
.container %aside 3 col / 1 col %article 9 col / 2 col
body color: white background-color: white .container +outer-container background-color: #f5f5f5 aside, article padding: 10px margin-bottom: 20px height: 100px aside +span-columns(3) background-color: #81d4fa +media(max-width 700px, 4) +span-columns(1) article +span-columns(9) background-color: #e64a19 +media(max-width 700px, 4) +span-columns(2)
Here, I provided the
media mixin with a media feature via
max-width 700px and a new grid context of
4 columns for the
max-width of the element. Having established a new grid context for both the
article elements for the viewport size of
700px max, I only needed to tell the elements how many columns they can now span within the new total of
4 columns. Personally, I think this is pretty darn readable and easy to organize. It gets even cooler once you reuse media contexts ( media query / grid context ) via the
new-breakpoint function and save them to a Sass variable.
Note: If you provide this mixin with only a pixel value, without any specific media feature:
.some-responsive-element +span-columns(8) +media(700px) +span-columns(4)
then Neat will use
$default-feature which is
min-width. Also, providing a grid context is optional and defaults to whatever is set through
$total-columns in your _grid-settings partial.
You’re probably wondering what’s up with the DRY approach I mentioned a couple of paragraphs earlier, right? That’s the spirit!
This handy custom Sass function is the Robin to your
media Batman, keeping you from repeating yourself over and over again. If you want to make your media queries a lot more readable and reuseable, I don’t see a good reason why you wouldn’t be using this sidekick to fight media query crimes.
Enough of the Batman analogy. Put simply, all this function does is save media contexts ( media query / grid context ) through variables and give you the opportunity to reuse them in all your
media mixins. That’s one heck of a useful extraction! Let’s take a look.
$tablet: new-breakpoint(min-width 768px max-width 1024px 4) .some-responsive-element +span-columns(3) +media($tablet) +span-columns(1) .some-other-responsive-element +span-columns(9) +media($tablet) +span-columns(2)
Super readable! To be extra sure we’re on the same page: here you provide all the media features you need (but no commas, colons,
and) plus the number of columns for the new grid context, then save it to a Sass variable. All that is left to do is feed your
media mixins with the appropriate variable, and DRY they are.
I hope you’ll appreciate how clean this reads and how easy it is to tweak your layouts for various breakpoints, all in one central place. Gone are the days where managing tons of layout related media queries could quickly get you in a fantasy fist fight with your former self.
I’d like to take a little extra time to explore this one. If you’re not using tables very often in your designs (as you probably shouldn’t since we kissed the days of using tables for layout purposes goodbye) this one can be tricky to jump into right away.
You have two main options for using this mixin: with the argument
table or without any argument.
row without the
table argument, a
clearfix is added and
$display stays set to default, which is
block. Effectively, that means that whatever comes after the designated element using
row needs to start its own thing on a separate “row”.
On the other hand, using
row(table), you guessed it, makes this row part of a table layout. What happens under the hood, among other things, is that this mixin sets
display: table and
There is one more option you can provide this mixin with. You can pass an argument (
RTL) that changes the direction of your layout for that particular row.
.some-row-element +row($direction: RTL)
But let’s start at the beginning. The following dummy example has 16
<img> elements, the first four of which are nested under a
.row container which uses the
row mixin. Let’s see what happens if you leave off the
.container .row %img %img %img %img %img %img %img %img %img %img %img %img %img %img %img %img
.container +outer-container background-color: #f5f5f5 .row +row img +span-columns(1) height: 60px margin-bottom: 5px background-color: #e64a19
As you can see, the browser treats the first four
<img> elements as part of one row, putting the following
<img> elements on a separate row. The elements below the
.row container are not bound to a particular row and just float downwards as long as they have space available to them.
.row containers result in the same trick, stacked on top of each other.
.container .row %img %img %img %img .row %img %img %img %img %img %img %img %img %img %img %img %img
Not too tricky I guess. Although I’m not sure how useful this would be, because instinctively I’d rather use the
omega mixin for such an occasion. What seems pretty useless, however, is using
row(table) here. You’d just get one very long column that stacks all 16 elements above each other. I’ll spare you the nasty screenshot but check out the codepen example if you’re curious.
Using Row Without an Argument on a Table
Thus far I’ve shown you the basic mechanics of this mixin, especially if you are new to the game. Now we’re approaching useful territory. Let’s play with an actual table.
If you haven’t fooled with tables before, I recommend firing up Google before you proceed. Below is a little survival guide for those who need to refresh a couple of terms.
Here we have a
table element. It comprises a
thead tag, which has one row to display the various column headings via the
th tags. Underneath you’ll find the
tbody which houses the actual data for each table row (
tr) via the
.container %table %thead %tr %th Username %th User_ID %th Favorite Pizza %th Pet %th Pet Name %th Favorite Game %tbody %tr %td Joe %td 112233 %td Pepperoni %td Cat %td Gordon %td Splinter Cell %tr %td Jane %td 223311 %td Mushrooms %td Dog %td Fluffy %td Metal Gear Solid V %tr %td Bob %td 331122 %td Onions %td Fish %td Sharky %td Little Big Planet 2
body color: white background-color: white .container +outer-container background-color: darken(#f5f5f5, 50%) tr +row() text-align: center th padding: top: 10px bottom: 20px td height: 50px background: #81d4fa padding-top: 2px
This results in an uneven, nasty table blob, which only spans as far as the content in these table data cells. Obviously not super useful and a pain if you want to manually fix this using a bunch of CSS rules to tidy things up.
There should be a simple solution to this right? Adding
table as an argument and
display: table and
table-layout: fixed come to the rescue! Not to mention a little topping of
fill-parent under the hood.
tr +row(table) text-align: center
Note: A fixed table-layout like this has the advantage of not only laying out the table faster, but the width of the columns is not dependent on the contents of the table cells. You’ll get evenly laid out rows which span the width of the table container. Remove one table data cell (
td) and you’ll see the other elements divide up the space in that row evenly:
Let’s close with an example that shows the default behaviour of tables without using the
row mixin at all.
body color: white background-color: white .container +outer-container background-color: darken(#f5f5f5, 50%) tr text-align: center th padding: top: 10px bottom: 20px td height: 50px background: #81d4fa padding-top: 2px
As you can see, the cells are spaced evenly but don’t use all the appropriated space that is available to them. They orient themselves to the longest content per column and adjust their cells to align themselves along these lines.
Apologies for being overly verbose about
row but I hope this section made any headaches you might have with tables and rows a little less painless.
Moving on, Neat offers an easy solution if you want an element to quickly fill its parent by spanning the same number of columns. You don’t have to provide any arguments. This mixin is nothing fancy, but might come in handy when you deal with media queries or tables.
span-columns(12) instead of
fill-parent to span the whole width of an outer-container would not be the right approach—it would just add unnecessary baggage.
.container %aside Aside 3 columns | fill-parent %article Article 5 columns | fill-parent
body color: white background-color: white .container +outer-container margin-top: 10px background-color: #f5f5f5 aside, article margin-bottom: 5px height: 200px aside +span-columns(3) +fill-parent background-color: #81d4fa article +span-columns(5) +fill-parent background-color: #e64a19
Bear in mind that elements using
fill-parent ignore other elements in the same row, and aim to span the full width of their parent without considering their neighbours. I guess this one is straightforward enough, let’s move on!
Every element in your Neat grid has a
$default-layout-direction which is set to
LTR (left-to-right) in settings/_grid.scss. This means that behind the scenes Neat is always using a
Under the hood, this mixin does nothing other than change the float direction of the applied element. What is neat is that within some directional context, let’s say
left-to-right, you can gather a bunch of grid elements and change their direction to
right-to-left—all at once, under one code block. Again, this solution makes things more compact and readable for yourself, as well as easier to understand for someone who’s not that familiar with a certain project.
.container %aside 3 columns %article 9 columns
body color: white background-color: white .container +outer-container margin-top: 10px background-color: #f5f5f5 aside, article margin-bottom: 5px height: 200px +direction-context(right-to-left) aside +span-columns(3) background-color: #81d4fa article +span-columns(9) background-color: #e64a19
Here’s that same demo without
Here’s another example. Nothing new for now, it’S just that the columns are of equal size and also flow from
.container %aside 3 columns %article 3 columns
body color: white background-color: white .container +outer-container margin-top: 10px background-color: #f5f5f5 aside, article margin-bottom: 5px height: 200px +direction-context(right-to-left) aside +span-columns(3) background-color: #81d4fa article +span-columns(3) background-color: #e64a19
The following little tweak has just one of these three column elements use the mixin, and therefore they float to opposite sides of the container. Nothing too magical, but this might be handy to have in your bag of tricks.
body color: white background-color: white .container +outer-container margin-top: 10px background-color: #f5f5f5 aside, article margin-bottom: 5px height: 200px aside +span-columns(3) background-color: #81d4fa +direction-context(right-to-left) article +span-columns(3) background-color: #e64a19
This last section of the tutorial covers a couple of mixins I wanted to mention for the sake of completeness, but which I personally try to avoid since they haven’t always given me the results I expected. If you have a better experience using them, please let me know. Besides that, three of them are soon to be deprecated:
There’s not much to say about this one. Imagine you’ve changed the layout direction for whatever reason and want to switch back to the
left-to-right)? Here you go, the default context is restored! No argument needed.
.row +row($direction: RTL) .row reset-layout-direction
When might this be useful? Good question! The documentation says mostly when you need to change direction in a single row. I personally wouldn’t bother too much. First of all it’s slated to be deprecated in favor of a
direction mixin, and also it gave me a surprising headache when I wanted to make it work with media queries.
For creating a code block that changes the display properties used by mixins within itself, you have two options you can pass to this mixin:
table. The first one is obvious and
display: table-cell for you.
table-cell forces an element to behave like a
+display-context(table) .some-cell +span-columns(2)
Let’s say you have changed the active display to
table like in the example above,
reset-display helps you easily switch back to
block. It takes no argument either. The documentation says it’s most useful if applied to single rows that have changed their display values.
.row +row(table) .row +reset-display
If you want to combine
reset-layout-direction in one go, that’s what you’ll get with
reset-all—no arguments required. Let’s say on some row you changed the display to
table and the
RTL and want to switch back.
.row +row(table, RTL) .row +reset-all
Well, that was a long one. Thanks for making it through, and I hope you found it to be an interesting journey into Neat mixin territory. There is one more thing to discuss though; namely all the variables that you have at your disposal to tweak the framework for your needs. The next tutorial is a shorter one, but wraps up our coverage of Neat. See you there!