1. Web Design
  2. UX/UI

Taking Bourbon Neat Mixins to the Next Level

Scroll to top
12 min read
This post is part of a series called Bourbon: the Connoisseurs’ Choice for Sass Mixins.
6 Essential Bourbon Neat Mixins
A Rundown of Bourbon Neat Variables

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.

filefilefile

We’re going to look at the following:

Function

  • new-breakpoint

Mixins

  • reset-layout-direction
  • direction-context
  • display-context
  • reset-display
  • fill-parent
  • reset-all
  • media
  • row

media

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!

Haml:

1
2
.container
3
  %aside 3 col / 1 col
4
  %article 9 col / 2 col

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  background-color: #f5f5f5
9
10
aside, article
11
  padding: 10px
12
  margin-bottom: 20px
13
  height: 100px
14
15
aside
16
  +span-columns(3)
17
  background-color: #81d4fa 
18
  +media(max-width 700px, 4)
19
    +span-columns(1)
20
21
article
22
  +span-columns(9)
23
  background-color: #e64a19
24
  +media(max-width 700px, 4)
25
    +span-columns(2)
Please accept marketing cookies to load this content.

Here, I provided the media mixin with a media feature via max-width 700px and a new grid context of 4 columns for the $total-columns max-width of the element. Having established a new grid context for both the aside and 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:

Sass:

1
2
.some-responsive-element
3
  +span-columns(8)
4
  +media(700px)
5
    +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.

new-breakpoint

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.

Sass:

1
2
$tablet: new-breakpoint(min-width 768px max-width 1024px 4)
3
4
.some-responsive-element
5
  +span-columns(3)
6
  +media($tablet)
7
    +span-columns(1)
8
9
.some-other-responsive-element
10
  +span-columns(9)
11
  +media($tablet)
12
    +span-columns(2)
Please accept marketing cookies to load this content.

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, or, 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.

row

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.

Basics

You have two main options for using this mixin: with the argument table or without any argument.

Sass:

1
2
.some-row-element
3
  +row

When using 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”.

Sass:

1
2
.some-table-row-element
3
  +row(table)

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 table-layout: fixed.

There is one more option you can provide this mixin with. You can pass an argument ($direction with LTR or RTL) that changes the direction of your layout for that particular row.

Sass:

1
2
.some-row-element
3
  +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 table argument.

Haml:

1
2
.container
3
4
  .row
5
    %img
6
    %img
7
    %img
8
    %img
9
  
10
  %img
11
  %img
12
  %img
13
  %img
14
  
15
  %img
16
  %img
17
  %img
18
  %img
19
  
20
  %img
21
  %img
22
  %img
23
  %img

Sass:

1
2
.container
3
  +outer-container
4
  background-color: #f5f5f5
5
6
.row
7
  +row
8
9
img
10
  +span-columns(1)
11
  height: 60px
12
  margin-bottom: 5px
13
  background-color: #e64a19
Please accept marketing cookies to load this content.

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.

Two .row containers result in the same trick, stacked on top of each other.

Haml:

1
2
.container
3
4
  .row
5
    %img
6
    %img
7
    %img
8
    %img
9
  
10
  .row
11
    %img
12
    %img
13
    %img
14
    %img
15
  
16
  %img
17
  %img
18
  %img
19
  %img
20
  
21
  %img
22
  %img
23
  %img
24
  %img
Please accept marketing cookies to load this content.

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 td tags.

Haml:

1
2
.container
3
4
  %table
5
  
6
    %thead
7
      %tr
8
        %th Username
9
        %th User_ID
10
        %th Favorite Pizza
11
        %th Pet
12
        %th Pet Name
13
        %th Favorite Game
14
    
15
    %tbody
16
      %tr
17
        %td Joe
18
        %td 112233
19
        %td Pepperoni
20
        %td Cat
21
        %td Gordon
22
        %td Splinter Cell
23
      %tr
24
        %td Jane
25
        %td 223311
26
        %td Mushrooms
27
        %td Dog
28
        %td Fluffy
29
        %td Metal Gear Solid V
30
      %tr
31
        %td Bob
32
        %td 331122
33
        %td Onions
34
        %td Fish
35
        %td Sharky
36
        %td Little Big Planet 2

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  background-color: darken(#f5f5f5, 50%)
9
10
tr
11
  +row()
12
  text-align: center
13
  
14
th
15
  padding:
16
    top: 10px
17
    bottom: 20px
18
  
19
td
20
  height: 50px
21
  background: #81d4fa
22
  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.

Please accept marketing cookies to load this content.

Using row(table)

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.

Sass:

1
2
tr
3
  +row(table)
4
  text-align: center
Please accept marketing cookies to load this content.

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:

Please accept marketing cookies to load this content.

Without row

Let’s close with an example that shows the default behaviour of tables without using the row mixin at all.

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  background-color: darken(#f5f5f5, 50%)
9
10
tr
11
  text-align: center
12
  
13
th
14
  padding:
15
    top: 10px
16
    bottom: 20px
17
  
18
td
19
  height: 50px
20
  background: #81d4fa
21
  padding-top: 2px
Please accept marketing cookies to load this content.

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.

fill-parent

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.

Note: Using 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.

Haml:

1
2
.container
3
  %aside Aside 3 columns | fill-parent
4
  %article Article 5 columns | fill-parent

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  margin-top: 10px
9
  background-color: #f5f5f5
10
11
aside, article
12
  margin-bottom: 5px
13
  height: 200px  
14
15
aside
16
  +span-columns(3)
17
  +fill-parent
18
  background-color: #81d4fa 
19
20
article
21
  +span-columns(5)
22
  +fill-parent
23
  background-color: #e64a19
Please accept marketing cookies to load this content.

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!

direction-context

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 direction-context with left-to-right.

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.

Haml:

1
2
.container
3
  %aside 3 columns
4
  %article 9 columns

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  margin-top: 10px
9
  background-color: #f5f5f5
10
11
aside, article
12
  margin-bottom: 5px
13
  height: 200px  
14
15
+direction-context(right-to-left)
16
  aside
17
    +span-columns(3)
18
    background-color: #81d4fa
19
20
  article
21
    +span-columns(9)
22
    background-color: #e64a19
Please accept marketing cookies to load this content.

Here’s that same demo without direction-context:

Please accept marketing cookies to load this content.

Here’s another example. Nothing new for now, it’S just that the columns are of equal size and also flow from right-to-left.

Haml:

1
2
.container
3
  %aside 3 columns
4
  %article 3 columns

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  margin-top: 10px
9
  background-color: #f5f5f5
10
11
aside, article
12
  margin-bottom: 5px
13
  height: 200px  
14
15
+direction-context(right-to-left)
16
  aside
17
    +span-columns(3)
18
    background-color: #81d4fa
19
20
  article
21
    +span-columns(3)
22
    background-color: #e64a19
Please accept marketing cookies to load this content.

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.

Sass:

1
2
body
3
  color: white
4
  background-color: white
5
6
.container
7
  +outer-container
8
  margin-top: 10px
9
  background-color: #f5f5f5
10
11
aside, article
12
  margin-bottom: 5px
13
  height: 200px  
14
15
  
16
aside
17
  +span-columns(3)
18
  background-color: #81d4fa
19
  
20
+direction-context(right-to-left)
21
  article
22
    +span-columns(3)
23
    background-color: #e64a19
Please accept marketing cookies to load this content.

Last Mile

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:

  • reset-display
  • reset-layout-direction
  • reset-all

reset-layout-direction

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 $default-layout-direction (left-to-right)? Here you go, the default context is restored! No argument needed.

Sass:

1
2
.row
3
  +row($direction: RTL)
4
5
.row 
6
  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.

display-context

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: block and table. The first one is obvious and table adds display: table-cell for you. table-cell forces an element to behave like a td element.

Sass:

1
2
+display-context(table)
3
  .some-cell
4
    +span-columns(2)

reset-display

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.

Sass:

1
2
.row
3
  +row(table)
4
  
5
.row 
6
  +reset-display

reset-all

If you want to combine reset-display and 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 $default-layout-direction to RTL and want to switch back.

Sass:

1
2
.row
3
  +row(table, RTL)
4
  
5
.row 
6
  +reset-all

Final Thoughts

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!