Re-using CSS for the wrong HTML with Sass

Posted in:

Recently, while writing up some examples and pattern for using htmx with Django for form validation, I discovered a new trick for using externally defined CSS without having to change the HTML you are working with.

To make it concrete, an example might be that you are using some CSS from a CSS library or framework that requires your HTML to look a certain way. In the Bulma framework, for instance, you have to add the right class attribute directly on an element that needs styling.

At the same time, you might be working with another system that is generating the HTML for you, and modifying that output might be hard or impossible or just tedious and a potential maintenance burden going forward. For instance, in Django forms, there is an ErrorList class whose output can be overridden, but by default renders like this:

<ul class="errorlist">
  <li>Enter a valid email address.</li>
</ul>

Now I have these requirements:

  • I want this error list to be coloured using a Bulma colour utility as if it had class="has-text-danger" when it appears within a field row (which are <div class="field"> elements).

  • When it appears at the top of the form where it has an extra nofield class, I want it to instead be styled like a Bulma notification as if it had class="notification is-danger is-light".

But I want to do these without changing the HTML we’re given by Django, or changing existing CSS – only by adding some CSS rules.

The “best” way to do this is if your CSS framework provides its styles as a set of Sass mixins, or something equivalent. Bulma, as it happens, usually does this, but sometimes we’re not so lucky, and we just have CSS.

The trick I learnt requires you to use Sass/SCSS and the @extend directive. This powerful directive takes rules relating to one selector, and pulls them into whatever rule you are writing.

(If you are, like me, put off using things like CSS pre-processors because of the need for a separate build step, or needing to use Node.js/npm, see my post on How to use Sass/SCSS in a Django project without needing Node.js/npm or running a build process)

The one thing you have to do is rename the base CSS file you want to re-use from .css to .scss. This works because SCSS is a CSS superset. Then, for the example above, you can write your own SCSS file like this:

@import "path/to/bulma.scss";

.field ul.errorlist {
    @extend .has-text-danger;
}

ul.errorlist.nonfield {
    @extend .notification;
    @extend .is-danger;
    @extend .is-light;
}

This technique can be very powerful e.g. make all input[type=text] inside a <form class="bulma"> have the normal Bulma input appearance:

form.bulma {
    input[type=text] {
        @extend .input;
    }
}

This will include all related rules like .input:focus etc.

As mentioned, it may not always be the best technique, but it’s a great one to have in your toolbox.

Comments §

Comments should load when you scroll to here...