Stepping away from Sass
Published on
My latest site redesign and why I left out Sass and media queries in favour of native CSS grid, calc, viewport units and custom properties.
Published on
My latest site redesign and why I left out Sass and media queries in favour of native CSS grid, calc, viewport units and custom properties.
Published on
I try to rebuild or redesign my website at least once every year, it's a great way to keep up to date with HTML and CSS advances as well as workflows and site generators. I launched the latest version last month moving from Jekyll and Github pages to Eleventy and Netlify.
I also unintentionally, (at least at first) removed all traces of Sass from my codebase. This was not something I set out to do but the more I looked at my old Sass files the more I questioned whether it was adding value to my site, or just an extra level of complexity and dependency. CSS has evolved over recent years and the problems that lead me to Sass in the first place seem to be less of an issue today.
The knock on effect of this was removing media queries. As I moved towards some of the more modern features of CSS the need to target specific screen sizes with unique code was removed.
When I first starting to learn about Sass (around 5 or 6 years ago) I was skeptical, but as I built more and more responsive websites I began to realise how much time I could save by having reusable pieces of logic from Sass functions and mixins. It also became apparent that as devices, viewports and themes changed using variables made implementing updates much easier to handle.
Things I used Sass for:
Layout has been a longstanding source of frustration with CSS. This coupled with a move to fluid or responsive layouts was a key factor in my initial decision to use Sass to create a CSS grid.
I can still remember my first attempt at building a responsive grid layout in CSS, it involved creating a set of utility classes for each column and then polluting the markup with non semantic class names like col-span-1 and col-span-4.
.col-span-3 {
float: left;
width: 24%;
margin-left: 1%;
}
.col-span-4 {
float: left;
width: 32.3%;
margin-left: 1%;
}
.col-span-5 {
float: left;
width: 40.6%;
margin-left: 1%;
}
By using a Sass mixin paired with variables I was able to remove utility classes like the ones above, and also create more flexible layouts by changing the $gridColumns variable.
My first grid mixin:
@mixin grid($colSpan, $gridColumns: 12, $margin: 1%,) {
$unitWidth: $gridColumns / $colSpan;
float:left;
width: (100 - $unitWidth * $margin) / $unitWidth;
margin: 0 $margin/2;
}
Implemented like this:
.sidebar {
@include grid(3);
}
.main-content {
@include grid(9);
}
@media only screen and (max-width: 480px) {
.sidebar {
@include grid(12);
}
.main-content {
@include grid(12);
}
}
The introduction of CSS Grid removes the need for any of this, you no longer need to build a grid system with utility classes, in Sass or any other processor. Rachel Andrew says it best here...
The code below creates a responsive layout that adapts based on the min and max width of the content, not on pre set device sizes.
.project {
display: grid;
grid-template-columns: repeat( auto-fill, minmax(12em, 1fr) );
grid-gap: 1em;
}
Moving from a Sass based grid to CSS grid was a relatively pain free experience, not only did it reduce my dependency on Sass it also allowed me to create a much flexible codebase, opened up wider design possibilities and allowed me to structure the site around content not media queries.
The obvious downside to switching to native CSS for my layout is the limited browser support, or so I thought. Grid is currently supported in most modern browsers and with prefixes, IE11 and IE10 too. auto-fill and auto-fit have less support, but this can be easily rectified with a feature query.
A variable is a value that is likely to change, in terms of CSS a variable is something I didn't know I needed until I had it. Nowadays most of my projects follow the ITCSS methodology and so start off with a settings file containing the project variables. Usually I set variables up for fonts, colours and media queries.
My old Sass set up:
/* COLORS */
$colors: (
"black": #2a2a2a,
"white": #fff,
"grey-light": #ccc7c3,
"grey-dark": #2a2a2a,
"accent": #ffa600,
"off-white": #f3f3f3,
"sky-blue": #ccf2ff
);
/* BREAKPOINTS */
$breakpoints: (
"break-mobile": 290px,
"break-phablet": 480px,
"break-tablet": 768px,
"break-desktop": 1020px,
"break-wide": 1280px
);
/* TYPOGRAPHY */
$font-stack: (
decorative: #{'oswald', Helvetica, sans-serif},
general: #{'Helvetica Neue', Helvetica, Arial, sans-serif}
);
Using variables or maps like this allowed me to make site wide changes quickly and easily. It also helps prevent the build up of multiple shades, colour variations and anomalies common in large code bases, particularly for hover states, shadows, borders etc.
For example:
.button {
background-color: #4CAF50; /* Green */
}
.button:hover {
background-color: #3F8C42; /* Dark Green */
}
.button:active {
background-color: #266528; /* Darker Green */
}
Can be rewritten using Sass variables and colour functions to:
$button-colour: #4CAF50;
.button {
background-color: $button-colour;
}
.button:hover {
background-color: darken($button-colour, 20%);
}
.button:active {
background-color: darken($button-colour, 50%);
}
CSS custom properties can do more than just replace pre processor variables, they have the added bonus of being updated dynamically (instead of compiled at build). This allows values to be altered at run time with Javascript and to be scoped without the need for mixins and functions to outwit the cascade.
:root {
--button-color: #4CAF50;
}
.button {
background-color: var(--button-color);
}
header
.button {
--button-color: #000000;
background-color: var(--button-color);
}
Colour manipulations like those available in Sass are also available in native CSS using the color-mod function.
:root {
--button-color: #4CAF50;
}
.button:hover {
color: color-mod(var(--button-color) tint(50%));
}
Unfortunately this is still at public working draft stage so for the time being I decided to remove effects like this and replace them with full colour changes and text effects.
.button {
background: var(--colour-dark);
}
.button:hover {
background: var(--colour-bright);
text-decoration: underline;
}
However if you really want to use them there are a few PostCSS workarounds about including postcss-color-mod-function.
Finally typography, in previous code bases I was using Sass to create responsive typography and spacing. Mixins like the one below allowed me to easily automate changes for different screen sizes and devices.
@mixin typography($size) {
font-size: $size;
@include mq(break-desktop) {
font-size: $size * 1.2;
}
}
Today I use calc and viewport units to perform these calculations in native CSS instead.
:root {
--font-size: calc(18px + 0.25vw)
}
body {
font-size: var(--font-size);
}
CSS is moving towards a more content lead spec, as well as CSS grid there is flexbox and sizing properties like min-content, max-content and fit-content as well as future developments like Subgrid from CSS Grid Layout Module Level 2.
All of these features make native CSS much more attractive to work with.
These are webmentions via the IndieWeb and webmention.io.