Quantity Selectors in Sass

ATX Sass | September 21st, 2017

How nth-child works

How nth-child works
3 3n 3n+1 -n+3 n+4
0 3 0 1 3 4
1 3 3 4 2 5
2 3 6 7 1 6
3 3 9 10 0 7
4 3 12 13 -1 8
100 3 300 301 -97 104
:nth-child(3){…}    // the third child
:nth-child(3n){…}   // every third child
:nth-child(3n+1){…} // every third child, with offset
:nth-child(-n+3){…} // the first three children
:nth-child(n+4){…}  // all except first three children
Some basic nth-child recipes

Creating Quantity Queries

li:nth-last-child(-n+8){ // the last eight children
  background: red;
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
li:nth-last-child(-n+8){ // the last eight children
  background: red;
}

li:first-child{ // the first child
  background: green;
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
li:nth-last-child(-n+8){ // the last eight children
  background: red;
}

li:first-child{ // the first child
  background: green;
}

li:nth-last-child(-n+8):first-child{ // first of at most eight
  background:blue;
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
li:nth-last-child(-n+8):first-child, // first of at most eight
li:nth-last-child(-n+8):first-child ~ li{  // or a sibling 
  background:blue;
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
li:nth-last-child(n+6):first-child, // first of at least six
li:nth-last-child(n+6):first-child ~ li{  // or a sibling 
  background:blue;
}
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
li:nth-last-child(even):first-child, // first of even
li:nth-last-child(even):first-child ~ li{  // or a sibling 
  background:blue;
}
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  

Abstracting Into Sass

@mixin has-nth($expression, $element: '*') {
  &:nth-last-child(#{$expression}):first-child,
  &:nth-last-child(#{$expression}):first-child ~ #{$element} {
    @content;
  }
}

A generic Sass mixin for selecting by quantity

Any valid :nth-child expression can be passed to the has-nth() mixin.

li {
  @include has-nth('3n', 'li') {
    border-radius: 0;
  }
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
@mixin at-least($quantity, $element: '*') {
  @include has-nth('n + #{$quantity}', $element) {
    @content;
  }
}
An at-least Sass mixin, an abstraction of has-nth for readability.
@include at-least(6) {
  background: $blue;
}
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
@mixin at-most($quantity, $element: '*') {
  @include has-nth('-n + #{$quantity}', $element) {
    @content;
  }
}
An at-most Sass mixin
@include at-most(8) {
  background: $blue;
}
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Some Other Possible Mixins:

  • divisible-by
  • has-exactly
  • has-even
  • has-odd

Use Cases

Gotchas & Considerations

  • Can only count either nth-child or nth-of-type
  • Does not account for hidden elements
  • Styling can't affect parent elements (i.e., the ul can't be styled based on the number of li elements.
  • Works best with elements with predictable siblings, such as tr and li

Questions?

https://sassquantity.slides.rocks