Skip to content

Sass best practices

ashleykolodziej edited this page Jan 7, 2019 · 2 revisions

Before you start, you should be familiar with:


In this document, we'll cover:


Sass is just like CSS - what's the big deal?

Although you can write standard CSS in a Sass file, Sass gives you a number of tools that can be very helpful to you - and also get you into a lot of trouble. Understanding how these tools work and how the Sass compiler understands them is key to ensuring your compiled CSS is just as efficient and beautiful as if you had written it yourself. It's also important knowledge to have at your disposal if you need to debug some bonkers CSS in your theme.

We won't bore you with the basics - that's what this handy Sass guide is all about. It's easy to find information on the features of Sass. It's not so easy to find information on the nuances of how Sass handles some of these features, and that's what this guide is all about. Let's dig in.

Try live examples on your own! Throughout this document, you'll notice some links to live examples on SassMeister. Go ahead and try editing them - it compiles in real time, and you can see how your changes affect the compiled CSS right away. No one but you will see your changes, so go wild.

Nesting

The problem

Your compiled CSS is too specific. Like, whack-level specific.

Below is an example of how the same (NOT GOOD) rule could be written three ways. Notice how all three rulesets compile to the same thing, even though some technically adhere to the style guide. Just as you avoid overly specific selectors in CSS, you should avoid over-nesting in Sass.

Try a live example

Play with this gist on SassMeister.

<script src="https://cdn.sassmeister.com/js/embed.js" async></script>

The solution

Don't do that thing!

Why do we care? Putting aside performance, length of your stylesheet, BIG problems with @extend, and readability of the Sass file, the fact of the matter is that a rule like .single .navigation .pages a.numbers:hover is very, very fragile. In that rule, if ANY of these changes - .single .navigation .pages a - the whole rule breaks. What happens if someone updates a class in your theme? What if you need to use a span instead of an a later? When so many things are dependent on each other, testing and making changes to improve themes is very, very difficult.

The big takeaway: Our Sass nesting rules are meant to prevent overly specific CSS selectors in the compiled CSS. No matter how you spin it, a long CSS selector will always compile to a long CSS selector. Don't do it!

Extending

The problem

Your compiled CSS is insanely long and bizarre, with weird rules you never wrote.

How excited were you when you first found out you could just tell Sass to make stuff look like other stuff instead of writing it all out all over again? You were like NO WAY. And you were in love. It was @extend at first site.

Now it's months later, and your compiled CSS is filled with bizarre rules that you never wrote, can't find anywhere in the Sass files, make no sense, and would never be used in the site. It's out of control and un-debuggable. What happened? @extend happened.

@extend is one of the most useful features of Sass - and also one of the easiest to get in trouble with. @extend says, "Hey, Sass, take this rule and make it act just like this other rule." The crucial part: they're not kidding about the "just like" there. Anywhere the class you're extending shows up in the Sass file, the CSS rule you told to look like that class will try and act exactly the same by creating a new rule using your CSS rule.

It's sort of like doing a find and replace on that class in the CSS - except imagine if instead of replacing the class name, you just made a copy of the rule and then replaced it. Everywhere that class shows up, the thing that extends it will show up too. Confused? Try playing with this example to see how it works.

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

The solution

Find the generic styles you want to apply to everything, and create a placeholder selector to hold them. @extend the placeholder selector.

Why use a placeholder? If you don't use it, it won't show up in your compiled CSS - awesome. But more importantly, you're much less likely to accidentally write a rule like .archive %row-styles than you are .archive .row.. When you use a placeholder selector, you're really thinking "are these general styles I want to apply to a number of different classes?" Check out how a placeholder class fixes the above example right up with minimal effort.

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

Placeholder Selectors

The problem

You want to be able to edit a repeated set of rules from one place.

In this scenario, placeholder selectors are your friend. You may have seen these things in our framework or in other people's code. They hold a set of reusable CSS rules that you can reference throughout your code. If you're reading this in order, you know how to use them - just @extend them.

These rules don't have to be full sets of styles for a single element. Sometimes, it helps to use them as utilities that can be changed at a global scale. In this way, they can act a little like variables, except for multiple rules. In the example below, if I change the letter-spacing once in my placeholder class, it will update all my type spacing across the CSS.

Debugging tip: Having trouble keeping track of what rules go with what placeholders? Things not ending up where you expect? Try /* adding a multi-line comment */. Our Sass setup keeps these comments in the compiled, uncompressed CSS, so you can leave yourself a comment, compile, and then search for it to find where your CSS is ending up if you ever get lost.

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

Advanced placeholders

Placeholder selectors can do just about everything a normal CSS class can do in Sass, including using mixins, variables, and defining children and pseudo-class styles. This can be especially handy when you want to have multiple shortcodes which share many attributes, but differ in one or two key ways. In this example, we have three shortcodes that share all the same styles, except for a different icon.

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

Mixins

The problem

Rules are being repeated all over the place! What gives?

The big difference between placeholder selectors and mixins is their behavior when you compile. Placeholder selectors will gather all the rules into one place, and only write the CSS once. Mixins - @include - will write a new CSS rule, repeating all properties in the rule, every time it's called. For this reason, you should only use mixins for CSS that needs to change based on a variable.

Here are two examples of how a clearfix can be written and called, and what happens on compile with each.

@include a mixin

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

@extend a placeholder class

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

Surprise! The placeholder produces MUCH more efficient and neat CSS.

Now, that doesn't mean mixins are bad. You just need to be aware of what CSS you actually need to print and change using a mixin. Let's look at a more advanced example. Say we want all our widgets to have a particular set of styles, but we want to change the color of the text in the widget, as well as the hover color of the links in the widget, based on what type of widget it is.

You were a rockstar and figured out all the static CSS should go in placeholder classes. You even figured out that by using color: inherit, you can just set a color on the widget container and have all the child type turn out that color. Nice!

You may be tempted to put those placeholder classes right in the mixin, like so:

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

However, we know something about all of these widgets - they will always have a class of .widget on them. So if we know that, does it make sense to print individual rules for the children of .bu_text, .bu_pages, and .bu_profiles individually, when they all share the same rules? (Hint: nope!)

The solution

Only include what needs to be changed with a variable in your mixins. Although the CSS is properly combined because of your placeholder classes, it makes more sense to apply the placeholder classes to widgets instead of the individual types of widgets, like so:

Try a live example

Play with this gist on SassMeister.

<script src="http://cdn.sassmeister.com/js/embed.js" async></script>

This avoids unnecessary CSS selectors.

#A final note

There are tons of great features in Sass, but understanding how they work and what they will do will make your compiled CSS much better, and provide a better user experience for the people using our site.

And if that's not reason enough to do this, consider that these small examples will be multiplied many times over on a real project - and you get to debug them if something doesn't work as expected. Doing your best to adhere to these best practices in your Sass will save you time and heartache when you're getting ready to launch.

As always, be sure to follow our coding standards and check out the code review checklist to make sure you're not missing anything. Happy theming!

Welcome to Responsive!

Get started

Configuration

Build child themes

Sass

Javascript

PHP

Shortcodes

Templates

GitHub

Tasks

Contribute to the framework

Code Examples

BU Developer Resources

Clone this wiki locally