Today we're going to look at something that hasn't yet been incorporated into the official CSS specification but could change the way we write CSS. I am, of course, talking about Functions and Mixins.
Here's the TL;DR, CSS Functions and Mixin add a way to capture and reuse CSS logic without the use of pre-processors. This allows DRY
principles to be executed in CSS without the need of utility classes.
Let's dive in and see how we got here and what these changes may mean in practice.
CSS pre-processors
Traditionally CSS lacked features such as variables, nesting, mixins, and functions. This was frustrating for Developers as it often led to CSS quickly becoming complex and cumbersome. In an attempt to make code easier and less repetitive CSS pre-processors were born. You would write CSS in the format the pre-processor understood and, at build time, you'd have some nice CSS. The most common pre-processors these days are Sass, Less, and Stylus. Any examples I give going forward will be about Sass as that's what I'm most familiar with.
Pre-processors were not without their problems though; for one, the browser can't understand them, you need a build/compile step before you can see what they're doing. For another, each pre-processor has a slightly different syntax for devs to learn and master.
Perhaps as an attempt to remedy this or perhaps just a way to improve vanilla DX (Developer eXperience) the CSS spec began to incorporate aspects of Pre-processors with variables
and more recently nesting
.
Sass @function
Functions allow you to define complex operations on SassScript values that you can re-use throughout your stylesheet. They make it easy to abstract out common formulas and behaviours in a readable way.
Functions in Sass allows a developer to calculate a single value. This will be calculated at build time so can not include vanilla CSS Variables.
Sass @mixin
Mixins allow you to define styles that can be re-used throughout your stylesheet. They make it easy to avoid using non-semantic classes like .float-left, and to distribute collections of styles in libraries.
Mixins in Sass allows a developer to @include
a whole block of css (property and value pairs). It also allows you to pass in arguments that can modify the block. Though, again as this is calculated at build time vanilla CSS Variables aren't available.
Examples and use cases
Let's suppose we have a design system where we have buttons that can be different colours, each button should look the same apart from the different background colour, the hover and active states are slightly darker variants of their base colour.
First let's make a function that will mix any colour with black at a set percentage.
@function --darken(--base, --percent) {
@return color-mix(in srgb, var(--base), #000 var(--percent));
}
Now that we have a function that can darken our base colours let's make a mixin that will make our default button style with the hover and active states, we can use nesting in the mixin to make this easier.
You'll notice the --color
argument has a default colour which will be used if one isn't supplied.
@mixin --button(--color: #174D7C) {
background-color: var(--color);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
&:hover {
background-color: --darken(var(--color), 5%);
}
&:active {
background-color: --darken(var(--color), 10%);
}
}
Finally let's make three buttons one using the default colour then a green and also an orange one.
.primary-btn {
@apply --button
}
.green-btn {
@apply --button(#6F9F9C)
}
.orange-btn {
@apply --button(#FE5F55)
}
And just like that we have 3 beautiful buttons with the bulk of our CSS only being written once and everything being calculated at run time. Meaning we get full reign of native CSS variables.
Fin
Just when we think the faucet of CSS changes has been shut off something huge like this comes our way. Whilst it will take a while to be finalised into spec and then a while more roll out to browsers the possibilities are simply mind boggling.
Thanks so much for reading. If you'd like to connect with me outside of Dev here are my twitter and linkedin come say hi 😊.