Using Custom Properties instead of Utility Classes

Update 2022 : A newer version of this code can be found here

If you write CSS for a living you might have a strong opinion as to whether utility classes are a good or a bad thing. If you use something like the popular Tailwind framework your answer to this will be that they’re a good thing, but if you’re averse to using frameworks your CSS may use them far more sparingly, if at all.

What about Custom Properties? Have you started using these widely in your websites? Do they exist solely within your CSS files, or do you dot them through your HTML to adjust individual components?

With this in mind, I wonder what your thoughts might be on the following:

Honestly, I’m not sure how I feel about it myself.

I’ve been using utility classes for adjusting margin and padding for some time, and always felt that it led to quite a bit of underused code (actually it’s 4kb uncompressed). But it’s never been enough of a worry to address it, until now.

.mtx--10{margin-top:.71429em}.mbx--10{margin-bottom:.71429em}.ptx--10{padding-top:.71429em}.pbx--10{padding-bottom:.71429em}.mtx--20{margin-top:1.42857em}.mbx--20{margin-bottom:1.42857em}.ptx--20{padding-top:1.42857em}.pbx--20{padding-bottom:1.42857em}.mtx--30{margin-top:2.14286em}.mbx--30{margin-bottom:2.14286em}.ptx--30{padding-top:2.14286em}.pbx--30{padding-bottom:2.14286em}.mtx--40{margin-top:2.85714em}.mbx--40{margin-bottom:2.85714em}.ptx--40{padding-top:2.85714em}.pbx--40{padding-bottom:2.85714em}.mtx--50{margin-top:3.57143em}.mbx--50{margin-bottom:3.57143em}.ptx--50{padding-top:3.57143em}.pbx--50{padding-bottom:3.57143em}.mtx--60{margin-top:4.28571em}.mbx--60{margin-bottom:4.28571em}.ptx--60{padding-top:4.28571em}.pbx--60{padding-bottom:4.28571em}.mtx--70{margin-top:5em}.mbx--70{margin-bottom:5em}.ptx--70{padding-top:5em}.pbx--70{padding-bottom:5em}.mtx--80{margin-top:5.71429em}.mbx--80{margin-bottom:5.71429em}.ptx--80{padding-top:5.71429em}.pbx--80{padding-bottom:5.71429em}.mtx--90{margin-top:6.42857em}.mbx--90{margin-bottom:6.42857em}.ptx--90{padding-top:6.42857em}.pbx--90{padding-bottom:6.42857em}.mt--10{margin-top:.71429vw}.mb--10{margin-bottom:.71429vw}.pt--10{padding-top:.71429vw}.pb--10{padding-bottom:.71429vw}.mt--20{margin-top:1.42857vw}.mb--20{margin-bottom:1.42857vw}.pt--20{padding-top:1.42857vw}.pb--20{padding-bottom:1.42857vw}.mt--30{margin-top:2.14286vw}.mb--30{margin-bottom:2.14286vw}.pt--30{padding-top:2.14286vw}.pb--30{padding-bottom:2.14286vw}.mt--40{margin-top:2.85714vw}.mb--40{margin-bottom:2.85714vw}.pt--40{padding-top:2.85714vw}.pb--40{padding-bottom:2.85714vw}.mt--50{margin-top:3.57143vw}.mb--50{margin-bottom:3.57143vw}.pt--50{padding-top:3.57143vw}.pb--50{padding-bottom:3.57143vw}.mt--60{margin-top:4.28571vw}.mb--60{margin-bottom:4.28571vw}.pt--60{padding-top:4.28571vw}.pb--60{padding-bottom:4.28571vw}.mt--70{margin-top:5vw}.mb--70{margin-bottom:5vw}.pt--70{padding-top:5vw}.pb--70{padding-bottom:5vw}.mt--80{margin-top:5.71429vw}.mb--80{margin-bottom:5.71429vw}.pt--80{padding-top:5.71429vw}.pb--80{padding-bottom:5.71429vw}.mt--90{margin-top:6.42857vw}.mb--90{margin-bottom:6.42857vw}.pt--90{padding-top:6.42857vw}.pb--90{padding-bottom:6.42857vw}.mt--100{margin-top:7.14286vw}.mb--100{margin-bottom:7.14286vw}.pt--100{padding-top:7.14286vw}.pb--100{padding-bottom:7.14286vw}.mt--200{margin-top:14.28571vw}.mb--200{margin-bottom:14.28571vw}.pt--200{padding-top:14.28571vw}.pb--200{padding-bottom:14.28571vw}@media screen and (min-width: 1400px){.mt--10{margin-top:10px}.mb--10{margin-bottom:10px}.pt--10{padding-top:10px}.pb--10{padding-bottom:10px}.mt--20{margin-top:20px}.mb--20{margin-bottom:20px}.pt--20{padding-top:20px}.pb--20{padding-bottom:20px}.mt--30{margin-top:30px}.mb--30{margin-bottom:30px}.pt--30{padding-top:30px}.pb--30{padding-bottom:30px}.mt--40{margin-top:40px}.mb--40{margin-bottom:40px}.pt--40{padding-top:40px}.pb--40{padding-bottom:40px}.mt--50{margin-top:50px}.mb--50{margin-bottom:50px}.pt--50{padding-top:50px}.pb--50{padding-bottom:50px}.mt--60{margin-top:60px}.mb--60{margin-bottom:60px}.pt--60{padding-top:60px}.pb--60{padding-bottom:60px}.mt--70{margin-top:70px}.mb--70{margin-bottom:70px}.pt--70{padding-top:70px}.pb--70{padding-bottom:70px}.mt--80{margin-top:80px}.mb--80{margin-bottom:80px}.pt--80{padding-top:80px}.pb--80{padding-bottom:80px}.mt--90{margin-top:90px}.mb--90{margin-bottom:90px}.pt--90{padding-top:90px}.pb--90{padding-bottom:90px}.mt--100{margin-top:100px}.mb--100{margin-bottom:100px}.pt--100{padding-top:100px}.pb--100{padding-bottom:100px}.mt--200{margin-top:200px}.mb--200{margin-bottom:200px}.pt--200{padding-top:200px}.pb--200{padding-bottom:200px}}

Having used the classes as the currently exist (above) I found that they were a bit useless in certain scenarios. Whilst I use media queries to set max values, the fact that my main utility classes relied on viewport units resulted in some of the smaller sizes completely disappearing on mobile screens.

Clamp()?

Having begun to use clamp() more widely in my production code I knew that this would solve my issue of requiring minimum values as well as make media queries redundant for the max values.

.mt--20 {margin-top:clamp(10px,1.42857vw,20px);}
.mt--30 {margin-top:clamp(15px,2.14286vw,30px);}
.mt--40 {margin-top:clamp(20px,2.85714vw,40px);}

Setting my minimum value as half of the maximum seemed like a suitable choice for most instances, though it could be argued that using em’s rather than px would be far more versatile when also using fluid typography.

If I do choose to set utility classes this way, that will certainly be something I’d look to try. But as I looked at this code and how I’d still be stuck with classes I may not use, I wondered if Custom Properties offered an alternative?

Enter Custom Properties

With Custom Properties I knew there was a way I could define a value in my HTML that would then be accessible in an external CSS file as a way of adjusting components individually.

<style>
.box {padding-top:var(--padding-top);}
</style>

<div class="box" style="--padding-top:20px;">Text</div>

This means that rather than have multiple utility classes I can have one that controls the margin & padding for any element I might otherwise use a utility class. All I need to do is set the class as .box (in this instance) and include the Custom Property within the style attribute.

A good idea?

Though this cleans up my CSS, removing a load of redundant classes, I’m not sure if this an appropriate use of Custom Properties. Am I making more of a mess of my HTML? And is this way any better than using utility classes, or even just specifying inline styles in a traditional way?

I also wonder what the cost of code like this is? In my full example at the top of this post I’m using a number of clamp() and calc() functions to get this to work. Just how performant are these? Does using custom properties in this way cause the browser to render the page any slower or cause unexpected reflows? It’s something that probably needs some testing.

I’d love to hear what others think…


We'd love to hear from you!

If you think Bronco has the skills to take your business forward then what are you waiting for?

Get in Touch Today!

Discussion

Add a Comment