“All things old become new again.” – Harley King
The web has a way of getting back to its roots. Even as web standards have evolved and advanced over time, developers have created tools and techniques that push beyond the capabilities of the browser itself. Over time, the development community will often re-evaluate these tools, absorbing the good parts into the languages’ standards and best practices, and discarding the not-so-good stuff.
This phenomenon happened again more recently with the rise of responsive web design, which in essence is a return to the natural fluidity of the web after the industry’s decades-long love affair with fixed-width layouts. To paraphrase Jeremy Keith, the web was always responsive, right up until developers and designers came along and broke it. In the case of responsive design, the primary technological advancement — media queries — was actually just a small piece of the puzzle. The change that really mattered was the development community’s shifting perception of how a website should be conceptualized and built.
Preprocessors Perpetuate the Problem (Say That Five Times Fast)
CSS has always lacked certain programmatic features that allow for more efficient, reusable, and maintainable code. Preprocessors like SASS and LESS were born to extend CSS and provide conveniences like variables, functions, nesting, and inline importing. These tools added great value to the language and continue to enjoy immense popularity in the web development community.
The problem with all of this is that we’ve slowly been putting more and more layers of abstraction between real front-end code and us. SASS is not CSS. It’s a separate language, with a different syntax, which must be compiled into CSS by a build tool before it can be served to the browser. These build times can get progressively longer on larger projects, especially if you’re using the notoriously slower Ruby version of SASS.
Is it finally time to reverse direction and get back to writing real code? Our development team decided to explore this topic.
Goodbye, Preprocessors; Hello, Postprocessors and Transpilers
First, let’s discuss the difference between a preprocessor and a postprocessor.
Preprocessors like SASS force you to write your code using a different language and then compile it into standard CSS. Postprocessors, in contrast, allow developers to write real, powerful, bleeding-edge CSS and then process and transform that code into output that will work in today’s browsers (or, with the change of a few configuration settings, yesterday’s or even tomorrow’s browsers). Aside from the fact that postprocessors let you write CSS code that isn’t even officially CSS yet, there’s no new syntax to learn, and you can solve many of the same problems that preprocessors also solve.
Improving Processes Without Sacrificing Functionality
Our team’s first venture into the world of postprocessors was minor, but eye opening. We put our collective baby toe in the water and swapped out Compass’s CSS3 mixins for Autoprefixer, a PostCSS plugin that adds vendor prefixes to CSS rules based on current browser usage statistics. This was a relatively easy change for us to implement on a new project. Instead of calling a SASS mixin to use a not-yet-fully-supported CSS property, we instead just wrote the CSS property as if all browsers already supported it.
This meant no memorizing prefixes, and no function calls using another language. Autoprefixer swoops in at build time to analyze your CSS and insert vendor prefixes where needed. It was surprisingly freeing to write in standards-compliant, future-proof CSS again. We were coding for an idealized world of full browser support, and Autoprefixer was quietly taking care of the real-world hassles for us in the background.
At that time, we didn’t really know much about PostCSS. Autoprefixer was just a nice little tool slapped onto our build process that let us more easily write CSS3 rules, but we were still using SASS for custom mixins, variables and nesting. We soon discovered that Autoprefixer was just one of many postprocessing plugins living within the PostCSS ecosystem.
We’re not going to claim that PostCSS can approximate everything you might already be doing in SASS. That said, considering its relatively short existence, we were impressed by just how mature and full-featured the software and its accompanying ecosystem of add-ons already are.
The PostCSS build process we’ve come up with works great with Grunt, our existing task runner, and includes the following features:
- Partials and globbing: Being able to work in small, component-specific files is one of SASS’s best features, and not being able to do the same with PostCSS would’ve been an instant deal-breaker. Luckily, postcss-import handles partials with ease. File globbing – the automatic importing of partials based on a directory pattern – is a love/hate topic in the SASS world, but if you’re a fan, v1.2.0 and the newer grunt-sass-globbing works equally well with PostCSS.
- Nesting: Much like partials, nesting properties in SASS is a must-have (even though it’s recommend to use them sparingly). We were able to replicate this functionality using postcss-nested.
- Variables: We leverage postcss-custom-properties, which allows us to write CSS variables (officially known as “custom properties”) straight out of the W3C’s working draft. Honestly, this took the most getting used to, as the syntax (going from $variablename in SASS to var(–variablename) in CSS) is pretty clunky. If you just can’t give up that handy SASS dollar-sign syntax, you could always use postcss-simple-vars instead, but we’ve chosen to write our code in what will someday be the recommended, standards-compliant syntax.
- Color functions: Unfortunately, you’ll lose SASS’s convenient “lighten” and “darken” functions. But through the use of postcss-color, we’re able to keep the same functionality, while also following the W3C’s proposed CSS Color Module spec. Again, the syntax takes some getting used to, but the functionality works great (and the code we’re writing will someday be standards-compliant).
- Math: Although not nearly as powerful as Ruby SASS’s built-in arithmetic abilities, postcss-calc does help precalculate CSS calc() rules, which takes a little bit of unnecessary processing away from your users’ browsers.
- Vendor prefixes: As we mentioned before, the wonderful Autoprefixer doesn’t just write our vendor prefixes for us; it does it automatically. It conforms to the browser support settings we define in a single config file – which can be changed and recompiled on the fly – and unlike SASS, it doesn’t require us as developers to write special function calls or even think about which CSS3 properties are supported by which browsers.
Where Do We Go From Here?
As a team, DEG’s UI developers always try to find a balance. We’re constantly pushing to improve our workflows and processes, but we’re also keenly aware of the fact that chasing the latest UI and development shiny objects can be fruitless and exhausting. Rethinking our development process at such a fundamental level isn’t something we’ve taken lightly.
There’s bound to be some turbulence as we learn more about it, but we’re cautiously optimistic of and excited about our reimagined process. In a field where “the next best thing” can change in an instant, getting back to writing “real” code feels more genuine and pragmatic than any process change we’ve made in a long time.