loading...

Easily select h1, h2, ... through SCSS functions

nirlanka profile image Nir Lanka ニル ・1 min read

I was writing styles for formatting inside a rich-text web component.

There, due to limitations of the CMS and requirements, we wanted all h1, h2, ... h6 tags to have some similar presentations.

Also, we had selectors like this:

h1 + p, 
h2 + p, 
/*...*/
h6 + p { 
  /*...*/ 
}

Always writing selectors for all cases including all h# tags is a nightmare. It's hard to maintain, too. So I decided to look into how to fix this in the simplest way, while still complying to different use cases.

After going through forums and finding similar solutions, this is my end .scss code:

selector-helpers.scss:

/**
 *  Select any range in {h1, h2, h3, h4, h5, h6}.
 * 
 *  e.g. usage
 *    #{headings('', 1, 6, '.--attr')} { ... }
 */

@function headings($before:'', $from:1, $to:6, $after:'') {
    @if $from == $to {
        @return '#{$before} h#{$from}#{$after}';
    } @else {
        @return '#{$before} h#{$from}#{$after}, ' + headings($before, $from+1, $to, $after);
    }
}

Usage in x-rich-text.scss:

@import "./selector-helpers";

x-rich-text {

    // h1, ...
    #{headings()} {
        /* ... */
    }

    // h1:first-child, ...
    #{headings($after:':first-child')} {
        /* ... */
    }

    // h1 + p, ...
    #{headings($after:' + p')} {
        /* ... */
    }

    // h1, h2 (only)
    #{headings($from:1, $to:2)} {
        /* ... */
    }

    // img + p, ...
    #{headings($before:'img + ')} {
        /* ... */
    }

    // h1.--dark, h2.--dark, ...
    #{headings($after:'.--dark')} {
        /* ... */
    }

    // h1 code, h2 code, ...
    #{headings($after:' code')} {
        /* ... */
    }
}

I believe this can handle all cases with prefixes, suffixes and selective ranges in 1..6.

So yeah. :) Hope this helps you! Let me know if there's a better way of handling this.

Discussion

pic
Editor guide