Using preprocessors such as Sass, LESS and Stylus, has always given developers more control over their stylesheets, but native CSS is gradually closing the gap. CSS features such as variables, calc and mixins are just the tip of the iceberg; let’s review what preprocessors are currently helping us with, and how native CSS logic is going to change how we do things.

The Age of Preprocessors
Language abstractions such as Sass, LESS and Stylus blew up developers’ worlds by giving them variables, mixins, functions, extends and much more. These preprocessors filled in missing features which CSS wasn’t able to provide. However, CSS should no longer be thought of as “logic-less” without the presence of intellect. With CSS on the move to refine itself we’re already catching glimpses of the future; a future that will compete with preprocessors.
1. Mixin It Up
Typically we associate “mixins” with preprocessors; groups of CSS declarations which you can reuse throughout a project. A mixin can be used as a standalone helper, or you can pass values as arguments to make it extra flexible.
Here’s a Sass @mixin
example called font-size
.
@mixin font-size($size, $base) { font-size: $size; // fallback for old browsers font-size: ($size / $base) * 1rem; }
The above mixin will accept arguments for $size
, $base
and is used in an @include
declaration with the ability to adjust arguments depending on the context.
/* Sass Call */ body { @include font-size(14, 16); } /* CSS output */ body { font-size: 14px; font-size: 0.875rem; }
The result is a rem
based value for font-size
with a px
fallback for browsers that don’t support rem
. Preprocessor mixins like this have saved developers countless hours over the years.
Native CSS mixins are currently an editors draft, but also have a working implementation in Chrome. If you’ve already played with CSS variables the following snippet will look quite familiar.
:root { --pink-theme: { background: #F64778; } }
Beware that the code above will most definitely make your syntax highlighter go bonkers. This way of writing a CSS mixin uses a new at-rule called @apply
similar to what we know in Sass as @include
.
body { @apply --pink-theme; }
Just as we’re familiar with Sass using @include
we could eventually have @apply
for CSS!

You can try this experiment for yourself within Chrome by enabling a flag under chrome://flags/#enable-experimental-web-platform-features
.
2. Do the Math
Remember when preprocessors were the only style tools capable of mathematical gymnastics? Well that isn’t the case anymore. With calc()
we can take those pesky numbers and mutate them into new values based on your desired arithmetic.
nav { margin: calc(1rem - 2px) calc(1rem - 1px); }
This is the beauty of calc()
; it finally extends CSS powers into the stratosphere. Prefer addition? Subtraction? Division? Multiplication? Calc can handle all that and more.
If you’d like to read more about calc()
the W3C spec has everything you’ll need to make you drowsy and happy at the same time. Browser support is also rock-solid according to Can I Use.

3. Pass the Variable
Native variables for CSS are finally here. They’re a real and tangible option for developers, though it took some time to learn from preprocessors.
Here’s what Sass variable syntax looks like:
$spacing-unit: 20px; main { margin: $spacing-unit; padding: $spacing-unit; }
Sass variables are denoted with a dollar $
sign, but in CSS they look a bit different:
:root { --primary-color: skyblue; } nav.primary { background: var(--primary-color); }
CSS variables are denoted with a double hyphen --
and are typically placed inside :root
for global access; although their scope can be tightened by placing them within specific selector declarations.
div { color: var(--my-var, red); }
Variables can even accept a fallback value if they aren’t yet defined, as is the case with the example above. Browser support isn’t bad either, with Edge showing partial support. The spec is also in the candidate recommendation stage for your reading pleasure.

4. Nest Building
Nesting is a feature in many preprocessors which allows you place selectors inside an existing declaration. Typically, nesting in Sass looks something like this:
ul { margin: 20px auto; li { font-size: 12px; a { text-decoration: none; } } }
Nesting can become unwieldily and get you wrapped up into a ton of trouble, resulting in impossibly long selector chains. For this reason it’s advisable to stick to the Inception Rule and keep nesting to no more than three or four levels deep.
While nesting can be dangerous, it can also be handy if you take the time to be mindful. Here’s a sneak peek into how it could eventually looks for native CSS:
/* CSS Nesting */ nav { color: #222;&.primary { background: maroon; } } /* Result */ nav { color: #222; } nav.primary { background: maroon; }
Just as we’re accustomed to with our preprocessor allies, native CSS nesting lends us the same principles, but without the need to compile the language. There’s a draft spec by Tab Atkins on this very feature for Native CSS nesting.
5. Extend Rule
“Extends” are another way to pass properties and values around, sharing them between declarations. In Sass we’ve become used to applying the following syntax:
.message { border: 1px solid #ccc; padding: 10px; color: #333; } .success { @extend .message; border-color: green; } .error { @extend .message; border-color: red; } .warning { @extend .message; border-color: yellow; }
You can see that we start by defining styles for .message
, then offer three variants with different border-colors
. Each variant first extends.message
, thereby inheriting all its style rules before changing the border color.
Identical syntax to the example above is what’s being drafted by Tab Atkins as another potential spec for native CSS. Whether or not you agree with extends (a feature whose benefits are hotly debated) it’s great to see CSS caretakers embrace ideas brought forth by preprocessors.
6. Your True Colors
If you ever find yourself using preprocessor color manipulation functions, you’ll appreciate this functionality in native CSS. The color-mod() function takes an existing color and applies zero or more “color adjusters” which specify how to manipulate the end result.
nav { background: color-mod(#79d3e2 hue(360) saturation(100%)); }
Development is in the early stages, and while there are polyfills available syntax changes frequently (the current color-mod
used to be color
for example).
Tyler Gaw made a really neat tool (colorme.io) that lets you experiment with all the possible color adjusters available.

Spec for the color-mod() function is currently in draft mode through the CSS Working Group.
Closing Thoughts
In the same way that jQuery helped make the Web better, so indeed have preprocessors when it comes to CSS. Languages like Sass have helped pave the way for new ideas and approaches not yet considered by the CSS spec authors.
I hope the new features we’ve talked about inspire you to use them in your own work; I encourage you to consider using native functionality over a preprocessor whenever possible!