nesting – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Wed, 21 Dec 2022 18:17:28 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 nesting – CSS-Tricks https://css-tricks.com 32 32 45537868 Help choose the syntax for CSS Nesting https://css-tricks.com/help-choose-the-syntax-for-css-nesting/ https://css-tricks.com/help-choose-the-syntax-for-css-nesting/#comments Tue, 20 Dec 2022 16:04:54 +0000 https://css-tricks.com/?p=376319 CSS Nesting is making the rounds yet again. Remember earlier this year when Adam and Miriam put three syntax options up for a vote? Those results were tallied and it wasn’t even even close.

Now there’s another chance …


Help choose the syntax for CSS Nesting originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
CSS Nesting is making the rounds yet again. Remember earlier this year when Adam and Miriam put three syntax options up for a vote? Those results were tallied and it wasn’t even even close.

Now there’s another chance to speak into the future of nesting, this time over at the WebKit blog. The results from the Adam and Miriam’s survey sparked further discussion and two more ideas were added to the mix. This new survey lets you choose from all five options.

Jen Simmons has put together a thorough outline of those options, including a refresher on nesting, details on how we arrived at the five options, and tons of examples that show the options in various use cases. Let’s return the favor of all the hard work that’s being done here by taking this quick one-question survey.

To Shared LinkPermalink on CSS-Tricks


Help choose the syntax for CSS Nesting originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/help-choose-the-syntax-for-css-nesting/feed/ 7 376319
CSS Nesting, specificity, and you https://css-tricks.com/css-nesting-specificity-and-you/ https://css-tricks.com/css-nesting-specificity-and-you/#comments Tue, 10 Aug 2021 14:51:39 +0000 https://css-tricks.com/?p=346355 Here’s Kilian Valkhof on CSS nesting which isn’t available in browsers yet, but will be soon. There are a few differences he notes between CSS nesting and nesting in Sass or Less though. Take, for example, the following code:

div 


CSS Nesting, specificity, and you originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Here’s Kilian Valkhof on CSS nesting which isn’t available in browsers yet, but will be soon. There are a few differences he notes between CSS nesting and nesting in Sass or Less though. Take, for example, the following code:

div {
  background: #fff;
  & p {
    color: red;
  }
  border: 1px solid;
}

When CSS nesting lands, that last line border: 1px solid; won’t be applied to the div like it would be in, say, Sass. That’s because with CSS nesting, any styles you want applied to that div have to be written before any nesting styles are written. I think this makes a ton of sense because I tend to enforce that style in any Sass codebases I work on (it’s just much easier to read), but I can imagine people getting confused about this the first time around.

One of the smaller and, yet for some reason, super exciting things about CSS nesting is how we’ll be able to nest media queries, as Kilian notes, just like this:

body {
  background: red;
  
  @media (min-width: 40rem) {
    & {
      background: blue;
    }
  }
}

This is very exciting!

To Shared LinkPermalink on CSS-Tricks


CSS Nesting, specificity, and you originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-nesting-specificity-and-you/feed/ 2 346355
Nested Media Queries https://css-tricks.com/nested-media-queries/ https://css-tricks.com/nested-media-queries/#comments Tue, 09 Feb 2021 20:34:45 +0000 https://css-tricks.com/?p=334168 We don’t have “regular” nesting in CSS. Maybe this becomes a thing someday, or something like it. That would be cool, although that pre-spec doesn’t mention anything about media queries. I’d hope we get that right out of the gate …


Nested Media Queries originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
We don’t have “regular” nesting in CSS. Maybe this becomes a thing someday, or something like it. That would be cool, although that pre-spec doesn’t mention anything about media queries. I’d hope we get that right out of the gate if we ever do get native CSS nesting. In fact, I’d trade it for selector nesting in a heartbeat. I’d say that’s the most useful thing a CSS preprocessor like Sass does today.

But I’ve digressed before I even began. You can nest media queries in native CSS, as long as you’re doing it from the root. It’s funny to see in native CSS, but it works!

@media screen {
  @media (min-width: 1px) {
    @media (min-height: 1px) {
      @media (max-width: 9999px) {
        @media (max-height: 9999px) {
          body {
            background: red;
          }
        }
      }
    }
  }
}

To Shared LinkPermalink on CSS-Tricks


Nested Media Queries originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/nested-media-queries/feed/ 2 334168
Can you nest @media and @support queries? https://css-tricks.com/can-you-nest-media-and-support-queries/ https://css-tricks.com/can-you-nest-media-and-support-queries/#comments Mon, 05 Aug 2019 14:50:22 +0000 https://css-tricks.com/?p=293607 Yes, you can, and it doesn’t really matter in what order. A CSS preprocessor is not required. It works in regular CSS.

This works:

@supports(--a: b) {
  @media (min-width: 1px) {
    body {
      background: red;
    }
  }
}

And so …


Can you nest @media and @support queries? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Yes, you can, and it doesn’t really matter in what order. A CSS preprocessor is not required. It works in regular CSS.

This works:

@supports(--a: b) {
  @media (min-width: 1px) {
    body {
      background: red;
    }
  }
}

And so does this, the reverse nesting of the above:

@media (min-width: 1px) {
  @supports(--a: b) {
    body {
      background: green;
    }
  }
}

You can keep going with the nesting, if it ever makes sense:

@media (min-width: 2px) {
  @media (min-width: 1px) {
    @supports (--a: b) {
      @supports (display: flex) {
        body {
          background: pink;
        }
      }
    }
  }
}

There is probably a point where the logic of that gets out of hand, so careful. But hey, it works. Presumably, you can “infinitely” nest at-rules.

To look at nested code like that looks a little like a CSS preprocessor is in use, but that’s not the case here. Regular ol’ CSS handles this just fine, and in fact, CSS preprocessors don’t meaningfully manipulate it at all (tested Sass, Less, and Stylus).


Can you nest @media and @support queries? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/can-you-nest-media-and-support-queries/feed/ 2 293607
Where Do You Nest Your Sass Breakpoints? https://css-tricks.com/where-do-you-nest-your-sass-breakpoints/ https://css-tricks.com/where-do-you-nest-your-sass-breakpoints/#comments Mon, 11 Feb 2019 15:16:48 +0000 http://css-tricks.com/?p=282174 I love nesting my @media query breakpoints. It’s perhaps the most important feature of Sass to me. Maybe I pick a method and do it like this:

.element {
  display: grid;
  grid-template-columns: 100px 1fr;
  @include breakpoint(baby-bear) {
    display: block;
  }


Where Do You Nest Your Sass Breakpoints? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I love nesting my @media query breakpoints. It’s perhaps the most important feature of Sass to me. Maybe I pick a method and do it like this:

.element {
  display: grid;
  grid-template-columns: 100px 1fr;
  @include breakpoint(baby-bear) {
    display: block;
  }
}

That’s straightforward enough. But what if my element has several sub-elements and the breakpoint affects them as well? There are different approaches, and I’m never quite sure which one I should be doing.

I could duplicate the breakpoint for each child:

.parent {

    @include breakpoint(desktop) {
    }

    .child {
        @include breakpoint(desktop) {
        }
    }

   .child-2 {
        @include breakpoint(desktop) {
        }
    }

}

The compiled CSS comes out to something like this:

@media screen and (min-width: 700px) {
  .parent {
  }
}
@media screen and (min-width: 700px) {
  .parent .child {
  }
}
@media screen and (min-width: 700px) {
  .parent .child-2 {
  }
}

Or, I could duplicate the children under the first nested breakpoint:

.parent {

    @include breakpoint(desktop) {

       .child {
       }

       .child-2 {
       } 

    }

    .child {
    }

   .child-2 {
    }

}

That results in:

@media screen and (min-width: 700px) {
  .parent .child {
  }
  .parent .child-2 {
  }
}
.parent .child {
}
.parent .child-2 {
}

Or I could do a combination of the two. Neither of them feels particularly great because of the duplication, but I’m not sure there is a perfect answer here. I err a little more on duplicating the media query, as it seems less error-prone than duplicating selectors.


Where Do You Nest Your Sass Breakpoints? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/where-do-you-nest-your-sass-breakpoints/feed/ 40 282174
Sass Selector Combining https://css-tricks.com/sass-selector-combining/ Mon, 15 Oct 2018 23:56:21 +0000 http://css-tricks.com/?p=277311 Brad Frost was asking about this the other day…

.c-btn {
  &__icon {
      ...
  }
}

I guess that’s technically “nesting” but …


Sass Selector Combining originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Brad Frost was asking about this the other day…

.c-btn {
  &__icon {
      ...
  }
}

I guess that’s technically “nesting” but the selectors come out flat:

.c-button__icon { }

The question was whether you do that or just write out the whole selector instead, as you would with vanilla CSS. Brad’s post gets into all the pro’s and con’s of both ways.

To me, I’m firmly in the camp of not “nesting” because it makes searching for selectors so much harder. I absolutely live by being able to search my project for fully expanded class names and, ironically, just as Brad was posting that poll, I was stumped by a combined class like this and changed it in one of my own code bases.

Robin Rendle also notes the difficulty in searching as an issue with an example that has clearly gone too far!

To Shared LinkPermalink on CSS-Tricks


Sass Selector Combining originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
277311
inStyle (Modifying the Current Selector `&` in Sass) https://css-tricks.com/instyle-current-selector-sass/ https://css-tricks.com/instyle-current-selector-sass/#comments Fri, 27 May 2016 13:06:17 +0000 http://css-tricks.com/?p=242174 The following is a guest post by Filip Naumovic from Salsita Software. Filip has built a Sass tool to help with an issue I know I’ve experienced many times. You’re happily nesting in Sass. You’re maybe a level or


inStyle (Modifying the Current Selector `&` in Sass) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The following is a guest post by Filip Naumovic from Salsita Software. Filip has built a Sass tool to help with an issue I know I’ve experienced many times. You’re happily nesting in Sass. You’re maybe a level or two deep, and you need to style a variation based on some parent selector. You need to either break out of the nesting and start a new nesting context, or go nuclear with @at-root. I’ll let Filip tell the story of his new tool that changes that.

Sass has helped a lot of us tremendously with cleaning up our CSS code bases. When it arrived on the scene, some extremely useful patterns emerged and got quickly adopted.

For example, the usage of & and nesting allowed for the cleaning up of otherwise rather gross code blocks.

This:

.my-app { display: block; }
.my-app .widget { border-radius: 5px; }
.my-app .widget.blue { color: blue; }
.isIE6 .my-app .widget { background-image: url('fake-borders.png'); }
@media (max-width: 768px) { .my-app .widget { float: left; } }

Turned into this:

.my-app {
  display: block;
  .widget {
    border-radius: 5px;
    &.blue {
      color: blue;
    }
    .isIE6 & {
      background-image: url("fake-borders.png");
    }
    @media (max-width: 768px) {
      float: left;
    }
  }
}

What a positive change for our sanity!

All style variations of the .widget element are clearly nested below itself, using indentation as both a visual cue for relevancy and a query generator.

The current selector (&), in this case, provides a shortcut for the most common patterns. Styling the variation of an element that is invoked either by a property of the element itself or a prepending parent state.

Nested media queries are a younger addition, but they hint that evolution towards indented syntax for styles comes almost naturally. It’s easy to read and navigate, because it somehow mirrors the familiar DOM structure and keeps all styles for an element in one place, while still producing our precious, yet sometimes complicated, selectors.

Today, nesting and current selector features are present in Less, Sass, and Stylus. With a bit of wine, one could almost call it a standard.

A classic case of “You can’t do that.”

Using the above code block as an example, let’s add styles for .my-app.expanded .widget.

Despite our mighty tools, we quickly find ourselves with limited choices:

Option 1

Using the modern @at-root directive (or / in Stylus), we leave the current scope entirely and repeat the full root query to keep the relevant new styles nested below .widget, because the current selector can’t help us express this relationship.

.my-app {
  display: block;
  .widget {
    border-radius: 5px;
    &.blue {
      color: blue;
    }
    .isIE6 & {
      background-image: url("fake-borders.png");
    }
    // repeating the root selector here
    @at-root .my-app.expanded .widget {
      color: red'
    }
    @media (max-width: 768px) {
      float: left;
    }
  }
}

This creates harder to read code with a lot of duplicity, especially when real world usage extends way over our small example piece. But, it keeps our glorious nesting paradigm intact.

Option 2

We create a new code block below .my-app and use it to change all child elements relevant to the .expanded state. This means that our .widget is now styled in different places, and this separation grows for every added state in each element in the nest.

.my-app {
  display: block;
  .widget {
    border-radius: 5px;
    &.blue {
      color: blue;
    }
    .isIE6 & {
      background-image: url("fake-borders.png");
    }
    @media (max-width: 768px) {
      float: left;
    }
  }
  &.expanded .widget
     color: red;
  }
}

While it is in direct violation of our “nesting all relevant styles” dream, it’s the imperfection we learned to live with. Many of you would probably even defend this pattern, because it has been the way things are done for quite a while.

However, for the sake of choice, wouldn’t it be great to have an Option 3? One that would allow us to express the simple change in .my-app.expanded that influences our .widget without having to escape the context?

This idea has been secretly bothering me for quite a while, if only out of some form of OCD about my own stylesheets. I’ve made it my sidequest to try and find this missing tool in the style shed.

Finding Option 3

While digging around the topic, I’ve found spider webs, eternal discussions, and wildly varying propositions, many of which suggested adding some special syntax to the current selector character &. Doing that would mean months of learning complicated core libraries and fighting the long war, which instantly felt like an unacceptable burden.

Secondly, I think & works well because it’s a clear representation of the whole context, and for that reason it might be problematic adding more features to it. It does one thing and does it well, so creating a good partner to it seemed like a better idea at this time.

For sake of easy integration, I’ve decided to implement the idea on the level of preprocessor language, so you could just @import and use it right away. Preprocessors are powerful frameworks nowadays, so why not?

My first choice was Stylus, because it’s just so awesome. Unfortunately, due to issue 1703, the current selector placeholder cannot be modified inside a mixin function as of right now. Like a good zealot I’ll wait until the end of time for Stylus to fix it, but I had to keep searching for something I could implement now.

You shall not parse the current selector, as I’ve learned, in Less, so that was out.

SassScript on the other hand proved to be a powerhouse. While it is missing many useful abstractions for manipulation with strings and arrays, it is very possible to craft such functions manually. Many of them are already provided by Sass Prince Kitty Giraudel.

After months of controlled string terror…

inStyle for Sass 3.4+ is born!

Cheesy name, I know. But it’s suggestive of the functionality, because you want this thing readable in the actual code. Mixin syntax is already familiar with preprocessor users, so having a suggestive name for describing changes in element parents sounded right to me as an added bumper against unfamiliarity.

Either way, all of it has to stay readable while handling complex cases, otherwise it loses purpose in favor of @at-root selector approaches or just nesting the code elsewhere. I decided to go with two basic mechanisms that I believe address even the most despicable needs, while keeping a logically simple parsing algorithm:

Use 1) Modification

Additions to a compound element present in the current selector proved to handle ~80% of real world code, just like our first example tries to achieve.

.my-app {
  display: block;
  .widget {
    border-radius: 5px;
    &.blue {
      color: blue;
    }
    .isIE6 & {
      background-image: url("fake-borders.png");
    }
    @include in(".my-app.expanded") {
      color: red; // .my-app.expanded .widget { };
    }
    @media (max-width: 768px) {
      float: left;
    }
  }
}

Try to read that like this:

styling .widget in the .my-app.expanded state.

The function searches the nest bottom to top for the first occurrence of .my-app element (skipping current element) and appends the class .expanded to it, returning a new selector.

What about longer queries and combo modifications?

table {
  table-layout: fixed;
  thead {
    font-weight: normal;
    tr {
      height: 30px;
      td {
        background-color: #fafafa;
        &.user {
          font-weight: bold'
        }
        @include in('table.one tr.two:hover') {
          background-image: url(rainbow.png) // table.one thead tr.two:hover td { };
        }
      }
    }
  }
}

The tr parent is found and modified with .two:hover. Going upwards, table is also found and modified with .one, other elements are skipped.

Irrelevant multi-selectors are removed from the new selector:

ul, ol {
  list-style: none;
  li {
    display: inline-block;
    a {
      text-decoration: underline;
      @include in("ol.links") {
        color: orange; // ol.links li a { };
      }
    }
  }
}

Impossible cases and invalid CSS queries produce a blocking Sass error on compilation:

table {
  table-layout: fixed;
  td {
    height: 30px;
    @include in("table^s&()#") {
      what: the; // ERROR, invalid CSS
    }
    @include in ("tr.green:hover") {
      border-color: green; // ERROR, no tr or tr.green to modify in &
    }
  }
}

While crash testing this in production (hah!), I found another very practical need that I couldn’t satisfy with modifications of the parent tree only. In fact, it solves the example above, because you have to be able to do just that with tr.green:hover. You just have to be able to say where.

Use 2) Insertion

Let’s assume the following:

table {
  table-layout: fixed;
  thead {
    font-weight: normal;
  }
  tr {
    height: 30px;
  }
  td {
    background-color: #fafafa;
  }
}

Where would you ideally nest a table thead tr selector? By the dogma, you seemingly have to add it as follows:

table {
  table-layout: fixed;
  thead {
    font-weight: normal;
    tr {
      height: 50px;
    }
  tr {
    height: 30px;
  }
  td {
    background-color: #fafafa;
  }
}

However, the styled element in question is tr and you already have that as a generic style, so theoretically, nesting it below itself as a variant might be closer to how you think about the relationship, filling the gaps that current selector & cannot describe.

In this case, it means there has to be a simple way to insert some selector at a certain position above the current element while also allowing combinations with compound modifications. I couldn’t imagine this without adding a special character, so I went with the visually suggestive ^ caret.

table {
  table-layout: fixed;
  thead {
    font-weight: normal;
  }
  tr {
    height: 30px;
    @include in("^thead") {
      height: 50px; // table thead tr { };
    }
  }
  td {
    background-color: #fafafa;
    @include in("table.blue-skin ^tbody") {
      background-color: blue; // table.blue-skin tbody td { };
    }
  }
}

In this case, the caret is inserting thead one level above current or last modified element. More carets mean higher jumps in the current selector:

main {
  display: flex;
  > div {
    flex-grow: 1;
    span {
      display: inline-block;
      &.highlight {
        outline-style: dashed;
        @include in("^^.section.active") {
          outline-style: solid; // main .section.active > div span.highlight { };
        }
        @include in("^^^.section") {
          some: thing; // ERROR, inserting too high, it would equal to ".section &"
        }
      }
    }
  }
}

Note: &.highlight is the same element as span, so the insertion treats it as one step in the nest

I think inStyle shines in the simplest cases, which are also by far the most common. But things can get more complex if needed.

Use 3) Advanced combinations

The matching algorithm allows you to go even wilder with inserting in or modifying more compounds at once:

.my-app {
  display: flex;
  section {
    flex: 1;    
    header {
      width: 100%;
      @include in("^^.wrapper ^.dialog)") {
        height: 50px; // .my-app .wrapper section .dialog header { };
      }
      @include in("^.overlay ^.sidebar") {
        position: fixed; // .my-app section .overlay .sidebar header { };
      }
      @include in("^.modifier section.next ^.parent") {
        opacity: 0; // .my-app .modifier section.next .parent header { };
      }
    }
  }
}
  1. .dialog is inserted one level above header and .wrapper is inserted two levels.
  2. .sidebar is inserted above header and .overlay directly above it.
  3. Pushes .parent above header, modifies section with .next and then pushes .modifier above it.

This reminds me, perhaps you have some feedback! I’ve been thinking about enabling some simpler syntax when you want to insert more compound elements directly after each other as in the second case, perhaps something like @include in("^(.overlay .sidebar)") or improve the parser and enable more natural @include in("^.overlay .sidebar"). Let me know your opinion!

After using it for a while, I’ve found that most of my inconvenient code patterns are solved rather easily by just changing one element here and there or pushing a new selector at a certain position and keep things in place. Still, I need to be honest, it is potentially quite invasive to your usual code organization by nature of the idea.

I can see how using inStyle might bring on heated arguments. My colleagues seem to be either open minded or don’t care, which is both great.

If you use it, I would hope that the correct handling would be like with any other tool: when it’s fit for the job. Spamming complex nested mixins will unlikely score high on readability than flat out writing the full query, but on the other hand it can simplify most real world problems while keeping a slim footprint.

In the near future, I’d like to get the Stylus port working and perhaps create an Atom editor plugin to display the resulting query as a hint in the code.

It was fun taking a shot at solving the first-world problems of CSS and it is my hope that you consider the subject at least worthy of a discussion. The project is open source, so feel free to get onboard with either code or feedback!

Love it or hate it, here it is on GitHub, here’s a little microsite and here’s a live debugger for good measure.

See the Pen inStyle Crash Test Dummy by Salsita Software (@salsita) on CodePen.

Thanks for reading!


inStyle (Modifying the Current Selector `&` in Sass) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/instyle-current-selector-sass/feed/ 36 242174
The Sass Ampersand https://css-tricks.com/the-sass-ampersand/ https://css-tricks.com/the-sass-ampersand/#comments Tue, 12 Jan 2016 15:06:12 +0000 http://css-tricks.com/?p=236708 The & is an extremely useful feature in Sass (and Less). It’s used when nesting. It can be a nice time-saver when you know how to use it, or a bit of a time-waster when you’re struggling and could …


The Sass Ampersand originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The & is an extremely useful feature in Sass (and Less). It’s used when nesting. It can be a nice time-saver when you know how to use it, or a bit of a time-waster when you’re struggling and could have written the same code in regular CSS.

Let’s see if we can really understand it.

Basic Nesting

.parent {
  .child {}
}

This compiles to:

.parent .child {}

You can nest as deep as you’d like, but it’s a good practice to keep it only a level or two to prevent overly specific selectors (which are less useful and harder to override).

Adding another class

The & comes in handy when you’re nesting and you want to create a more specific selector, like an element that has *both* of two classes, like this:

.some-class.another-class { }

You can do this while nesting by using the &.

.some-class {
  &.another-class {}
}

The & always refers to the parent selector when nesting. Think of the & as being removed and replaced with the parent selector. Like this:

The “aha” moment!

Take this Sass:

.parent {
  .child {}
}

This can actually be thought of as short-hand for nesting with the &:

.parent {
  & .child {}
}

So, these two examples both compile to the same thing:

.parent .child {}

The example with the & isn’t anything different than the example without the &. Nesting without the & is shorthand for nesting with it. We can think of the & as a mechanism that allows us to place the parent selector wherever we need it in our child selector. It allows us to nest with alterations. Let’s look at some more examples.

Using the & with pseudo classes

You can write pseudo classes on a class in a much less repetitive way with the &:

.button {
  &:visited { }
  &:hover { }
  &:active { }
}

This compiles to:

.button:visited { }
.button:hover { }
.button:active { }

The & in this case allows us to position .button directly next to pseudo classes without repetition in the authored code. If we left out the & from this example, basic nesting would put a space between them like this…

.button :hover

… which isn’t the same.

Using the & with >, +, and ~

Using the & with the child combinator >, adjacent sibling combinator +, and the general sibling combinator ~ is a breeze. At first I thought you had to use the &, but:

// You don't actually have to do this.
// Here, the ampersand is implied.
.button {
  & > span { }
  & + span { }
  & ~ span { }
}

Leaving the &‘s out of the selector works here:

// This compiles the same as above
.button {
  > span { }
  + span { }
  ~ span { }
}

Both of these examples compile into this CSS:

.button > span { }
.button + span { }
.button ~ span { }

Qualifying based on context

Nested selectors don’t necessarily have to start with the ampersand. You can qualify a selector by putting the & on the right.

.button {
  body.page-about & { }
}

We’re repositioning the parent selector exactly where we need it. This is really useful for qualifying a selector based on a different parent. This will compile to:

body.page-about .button {}

Meaning, select the button class only when a child of a body with a page-about class.

Tweaking the definition of the &

Think of the & as not only being replaced by the parent selector but as being replaced by the *compiled* parent selector.

This is important when nesting more than two levels deep, where more than one level has an &. These next two wacky examples drive this point home.

Wacky but working example #1

Do not write selectors that look like this:

.parent {
  .child {
    & div & & > a {}
  }
}

For each & it will be replaced with the compiled parent selector. Therefore, every time there is an & we’ll insert .parent .child. Here’s the compiled CSS:

.parent .child div .parent .child .parent .child > a {}

Wacky but working example #2

.parent {
  .child {
    .grand-child & {
      &.sibling { }
    }
  }
}

To mentally-compile this CSS, start at the top-most layer and work your way down pealing off the outer layers and replacing the & with the new compiled parent selector.

Here it is compiled:

.grand-child .parent .child.sibling {}

What the & isn’t

I found I was using the & for something it wasn’t from time to time. The & doesn’t allow you to selectively traverse up your nested selector tree to a certain place and only use a small portion of the compiled parent selector that you want to use. I’ve wanted to do something like this before:

.grand-parent {
  .parent {
    &(1) .child {} // Trying to get `.parent`, not `.grand-parent .parent`
  }
}

My intention was for the & to only get replaced with .parent in hopes of compiling to this:

.parent .child {}

But that doesn’t work.

The & is always the fully compiled parent selector.

@at-root to the rescue

It’s worth mentioning that @at-root allows you to break out of your nesting structure entirely to the “root” of your nesting tree.

.grand-parent {
  .parent {
    @at-root .child {}
  }
}

We’ve teleported out of the nesting tree to this compiled CSS:

.child {}

This is nice. From an organizational perspective, all the code is still grouped together, which could be noted as an unsung benefit of nesting. @at-root can help keep specificity levels low because you no longer have the compiled parent selector to increase specificity. All the while still keeping your code conceptually organized with nesting:

.grand-parent {
  .parent {
    @at-root body.page-about .child {}
  }
}

Compiled CSS:

body.page-about .child {}

There’s a few other use cases for the & that can be fun.

Doubling up specificity

Sometimes you need to beat-down the specificity of a 3rd-party CSS library to take ownership of the style:

.parent.parent {}

It’s a lot less overpowering than using and ID, inline style, or !important and it could have benefits over qualifying the selector with an arbitrary parent element. The specificity level isn’t raised based on a selector’s context, but only by itself. With the & you can do that same thing like this.

.parent {
  &#{&} { }
}

The interpolation brackets #{ } are needed as two touching ampersands are invalid Sass.

Modifying the ampersand

Even though you can’t have two ampersands touching without the interpolation brackets — as we demoed earlier in our pseudo class example — you can have another selector touch the ampersand. Touching the ampersand works well with modifier classes.

.btn {
  &-primary {}
  &-secondary {}
}

Compiled CSS:

.btn-primary {}
.btn-secondary {}

This can be quite useful if employing a naming methodology (i.e. BEM) which uses dash and underscore combinated classes rather than combined selectors.

Conclusion

The ampersand combined with nesting is a great feature. Once you know what it’s doing, authoring your Sass can become easier, faster, and less error-prone.

Here’s a couple of other articles specifically about the ampersand, for your reference pleasure:


The Sass Ampersand originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-sass-ampersand/feed/ 20 236708