The Double Ampersand Mixin

A while back, I wrote about a useful selector for applying margins to columns and buttons. The selector used a double ampersand with an adjacent sibling combinator (&+&).

Here’s the gist of the article: The + combinator targets an element’s immediate sibling, so if we reference adjacent parent selectors with Sass, we can generate helpful layout styles. For example, to create a row where all but the first column have a left margin, we can write the following rule:

.col {
  width: 25%;
  float: left;
  & + & {
    margin-left: 20px;
  }
}

This will output:

.col {
  width: 25%;
  float: left;
}
.col + .col {
  margin-left: 20px;
}

This keeps the first column flush with the left side of the page, while the others get a 20px left margin.

The Mixin

I found myself repeating this “double ampersand selector” several times on projects, so I wrote a simple mixin for it:

@mixin doubly($margin) {
  & + & {
    margin-left: $margin;
    @content;
  }
}

A basic @include looks something like this:

.col {
  @include doubly(20px);
  float: left;
  width: 25%;
}

The mixin also works well with links and button groups. For instance, if a sibling button needs a different background color and a left margin—for separation, we can write the following:

.btn {
  @include doubly(10px) {
    background: firebrick;
  }
  background: dodgerblue;
  ...
}

The adjacent button gets the firebrick background color and 10px left margin:

.btn {
  background: dodgerblue;
  ...
}
.btn + .btn {
  margin-left: 10px;
  background: firebrick;
}

What if we need it for other things?

Sure, we could create further customization by adding other properties, passing more values, control directives, etc. Let’s keeps things simple here by setting the default $margin value to null:

@mixin doubly($margin: null) {
  & + & {
    margin-left: $margin;
    @content;
  }
}

Now we can do other neat things like pass declarations for creating hierarchy in typographic layouts. This rule uses text-indent to differentiate the paragraph above from paragraph below:

p {
  @include doubly() {
    text-indent: 1.5em; 
  }
}

Or, we could also zero out the top margins on all but the first paragraph:

p {
  @include doubly() {
    margin-top: 0; 
    text-indent: 1.5em;
  }
}

I’ve noticed this selector (the CSS version) used on typographic websites like jessicahische.is and trentwalton.com. Kudos goes out to Mattox Shuler for showing me this clever typography use case.

Check out an example on CodePen:

See the Pen jEKpae by Guil H (@Guilh) on CodePen.

comments powered by Disqus