Selector- and Class-Based Even/Odd Styling

2018-08-16 | #css, #webdev

We all now CSS's :nth-child(even/odd) right? This is super helpful for building alternating visual patterns, but wouldn't it be nice if we could narrow down the set of elements the alternations should be applied on and setting the alternations not by element index, but by index in that selected group? Say you have an element containing nodes that might be temporarily invisible, for example to switch between two types of visualization of the same data (maybe for responsive behaviour).

With the help of preprocessors like Sass and the the following siblings selector in CSS you can achieve this. Take these mixins:

@function nth-selector($n, $selector) {

$classes: ();

@for $i from 1 through $n {

$className: if($i == 1, #{$selector}, #{"~ " + $selector});

$classes: join($classes, unquote($className), space);

}

@return $classes;

}

@mixin even-by-selector($selector, $maxChainLength:12){

@for $i from 1 through $maxChainLength * 2 {

@if $i % 2 == 0 {

#{nth-selector($i, $selector)}{

@content

}

}

}

}

@mixin odd-by-selector($selector, $maxChainLength:12){

@for $i from 1 through $maxChainLength * 2 {

@if $i % 2 != 0 {

#{nth-selector($i, $selector)}{

@content

}

}

}

}

ul {

@include odd-by-selector('li.currently-visible', 10);

}

One mixin styles all even indices inside the selected element set, while the other styles the odd ones. This is based on a programmatic concatenation of the given selectors with a "~" in between. We differentiate even and odd, by just rendering the fitting counts. I set a maximum of 12 elements to be considered (because it's the most commonly used number of columns), but you are free to reduce or expand that. But always be mindful, that this renders a lot of CSS if the chains get longer and that selectors such as

li.currently-visible ~ li.currently-visible ~ li.currently-visible ~ ... {}

are CPU-heavy as well.