CSS Custom Properties (aka CSS Variables) Don't Make CSS Preprocessors Obsolete
NOTE: This post is more of an invitation for conversation than it is a hard statement. I am confused about this topic; and, I would love to hear other developer's point of view on the matter.
As of late, I've heard a number of thought-leaders in the Web Development community talk about CSS custom properties as the technology that makes CSS preprocessors "obsolete." Now, I love CSS custom properties (often referred to as "CSS Variables") as much as the next developer; and, they will certainly make theming components a lot easier; but, I don't understand what CSS custom properties have to do with the obsolescence of CSS preprocessors. I use LESS CSS - a simple but powerful CSS preprocessor - every day; and, I have no intention of giving it up, even when all the major browsers provide support for CSS custom properties (or, in other words, when IE11 finally dies).
If all you do with your CSS preprocessor is assign and interpolate dynamic values, then CSS custom properties will make that use-case obsolete. But, I use LESS CSS for other things. In fact, I almost never use variables in my LESS. Primarily, I love the way that LESS CSS facilitates nesting of selectors and the generation of hierarchical BEM-style (Block Element Modifier) class names.
To see what I mean, let's consider a "Contact" Component that is representative of a simple Angular component with unidirectional data flow:
First, let's look at the component template, which would be contained within a custom element tag:
<div class="layout">
<div class="layout__avatar">
<img [src]="contact.avatarUrl" class="avatar" />
</div>
<div class="layout__details">
<div class="name">
{{ contact.name }}
</div>
<div class="email">
{{ contact.email }}
</div>
<div class="actions">
<a href="#" class="action">Favorite</a>
<a href="#" class="action">Edit</a>
<a href="#" class="action">Archive</a>
<a href="#" class="action action--delete">Delete</a>
</div>
</div>
</div>
As you can see, it's pretty straightforward. You may not agree with all of my naming choices or my structure; but, I think it's clear to see what's going on. There are a few embedded elements concerned with layout. And, a few elements that are concerned with data. I think it's safe to say that this could easily be an atomic component (ie, one that is not composed of other, smaller components).
Now, let's look at the LESS CSS that styles this component. Remember, I use Angular 7. So, I'm actually using CSS modules - a "CSS in JS" technique that programmatically scopes CSS selectors by injecting HTML attribute at runtime. Of course, Angular takes care of all of that for me (using simulated encapsulation); so, for the sake of this demo, just assume that the generated CSS won't leak outside of my Contact component's "shadow DOM":
:host {
background-color: #fafafa ;
border: 2px solid #cccccc ;
border-radius: 4px 4px 4px 4px ;
box-sizing: border-box ;
display: inline-block ;
padding: 10px 10px 10px 10px ;
position: relative ;
width: 300px ;
&:hover {
background-color: #faf8f8 ;
border-color: #ff3366 ;
}
// Small visual accent on the box - DON'T REMOVE. The designer was extremely
// adamant that this element remain in the interface (despite the fact that it
// is hardly visible).
&:after {
border: 2px solid #dadada ;
border-radius: 0px 3px 0px 0px ;
border-width: 2px 2px 0px 0px ;
content: "" ;
height: 5px ;
position: absolute ;
right: 2px ;
top: 2px ;
width: 8px ;
}
// -- variations.
&( .active ) { // :host(.active)
border-color: gold ;
&:hover {
border-color: goldenrod ;
}
}
}
.layout {
display: flex ;
&__avatar {
flex: 0 0 auto ;
margin-right: 13px ;
width: 65px ;
}
&__details {
flex: 1 1 auto ;
}
}
.avatar {
border-radius: 100% 100% 100% 100% ;
display: block ;
width: 100% ;
}
.name {
font-family: sans-serif ;
font-size: 18px ;
font-weight: 600 ;
line-height: 22px ;
margin-bottom: 2px ;
padding-top: 5px ;
}
.email {
color: #666666 ;
font-size: 14px ;
line-height: 19px ;
}
.actions {
display: flex ;
font-size: 14px ;
margin-top: 13px ;
}
.action {
color: #666666 ;
margin-left: 10px ;
opacity: 0.7 ;
text-transform: lowercase ;
&:first-child {
margin-left: 0px ;
}
&:hover {
opacity: 1.0 ;
}
// -- variations.
&--delete {
color: red ;
margin-left: auto ;
}
}
What you can see here is that I love to use the LESS CSS Parent Selector ("&") in order to build-up compound class names. Part of this is influenced by my enjoyment of BEM (Block Element Modifier); but, much of it is also due to the fact that many pseudo-selectors in CSS, like ":after" and ":first-child", modify existing selectors instead of relying on unique class names. I also love to use JavaScript-style comments, which are not supported in core CSS.
What you don't see here is any reference to dynamic values. There's nothing - that I can see - in this code that would be made redundant by the use of CSS custom properties. If someone see something, please tell me.
To be clear, I think CSS custom properties are awesome. And, I have every intention of using them more heavily in future development efforts. But, for my daily uses cases, there's nothing about CSS custom properties that makes CSS preprocessors, like LESS CSS, obsolete. I say all this in an attempt to sacrifice myself on the alter of dignity - to say publicly, "I don't get it", in case there are other developers who are also confused about the recent prognostication on such matters. You can be confused with me - you are not alone - you are in the company of fools.
Want to use code from this post? Check out the license.
Reader Comments