-
Notifications
You must be signed in to change notification settings - Fork 0
Sass best practices
Before you start, you should be familiar with:
- The basics of Sass
- Our coding standards
- Looking at your compiled CSS on a regular basis
In this document, we'll cover:
- Sass is just like CSS - what's the big deal?
- Nesting
- Extending
- Placeholder Selectors
- Mixins
- A final note
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.
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.
Play with this gist on SassMeister.
<script src="https://cdn.sassmeister.com/js/embed.js" async></script>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!
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.
Play with this gist on SassMeister.
<script src="http://cdn.sassmeister.com/js/embed.js" async></script>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.
Play with this gist on SassMeister.
<script src="http://cdn.sassmeister.com/js/embed.js" async></script>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.
Play with this gist on SassMeister.
<script src="http://cdn.sassmeister.com/js/embed.js" async></script>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.
Play with this gist on SassMeister.
<script src="http://cdn.sassmeister.com/js/embed.js" async></script>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:
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!)
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:
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!
Get started
Configuration
Build child themes
- Customizing CSS in a child theme
- Overriding templates in a child theme
- Code patterns
- Code reviews
- Pulling in Foundation Updates
- Merging and Creating a Pull Request
Sass
Javascript
PHP
- Coding Standards
- PHP Constants
- Temp PHP Code Patterns
- PHP Snippets
- How to Use Hooks
- Action Hooks
- Using Action Hooks To Output Markup
- Filter Hooks
Shortcodes
Templates
GitHub
Tasks
Contribute to the framework
- Framework Development and Release Workflows
- Documentation Template
- Testing your changes
- Creating a new release
- Migration Guide
- Needs Documentation
Code Examples
- Adding Content Container Classes
- Adding News Templates
- Adding Script Dependencies
- Changing Available Layouts and Default Layout
- Displaying a Fancy Gallery
- Loading a Custom Build of Modernizr
- Loading Modernizr in the Footer
- Using Action Hooks To Output Markup
- Understanding get_template_part
BU Developer Resources