Using CSS Variables To Write Truly Modular CSS

With CSS Variables hitting the majority of browsers, a question has started to nag me. Can I write modular, reusable CSS without the help of SASS? Giving up mixins, extends, and nesting (the dark ages) I decided to give it a shot.

Why?

  1. Using SASS, I’ve always felt locked into the code base. I need a gulp task just to compile my styles for a simple color change. While I understand why the extra step is there, it doesn’t feel very modular.
  2. With companies I’ve worked with in the past, there are usually multiple projects with similar needs. There’s usually a global variables file, and while it makes sense to have it, your modules are now dependent on that global file. If your global variables change from project to project (which seemed to happen all the time), you won’t be able to copy over modules that aren’t broken until your global variables are matching what’s in your modules (or visa versa). To me, this is another dependency that can now be solved with CSS variables.

My solution is to use CSS variables with fallback values. If the global variable doesn’t exist, we go to a default value, or in the code below, an error color of dark red.

Global Variables

:root {
--primary-color: #FFF;
--secondary-color: #333;
--accent-color: orange;

--primary-font: 'Roboto Condensed';

--header-bg: var(--secondary-color);
--header-height: 100px;
--header-mobile-height: 75px;

--nav-bg: var(--secondary-color);
--nav-border-color: var(--primary-color);
--nav-mobile-spacing: var(--header-mobile-height);
}

Header Module

.header {
--background: var(--header-bg, darkred);
--mobile-height: var(--header-mobile-height, 75px);
align-items: center;
background: var(--background);
display: grid;
grid-template-columns: 0.1fr auto 1fr 0.1fr;
height: var(--mobile-height);
justify-items: end;
transition: height 0.25s;
}
@media(min-width: 650px) {
.header {
--height: var(--header-height, 100px);
height: var(--height);
}
}

We have new variables declared inside the header class ( — background, —mobile-height, — height) pulling in variables from our global root as well as a static fallback value. I chose dark red because if global variables are missing or named differently, I want it to stand out like a neon sign when I load the page. That said, the fallback could also be your default styling for that module, so if all else fails, you’re not left with a broken component. You can copy the above two sections of code (or just the header section of code) and it will function exactly as intended. No dependency on SASS, task runners, or global/external variables.


Am I going to be writing vanilla CSS exclusively going forward? Not yet, but I think we could get there. With modular, reusable components being a big focus in the industry (React, Angular, etc.), I think CSS variables are a significant step towards that goal.

(You can see the full working example of the above code here. Try deleting the global variables and see what happens.)