How to create flexible, reusable styles using CSS subclasses
TL;DR
- Long selector chains create fragile, non-reusable, and monolithic CSS
- CSS subclasses allow you to reuse modules in any location without breaking styles
- Skip down to the CSS subclass tutorial
A quick recap
In my previous post, I talked about how to style multiple sites that look different using only one CSS collection.
At Business Insider and INSIDER we use a single CSS collection to define the styles for both sites.
Geeking-out about CSS
Let?s talk about how to recognize patterns in your CSS, and how to create reusable, flexible styles by using CSS subclasses.
If you?ve ever written CSS, you?re familiar with the overwhelming instinct to use a parent element selector to style something differently.
Consider these examples.
Here we style the title differently based on where it?s located:
/* CSS */#header h2.title {…}#footer h2.title {…}
In the HTML:
<!– In the header HTML –><section id=?header?> <h2 class=?title?><!– In the footer HTML –><section id=?footer?> <h2 class=?title?>
Using multiple parent selectors we increase specificity in order to avoid overwriting styles:
/* CSS */#header .menu a.title {…}
With this HTML:
<!– In the HTML –><section id=?header?> <div class=?menu?> <a class=?title?>
Long selector chains usually link to a specific HTML structure, and frequently indicate poorly designed CSS:
/* CSS */#header .navigation .menu .sub-menu li a.title {…}
Used for the following HTML:
<!– In the HTML –><section id=?header?> <section class=?navigation?> <div class=?menu?> <ul class=?sub-menu?> <li> <a class=?title?>
So what?s the problem here?
Long descendant selector chains are problematic for a few reasons:
- They cause specificity issues.In order to avoid overwritten styles and selector collisions, we must either increase specificity by adding more selectors, or use !important.
- They?re fragile.The selectors are tightly coupled to the HTML structure. Changes to the HTML will break the styles.
- They?re not reusable.The module can?t be reused in different locations without broken styles. Non-reusable styles create monolithic CSS collections.
Danger ahead!
Let?s look at a quick example showing how a descendant selector chains could create non-reusable CSS.
We begin with a large title in the #header, and a small title in the #main section. Here?s the CSS:
/* CSS */.title { color #f00;}#header .title { font-size: 2rem;}#main .title { font-size: .5rem;}
And the corresponding HTML:
<!– In the header HTML –><section id=?header?> <span class=?title?><!– In the main HTML –><section id=?main?> <span class=?title?>
Let?s imagine our task is to move the title out of the main section into the footer section. Here?s the updated HTML:
<!– In the footer HTML –><section id=?footer?> <span class=?title?>
The title will have the wrong size until we rewrite the CSS selectors:
/* CSS */// Broken until we change ?#main .title? to:#footer .title { font-size: .5rem;}
These CSS selectors are location specific rather than location agnostic.
That means our CSS isn?t reusable because our descendant selectors are tightly coupled to the structure of our HTML.
This is a simple example, but it?s easy to imagine a component with dozens of elements and styles. Moving it could quickly become complex.
Fragile selectors like these break easily when its module changes locations.
What if there was a way for us to reuse the title in any location without needing to rewrite the CSS selectors?
There is!
This is where subclassing comes into play.
Subclass? That sounds fancy.
Yes, it is fancy.
Subclass is just a novel way to say, ?use another class name? when you recognize or plan reusable design patterns that relate to a parent class.
If we use subclasses, instead of descendant selectors, we can move and reuse stuff in different places without breaking styles or rewriting the selectors.
The key is to recognize reusable design patterns in our CSS, then write a subclass for it.
In this case, the reusable pattern is the title?s font-size:
/* CSS */.title { color #f00;}// New subclass called ?title-large?.title-large { font-size: 2rem;}// New subclass called ?title-small?.title-small { font-size: .5rem;}
Here?s how we?ll update HTML:
<!– In the header HTML –><section id=?header?> <span class=?title title-large?><!– In the footer HTML –><section id=?footer?> <span class=?title title-small?>
Since title uses CSS subclasses, we can move it and reuse it anywhere on the page without broken styles.
A mini-subclass tutorial
Let?s dive into a more in-depth practical example.
In the following example we?ll design the CSS for an inline SVG icon that can be reused in any location without breaking its styles.
Notice the icon is black and 50×50 px in the header.
1. To begin, we?ll write the icon?s base styles:
.icon { display: inline-block; width: 50px; height: 50px; fill: black;}
2. Next, we?ll take a minute to think about how to name our subclasses. We?ll do this by looking for reusable patterns.
Most of the planning for sustainable CSS frameworks happens at this point: recognizing and naming patterns.
The idea is to choose names that provide the most helpful information to you, your fellow engineers, and your future self, since you?ll be the ones using it.
How are the elements used on the page? How can we describe the patterns we recognize, hopefully semantically, without specifying exact styles?
This step can be tricky, and often frustrating. Yet in my experience, it can also be one of the more rewarding aspects of writing well-designed CSS.
Avoid coding to please strangers who inspect your page source. Instead, think about folks you build with, your colleagues, and the brilliant people who will inherit your code.
So, let?s look at how the icon is used:
In the header the icon is black and 50×50 px.In the footer the icon is white and 20×20 px.
An easy option is to use a name describing the icon?s location, for example, .icon-header. Unfortunately, that name doesn?t describe anything about the icon?s style. It?s not very informative. Also, it?s not helpful if we want to reuse it in different locations.
A better option is to use a name that describes how we expect to use, and reuse, the icon. Since the header has a white background, and the icon is larger, let?s use the name .icon-light-background-large.
The footer has a black background, and the icon is smaller, so let?s use the name .icon-dark-background-small.
Feel free to experiment where you and your team land on the spectrum of naming conventions. Don?t stress too much. Find out what?s helpful and enjoyable, then use it consistently.
In most cases, overly abstract classnames are not descriptive or human readable. They require engineers to learn symbolic codenames from a CSS framework, for example, .w-100 or .yui3-u-1?12.
By contrast, overly specific classnames are not flexible or reusable because they specify the styles rather than describe them, for example, .green-logo-80px-wide.
3. Now we?ll add the new CSS subclasses. This helps us avoid the temptation to use its location as a parent selector.
Instead of this:
// No#header .icon {…}#footer .icon {…}
We?ll write this:
// Yes.icon { display: inline-block;}.icon-light-background-large { width: 50px; height: 50px; fill: black;}.icon-dark-background-small { width: 20px; height: 20px; fill: white;}
And here?s the HTML with our new subclass names:
<!– In the header HTML –><section id=?header?> <a class=?icon icon-light-background-large?> <svg … ><!– In the footer HTML –><section id=?footer?> <a class=?icon icon-dark-background-small?> <svg … >
4. If you really want to geek out, subclass the size as well:
.icon { display: inline-block; width: 30px; height: 30px;}.icon-large { width: 50px; height: 50px;}.icon-small { width: 20px; height: 20px;}.icon-light-background { fill: black;}.icon-dark-background { fill: white;}
And the HTML would be:
<!– In the header HTML –><section id=?header?> <a class=?icon icon-light-background icon-large?> <svg … ><!– In the footer HTML –><section id=?footer?> <a class=?icon icon-dark-background icon-small?> <svg … >
When not to use CSS subclasses?
CSS subclasses are a powerful way to write reusable CSS. However, there are cases where you don?t need subclasses:
- The HTML won?t change
- The module won?t be reused
- The module won?t be moved or redesigned
That?s it for the demo
To wrap up, the key benefits from using CSS subclasses:
- They?re scalable, flexible and reusable.
- Their names are descriptive and helpful.
- They can be exchanged or omitted. When omitted, the module defaults to its base styles.
That?s a wrap
Thanks for doing a mini-deep dive into using CSS subclasses. Hopefully you and your team will benefit from thinking about how to build scalable and reusable CSS collections using subclasses.
Got ideas or feedback?
I?d love to hear from you if you have questions or suggestions. Especially if there?s stuff you?d like to know more about, or if something was confusing.
Looking for a new job opportunity? Become a part of our team! We are always looking for new Insiders.