This article originally appeared in issue 265 of net magazine
Every good developer knows to look for ways to reduce repetitious work and let their computer handle mundane, mindless tasks. CSS preprocessors like Sass give us several valuable tools to help automate the frontend coding process. For example, with Sass we can use variables. So instead of running a 'find and replace' command through a long CSS file to tweak a colour value, we can simply change the variable definition.
Sass also allows us to write functions to generate blocks of repeated style code. For example, a button function could accept the colour or style as a parameter and generate all the standard CSS for a site's button UI: border radius, gradients, text colours and so on. We can also break up our giant stylesheets into organised modules. Nearly every CMS, plugin and web app uses directories and partials to improve code maintainability: Sass allows us to do this with our CSS.
The techniques explained in this tutorial are specific to Sass using the SCSS syntax, but they are applicable to most other preprocessors – like Less or Stylus – as well.
Converting theme stylesheetsIf the WordPress theme you're using has Sass files included already, the process of converting existing theme stylesheets to Sass is done for you. I typically start new themes with the Underscores template from Automattic (underscores.me). When creating a new theme package from its website, you'll find a '_sassify!' option if you click the 'Advanced Options' link. This will provide Automattic's default Sass library for you when you download the blank theme.
The Underscores WordPress theme offers an option for users to download a version of the theme that includes Sass partials alreadyIf the theme you're building or modifying doesn't include Sass files, however, you'll begin by converting the existing CSS file to Sass. This step reveals a major advantage to using Sass (SCSS): the Sass compiler reads plain CSS with no trouble at all. All you need to do to use the original style.css as Sass is to duplicate it and rename it style.scss.
Setting up Sass partialsEarlier I mentioned that Sass improves our workflow by letting us break thousands of lines of CSS into modular files called partials. Let's work through this step before getting to compiler methods.
If you've converted an existing CSS file to Sass, all you've got so far is a .scss file that's just as unwieldy as the CSS file it came from. At this point, you can start using variables and writing mixins or functions, but the Sass isn't modular or organised yet. You want to group your CSS file into sections that serve individual purposes. The goal is to be able to work out where code is found based on its file name.
Some modules of code that you'll probably want to isolate include navigation, typographic styles, sidebar widgets, footer and a grid system (although that list is not comprehensive by any means, it's just a starting point).
You will then cut and paste each modular section of CSS into its own Sass partial. A Sass partial's file name always starts with an underscore (_). This tells compilers not to create a unique CSS file based on this Sass file.
A compiler app that watches a folder full of Sass and automatically generates CSS will create style.css based on style.scss, but it won't create navigation.css based on _navigation.scss. To compile all the partials you've just created, you'll @import them in your main Sass file.
Each time you copy a block of code to a partial, replace it in the primary .scss file with @import 'partial-name';. If you move your footer styles to _footer.scss, add @import 'footer';. Don't include the _ or the .scss in the import: just the name of the file.
If you want to get really organised and break header navigation and footer navigation into two separate partials in a /navigation/ folder, include the folder name in the import:
@import 'navigation/header-nav'; // imports /navigation/_header-nav.scss
@import 'navigation/footer-nav'; // imports /navigation/_footer-nav.scss
It's important to remember that the CSS cascade still applies to code written in Sass. Styles written in partials imported later have the ability to override styles in partials imported earlier.
It's also wise to import partials that contain your mixins and variables at the beginning of your primary Sass file, so that later partials can actually use those variables and mixins.
WordPress commentsAccording to WordPress style.css requirements, we need to make sure our compiler preserves the WordPress comments at the top of style.css. When Sass' output_style is set to :compressed, it strips all comments when it compiles CSS.
To ensure that those comments are left intact, add an exclamation mark (!) to the beginning of the comment block in style.scss:
/*!
Theme Name: Sassy WordPress Theme
Theme URI: <a href="http://jamessteinbach.com/sass/
Author:" title="http://jamessteinbach.com/sass/
Author:">http://jamessteinbach.com/sass/
Author:</a> James Steinbach
Author URI: <a href="http://jamessteinbach.com
Description:" title="http://jamessteinbach.com
Description:">http://jamessteinbach.com
Description:</a> From CSS to Sass Sample Theme Code
*/
// Import all your .scss partials below
Now that we've broken a long stylesheet into smaller modular partials, we can start to refactor the original CSS to fit our Sass preferences. Some helpful Sass tools for refactoring code are variables, nesting, functions and mixins.
If you want to change some colours or set up a standard type scale, variables are the best way to save all that data in a single place and make site-wide changes easily. If you haven't already created a partial called _variables.scss, I recommend doing that now – and importing it at the top of your main Sass file. Here are some variables you may want to put in that partial:
$red: #FF4136;
$blue: #0074D9;
$blue-dark: #001F3F;
$orange: #FF851B
$type-small: 12px;
$type-medium: 16px;
$type-large: 21px;
$type-hero: 44px;
Once you've set up those variables, you can search your partials and replace values with variable names:
body {
color: $blue-dark;
}
.page-title {
font-size: $type-large;
}
You can use a Sass feature called 'nesting' to help make complex selectors more readable. Your starting CSS may include styles for multiple elements in the site sidebar:
.sidebar h1 {
//styles
}
.sidebar p {
//styles
}
.sidebar ul {
//styles
}
You can nest styles inside of other style blocks and Sass will combine selectors to create the complex selectors. The code below will compile to the same output as the original CSS (as shown in the code above).
.sidebar {
h1 {
//styles
}
p {
//styles
}
ul {
//styles
}
}
In nesting & can be used as a placeholder for the entire string of selectors above it. As nesting puts a space between selectors, it can be helpful when using pseudo-classes and pseudo-elements:
a {
color: $blue;
&:hover {
color: $blue-dark;
}
}
.clearfix {
&::before,
&::after {
content: "";
display: table;
clear: both;
}
}
The & can also be used to duplicate or reverse the order of selectors:
p {
& + & {
margin-top: 1em;
}
}
.menu-link {
color: $gray;
.menu-item:hover & {
color: $gray-light;
}
}
You may be wondering if it's worth your time to refactor by nesting properties. While nesting may increase readability (although this is subjective), it's also a tool to be used carefully. Most Sass experts recommend an 'Inception rule' for Sass nesting: never nest more than three levels deep. It's wise to use Sass nesting sparingly. If it doesn't make sense in your workflow, don't force it.
Sass is the most mature, stable and powerful professional-grade CSS extension languageIf you're repeatedly calculating certain properties in your CSS, you can replace that process with a Sass function. A function takes the parameters you give it and returns a value. It won't generate CSS property-value pairs, but it can generate values for you.
Here's an example of a function to calculate faded colours on hover:
// This goes in _functions.scss:
@function hover-color($color) {
@return lighten($color, 10%);
}
// This is how you use the function in other partials:
.button {
background-color: $red;
&:hover {
background-color: hover-color($red);
}
}
We can also refactor our code by taking repeated blocks of code and replacing them with mixins. A great example of a useful mixin is a clearfix.
// This goes in _mixins.scss:
@mixin clearfix() {
&::after {
content: “”;
display: table;
clear: both;
}
}
// This is how you use the mixin in other partials:
.content-container {
@include clearfix;
}
Mixins can also take parameters to generate customised output. This is very useful for design patterns like buttons or alerts:
// This goes in _mixins.scss:
@mixin alert($color) {
border-radius: .5em;
box-shadow: 0 0 .25em 0 rgba(0,0,0,.5);
border-top: 4px solid $color;
color: $color;
}
// This is how you use this mixin:
.alert-error {
@include alert($red);
}
.alert-success {
@include alert($green);
}
One common piece of advice that you may see online is to use mixins for cross-browser prefixing. I usually recommend against this, however. I find that Autoprefixer is a much better way to automate prefixes.
If you're unable to run Autoprefixer, and have to rely on Sass mixins, Compass' mixin library allows user configuration and stays up-to-date with CanIUse data.
Organise your partialsTo recap, we've taken the theme's existing stylesheet apart and refactored some code to make things cleaner and Sassier. Now we can organise our partials to improve maintainability in the long run.
Organising your CSS With Sass, developers can use tools like variables, nesting, functions and mixins to organise and automate their CSSRemember that the cascade still matters. Sass-compiled CSS is just like plain CSS in that styles that appear later in the stylesheet can override styles that appear earlier. As a rule, import your general styles before you import specific styles.
Similar partials can be organised in folders. There are two ways to import Sass partials from directories. The first is to import each file into style.scss including the folder name in the import directive, like this:
@import 'base/variables';
// imports _variables.scss from the /base/ directory
@import 'base/mixins';
// imports mixins.scss from the /base/ directory
@import 'base/grid';
// imports _grid.scss from the /base/ directory
The second (and admittedly more complicated) method is to create a placeholder partial in each directory that imports the other partials in that directory (next column):
// in style.scss
@import 'base/base';
// in /base/_base.scss
@import 'variables';
// imports _variables.scss from the /base/ directory
@import 'mixins';
// imports mixins.scss from the /base/ directory
@import 'grid';
// imports _grid.scss from the /base/ directory
Both of these methods import the same partials in the same order. The first method is simpler on the surface, but the second method has the advantage of keeping style.scss neat and moving any complexity into the modules it relies on.
There are almost as many ways to organise Sass partials as there are developers trying to organise Sass partials. You'll find several good options in the 'Resources' boxout on page 88.
Here's one fairly simple organisation scheme you could use:
This article only begins to explore the potential of using Sass in WordPress theme development. Chances are strong that you're eager for more information now, especially if this is the first thing you've read on the subject.
Check out the 'Resources' boxout for more reading around the subject – these articles include several variations on a Sass-WordPress workflow. Some of their advice differs from what I've recommended (especially on the topic of organising partials), but that's fine – find the techniques and workflows that work for you!
James Steinbach has created an exclusive screencast to go with this tutorial, which you can watch below.
Words: James Steinbach
Source: Switch from CSS to Sass in WordPress
No comments:
Post a Comment