allBlogsList

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.