mike.zarandona.com

coffee lover, dog person, frontend engineer

Optimizing CSS Inheritance

Posted June 2nd, 2016 in CSS tagged Less, How To


In working with CSS quite a bit, I’ve been through quite a few iterations of organization schemes, ultimately landing on a mixture of BEM, SMACSS, and some of my own preferences. My Less files were beginning to feel a bit bloated, especially in the scaffolding type areas such as default button styles, columns, block layouts, and other complex selector collections of layout-based element collections. In the past (and with libraries like Bootstrap and Font Awesome) the standard has been to use base and extension CSS classes, which feels muddy and was no longer working for me.

Out with the Old…

// old way base button styles
.button {
    // ...
}

// old way button modifier classes
.button-success { background-color: green; }
.button-warning { background-color: red; }
<!-- green button requires 2 classes -->
<a href="#" class="button button-success">Success</a>

<!-- red button requires 2 classes-->
<a href="#" class="button button-warning">Uh Oh</a>

To me this has always felt clunky. Maybe it’s CSS framework fatigue, maybe it’s the fact that I’m painfully OCD about these sorts of things, and I always tend to look for a cleaner, better, & more concise solution.

…In with the New

A while ago, after reading quite a bit on the topic I started leveraging attribute wildcard selectors which lead to a much cleaner way of accomplishing complex CSS classes without a lot of bloat inside the CSS/Less nor HTML. This new method is now evaluating pieces of the CSS selectors to apply styles, versus using individual classes. This yields complex styles through single classes, which in my experience has lead to better readability and less bloat.

// base button styles
[class*="button-"] {
    // ...

    // button modifier class pieces
    &[class*="-success"] { background-color: green; }
    &[class*="-warning"] { background-color: red; }
}
<!-- single class green button -->
<a href="#" class="button-success">Success</a>

<!-- single class red button -->
<a href="#" class="button-warning">Uh Oh</a>

Taking Things a Step Further

Doing things this way allows for building really complex sets of selectors without loading a ton of redundancy. Here’s an example of some button classes:

[class*="btn-"] {
    // base button styles

    // call to action buttons
    &[class*="-cta"] {
        // call to action button specific styles

        &[class*="-primary"] {
            // .btn-cta-primary specific styles
        }

        &[class*="-secondary"] {
            // .btn-cta-secondary specific styles
        }

        &[class*="-tertiary"] {
            // .btn-cta-tertiary specific styles
        }
    }

    // ghost buttons
    &[class*="-ghost"] {
        // ghost button specific styles

        &[class*="-primary"] {
            // .btn-ghost-primary specific styles
        }

        &[class*="-secondary"] {
            // .btn-ghost-secondary specific styles
        }

        &[class*="-tertiary"] {
            // .btn-ghost-tertiary specific styles
        }
    }
}

This code results in at least 6 separate button styles. It can be more considering you can leave off the last segment (or segments) and use classes like .btn-ghost or just .btn if the default styles were sufficient for a particular instance.

<!-- use these, they're pretty -->
<a href="#" class="btn-cta-primary">Click Me</a>
<a href="#" class="btn-cta-secondary">Click Me</a>
<a href="#" class="btn-cta-tertiary">Click Me</a>
<a href="#" class="btn-ghost-primary">Click Me</a>
<a href="#" class="btn-ghost-secondary">Click Me</a>
<a href="#" class="btn-ghost-tertiary">Click Me</a>

<!-- stop doing this nonsense, it's ugly and harder to maintain -->
<a href="#" class="button button-ghost button-secondary button-green">Click Me</a>

The huge benefit here is that class names become much easier to read since you’re not overloading each element with a base class plus two to four modifier classes each. Serenity now!

Serenity Now!