Conditionally Applying CSS Styles Based on Element Count

  • Twitter
  • LinkedIn

Conditionally Applying CSS Styles Based on Element Count

Have you ever needed to apply different styles based on the number of elements that exist in a particular group? Some developers might immediately turn to JavaScript in order to count the number of HTML elements. Then they might conditionally add or remove a class in order to apply different styles. However, JavaScript isn t actually needed, and in this post I ll show you how you can leverage CSS to accomplish this task.

Let s say you have some very specific business requirements for styling a row of items. They might look like the following:

  • If two items exist, apply 50% width to each.

  • If three items exist, apply 50% width to the first two items, and 100% width to the third item.

  • If four items exist, apply 25% width to each.

While this is trivial to implement using JavaScript, a CSS-only solution would be much cleaner. As a general rule of thumb - I try to avoid using JavaScript for anything that can be handled via CSS. This encourages a separation of concerns and helps keep code performant.

The CSS-only solution involves combining and leveraging the nth-child and nth-last-child pseudo class selectors. This will allow us to conditionally select elements when only a certain number are present . For example, to solve the first business requirement we could use the following selectors:

// if two items exist, apply 50% width

.item:nth-child(1):nth-last-child(2),
.item:nth-child(2):nth-last-child(1) {
    width: 50%;
}

By counting an element s position from both the start and the end of the row, we can conditionally apply styles when only a certain number of elements are present. So if an element is the first item from the beginning of the row and the second item from the end of the row - that means there s only two items present.

Using the same logic, we can solve the remaining business requirements with the following code:

// two items = 50% width

.item:nth-child(1):nth-last-child(2),
.item:nth-child(2):nth-last-child(1) {
    width: 50%;
}



// three items = 50% width
// ... except for last item, which has 100% width

.item:nth-child(1):nth-last-child(3),
.item:nth-child(2):nth-last-child(2) {
    width: 50%;
}

.item:nth-child(3):nth-last-child(1) {
    width: 100%;
}



// four items = 25% width

.item:nth-child(1):nth-last-child(4),
.item:nth-child(2):nth-last-child(3),
.item:nth-child(3):nth-last-child(2),
.item:nth-child(4):nth-last-child(1) {
    width: 25%;
}

Now I admit, this can become tedious to write out over time. This is where CSS preprocessors such as Sass come in handy.

Creating a Sass Mixin

You may have noticed a pattern emerging here, especially in the last example. For each selector string the nth-child argument is incrementing by one, while the nth-last-child argument is decrementing by one. We can easily duplicate this logic pattern via a Sass mixin:

@mixin if($args...) {
    @each $arg in $args {
        @if type-of($arg) == number {
           @for $i from 1 through $arg {
              &:nth-child(#{$i}):nth-last-child(#{$arg - $i + 1}) {
                 @content;
              }
           }
        }
     }
}

And then include the mixin like so:

.item {
    @include if(2) {
        width: 50%;
    }

    @include if(3) {
        width: 50%;

        &:last-child {
            width: 100%;
        }
    }

    @include if(4) {
        width: 25%;
    }
}


Also note that you can pass multiple arguments to the if mixin. For example:

.item {
    // if 1 or 2 items exist
    @include if(1, 2) {
        width: 50%;
    }
}

Now you have a nifty if mixin to add to your toolbelt, which could come in handy when dealing with complex styling requirements.

Related Blogs

Latest Blogs