It’s been quite a while now since we’ve completely abandoned vanilla CSS for a CSS preprocessor (more than four years actually) and more specifically for Sass (with SCSS syntax). There are quite a few reasons why we did that, and the main one is improved DX (developer experience) along with easier plugin integrations.
Simply put, Sass used to be (and still is) a much more powerful language than vanilla CSS, especially if you’re concerned with older browser support (i.e… IE ¯\_(ツ)_/¯). I’ve found that the need for variables, conditionals, mixins, rule nesting, along with color functions and all the goodies a preprocessor comes with is much more apparent within the WordPress theming context where you wish to provide multiple color schemes for your theme or tame popular WordPress plugins to match your theme’s design and layout.
That said, I’m not here to sell you on CSS preprocessors right now, this piece is an overview on how we use Sass with Gulp in our theme and plugin development workflow, and how to incorporate the same workflow to your theme, if you so wish.
Our specific requirements
Back when we started exploring how we’d go about integrating Sass in our themes we had a few hard requirements that usually do not apply to other projects (like standalone apps or websites). This is because our customers range from simple website owners with little to no CSS knowledge to website developers with varying skillsets (not everyone is a front end developer). The above means that:
- All our themes must provide a complete vanilla CSS stylesheet (the main theme’s stylesheet – style.css) which mustn’t look like it was compiled from something else (to the best extend possible) and, more crucially, be readable. A lot of people simply want to add a few touches here and there or copy and paste selectors in their child theme’s stylesheet; they shouldn’t have to deal with Sass if they don’t want to.
- We do not ship themes with a minified stylesheet, for obvious reasons like mentioned above (also it’s not really allowed by the WordPress theme guidelines).
- All vendor stylesheets (e.g. from jQuery plugins) should be in their separate files and not included in the main theme’s stylesheet which must contain only theme styles.
- Sass should be transparent: structure our file hierarchy so that our users can work both with Sass or vanilla CSS depending on experience and preferences.
With the above in mind we’ve settled down in the following file structure with regards to stylesheets:
This allows us to keep Sass merely as an enhancement for the end user that prefers CSS, and still be prominent enough to be used if someone else so chooses.
All compiled files are right next to their sources and each one can easily be ignored in favor of the other. Also notice we’ve stuffed all Sass partials in the
/css/inc directory exactly so that they can be out of the way, if required.
The main style.scss file simply imports all partials, and contains no actual styles in it. For example:
Compiling Sass with Gulp
We use Gulp extensively at CSSIgniter. We have over a dozen different Gulp tasks in our internal toolkit for our various workflows (which we’ll cover in another tutorial), one of them being Sass compilation which we’ll glance over right away.
All Gulp needs to run is to have Node.js installed. After that we’ll need to initialize a project with
npm. First create a directory where your project will live in with the structure we’ve mentioned in the previous section and initialize the project:
package.json file is immediately created for us, which is used to keep track various information about the project such as its dependencies.
For our Sass toolkit we’ll need to install the following dependencies:
Having done that, let’s also globally install Gulp on our system so that we can actually run it as a command:
Another note: If you don’t want to pollute your system with global dependencies (and you shouldn’t) you can run
gulp as an npm script in
"gulp": "gulp". Now running
npm run gulp taskname will be the same as running
After that we’ll need to create a file named
gulpfile.js. This will be our toolkit’s main file, as Gulp expects and reads this in the current working directory any time we run
gulp from the command line.
gulpfile.js, require our dependencies:
And our Sass compilation task:
This is very close to what we use for our themes. Now running
gulp compile:sass (or
npm run gulp compile:sass) in the command line at our project’s root will handle all our Sass compilation. Let’s go over the key features:
This is the key ingredient of our task, enabled by the gulp-sass module. It’s where Sass actually gets compiled to CSS. We properly indent and output in expanded style so that we meet our readability requirements.
Autoprefixer is such an amazing tool. As the name implies, it automatically adds browser/vendor prefixes to our code for just the browser versions we’ve specified (in this particular example it would be the last 2 versions of all browsers). This allows us to freely write CSS without ever having to remember to add prefixes by ourselves (e.g. on flexbox) while maintaining support for older browsers that require them.
One more benefit is that when we decide to drop support for a particular browser (or as browsers advance in versions), all we need to do is remove that browser from our
gulpfile, recompile the CSS, and all relevant prefixed statements will be gone!
Another God-sent tool:
gulp-group-css-media-queries. To understand why we need it let’s see how we usually write CSS Media Queries with Sass:
Nesting Media Queries under their related elements is very handy, it allows us to encapsulate every style under each selector. The problem with this approach is that it gets compiled into:
Which has a few problems. Mainly it creates a new Media Query block for each declaration, increasing filesize and impacting readability significantly.
group-css-media-queries we avoid all these issues. The plugin simply traverses our code and groups together all matching Media Queries at the end of our stylesheet, so that the output would become:
Efficient, and much cleaner!
Our final line, streams the results to browserSync, which we’ll cover right away, after we create a new task which will start watching our Sass files for any changes and immediately compile and stream them to the browser.
This task actually does a bit more: First it initializes a
browserSync server instance. BrowserSync is another amazing tool with a lot of uses.
In this particular scenario we use it as a proxy to our local WordPress development server (which in this case is under
http://localhost/wordpress-installation — replace this with your own local dev URL). That way we can automatically stream all file changes to
browserSync which will handle reloading the page for us, or in the case of CSS, it’ll directly and transparently inject the new styles without even reloading! A huge boost in productivity all around.
Then we simply watch all Sass files for changes with Gulp’s internal API (
gulp.watch), triggering the
compile:sass task (which then streams the changes to
browserSync, which then injects the styles).
And to conclude, adding a gulp default task:
Now any time we run just
watch:sass task will trigger since we’ve declared it as the default one.
Bonus: Linting our styles with
No development workflow would be complete without a linter. Linting code has huge benefits, it prevents mistakes and helps maintain a concise and uniform codebase. Adding linting to the above workflow is as simple as creating a new task. Let’s first install the required dependency:
And append the lint task in our
Notice that we’ve also made the new
lint:sass task running at various parts of our workflow. Now every time we either compile Sass files or watch for changes the linter will automatically trigger.
Note: You can use the sample sass-lint config file to create your own linting rules.
And the full
Do you use a CSS preprocessor in your WordPress projects? How about Gulp? Let us know of your experiences, tips, or tricks in the comments below.