Level up your Sass with the ampersand

In Sass, the ampersand(&) represents the current selector. Paired with nesting, this allows us to do a variety of things from super simple to when-would-I-ever-actually-do-this complex.

Technically, you can think of the ampersand like a variable that always represents the current selector, or “whatever is before the opening curly brace”. So, wherever you place an &, your current selector will be copy and pasted there in your compiled CSS. If you’re used to using Sass, you probably can’t imagine a world without nesting your CSS rules. Well, the & makes that world so much better. It allows us to make more complex selectors while keeping our relevant code all in the same place.

In a selector like this…

.header {
	// the & is equal to `.header`
}

& pseudo-classes

At it’s simplest, we can use the ampersand to reference pseudo-classes from within our main selectors. This makes, among other things, managing states much easier. For example, we can apply hover and focus states to our links like this:

a {
	&:hover,
	&:focus { 
		text-decoration: underline; 
	}
}

which is compiled to:

a:hover,
a:focus { 
	text-decoration: underline; 
}

Because the ampersand will be replaced with the current selector as it appears in the compiled CSS, the current selector will include any nested parent selectors as well. So, to figure out what the current selector is at any given time, simply go up each nested selector until you reach the first parent. For example:

.footer {
  ul {
  	a {
  		&:hover,
  		&:focus { 
  			text-decoration: underline; 
  		}
  	}
  }
}

will compile to:

.footer ul a:hover, 
.footer ul a:focus {
  text-decoration: underline;
}

& changing parents

The ampersand doesn’t always have to go on the left of a selector. Often, we want to apply styles to elements when they appear in certain contexts, or as children of specific selectors. Normally, you would start a new rule with the relevant parent selector and specify down (i.e. .footer a), or as seen in the example above, nest our current selector within the parent selector rule. This works… but sometimes for organizational purposes, it might make more sense to include that parent selector within your current selector, and with the ampersand you can!

Using our previous example, we could add the ampersand to the right of a selector:

a {
	.footer ul & { 
		color: blue; 
	}
}

which compiles to:

.footer ul a {
  color: blue;
}

& concatenation

Because the ampersand basically copy and pastes your current selector into it’s position, we can even use it to concatenate stuff like class names. This is extremely helpful when following conventions like BEM, that rely on stringing together words into related class names. Take this plain CSS for example:

.block { 
	display: flex; 
}
.block__elem1,
.block__elem2,
.block__elem3 { 
	margin: 1em 0; 
}

Using the ampersand, we can write this much cleaner:

.block {
	display: flex;
    &__elem1,
    &__elem2,
    &__elem3 { 
	    margin: 1em 0; 
	}
}

& caching

As I mentioned before, the ampersand, or current selector, will get resolved based on how deep the selector is nested. So if you’re a few levels deep, the current selector will represent the full compiled CSS of your selector at that given point. Let’s review another example of this happening, using nested styles this time:

.footer {
  ul {
  	a {
  		&.external-link { 
  			// & is equal to `.footer ul a`
  		}
  	}
  }
}

But what if you don’t want that full selector, and only want a portion of it? Sometimes, nesting and using the ampersand can result in over-qualified selectors. To help with this, we can cache the current selector in a variable, to use it again in a deeper nesting level. Before we go into situations where this might be useful, let’s understand how this works using a simple example:

.block {
  $parent: &;
  &__elem1 {
    // $parent is equal to `.block`
  }
}

So now you might be thinking, when would I ever need to do this? The benefit of this feature is most obvious to imagine when following a convention like BEM, or similar. Here is an example of something that I wrote before I learned this trick:

.panel {
  &__image {
    margin-bottom: 1em;
  }
  &--right {
    float: right;
    .panel__image {
      margin-left: 1em;
    }
  }
}

In this example, I want to apply styles to the panel__image when it’s in a panel--right container. To do this, I had to repeat the parent container within my selector. Using the parent selector, I can write it out like this:

.panel {
  $parent: &;
  &__image {
    margin-bottom: 1em;
  }
  &--right {
    float: right;
    #{$parent}__image {
      margin-left: 1em;
    }
  }
}

Both code samples for this example compile to the same CSS. But now, if for any reason I need to change the parent container name, I only need to update it in one place.

.panel__image {
  margin-bottom: 1em;
}
.panel--right {
  float: right;
}
.panel--right .panel__image {
  margin-left: 1em;
}

You can see more examples of using the current selector this way over at CSS Tricks.

##& bonus Now that we understand how the ampersand works, we’re able to keep all relevant code together in one place, and honestly it makes writing Sass much more fun. But with great power comes great responsibility, and with advanced Sass nesting it’s easy to get carried away with your selectors. Being overly-specific causes problems for maintenance, and results in less performant CSS. Caching the current selector can help in some cases where you don’t want to over-qualify your selector, but for organizational purposes it might be nice to group your code together even without a common parent.

@at-root

@at-root is a Sass feature that allows us to ignore our nesting altogether, and write top level selectors any where we want. This helps to keep specificity low because you don’t have to worry about the compiled parent selector when you don’t need it.

.block{
	&__elem {
		@at-root .new-block {
			display: inline-block;
		}
	}
}

would compile to:

.block__elem {
  display: flex;
}
.new-block {
  display: inline-block;
}

Admittedly, there aren’t many use cases for this feature. But it’s a nice one to keep in your back pocket anyway. Below are a few examples taken from various sources that might shed some more light on when we could use this to our advantage.

The first example, taken from Sass Break, uses @at-root and the ampersand to modify a class based on a certain element:

.btn {
    background: #ededed;
    @at-root a#{&} {
        text-decoration: none;
    }
}

which compiles to:

.btn {
  background: #ededed;
}

a.btn {
  text-decoration: none;
}

The next example, taken from Always Twisted, wraps a keyframe animation within the selector that uses it:

.avatar {
  @at-root {
    @keyframes fade {
      0% { opacity: 1; }
      100% { opacity: 0; }
    }
  }
  &:hover {
    animation: fade .8s infinite ease-in alternate;
  }
}

You can also use @at-root to break out of a certain directive, like a media query:

@media print {
  .page {
    width: 8in;
    @at-root (without: media) {
      color: red;
    }
  }
}

which compiles to:

@media screen {
  .page {
    width: 8in;
  }
}
.page {
  color: red;
}

& Resources

Find more Sass features that you may not have heard of in the Sass Docs Try out crazy selectors in your browser automagically using Sassmeister

[ Back to All ]

You can find me online @

LinkedIn / Twitter / Github / Codepen / Dribbble