Dive into the latest edition of TWIL, our weekly series that sparks curiosity and fosters continuous learning in the realm of software development. In this installment, Katie demystifies Dynamic Values with Inline Custom Properties in CSS. Witness how CSS var()
function advancements create a new realm of possibilities, enabling effortless thematic changes and innovative styling without the heavy lifting of JavaScript. From tooltips with pseudo-elements to vibrant, customized progress bars, learn how HTML attributes and CSS custom properties team up to elegantly code an array of web components.
Dynamic Values with Inline Custom Properties in CSS
I’ve been trying for years to do clever things with the CSS attr()
function and being able to dynamically set styling values via HTML attributes (without having to manipulate styles with JavaScript), but it has not been able to accomplish everything I’ve wanted it to do. I’ve recently learned that what I could not do with attr()
, I can instead achieve with the clever use of CSS’s var()
function instead.
attr()
This function can be really handy for pulling content from an element to use in it’s styling; something like a tooltip or popover that uses ::before
or ::after
pseudo-elements, for example, can pull the content
value directly from the element if it’s defined there. For example:
<span class="list-title" separator=":">Here follows a list of things</span>
<!-- Or, a more useful example using Rails/ERB and variable content: -->
<span class="list-title" separator="<%= preferences.separator %>">
<%= list.title %>
</span>
.list-title::after {
content: attr(separator);
/* You can concat this too, like so:
content: 'Hot Tip: ' attr(tooltip) ' ...JSYK';
*/
}
This, however, only works with strings. If you wanted to pull a value for use with a numeric property, for example (e.g., to dynamically set element widths for a horizontal proportion/progress bar), attr()
won’t work for that.
var()
This function allows you to use custom properties, like variables, in your style definitions.
:root {
--thing-color: #BADA55;
--thing-size: 10em;
}
.thing {
color: var(--thing-color);
font-size: var(--thing-size);
}
The Special Sauce
While this has obvious benefits in use cases such as defining themes or simply reducing duplication, I had not considered the ability to define custom properties outside my CSS to then use within my CSS.
A quick example with simple progress bars:
<div class="progress-bar" style="--progress: 50%; --bar-color: #BADA55;"></div>
<div class="progress-bar" style="--progress: 25%; --bar-color: red;"></div>
<div class="progress-bar" style="--progress: 75%; --bar-color: green;"></div>
.progress-bar {
height: 20px;
background-color: var(--bar-color);
width: var(--progress);
}
Approach one, where progress bar is set with both background color and width %
.progress-bar {
background-color: var(--bar-color);
height: 20px;
position: relative;
width: 100%;
}
.progress-bar::after {
background-color: white;
content: "";
display: block;
height: 100%;
position: absolute;
right: 0;
width: calc(100% - var(--progress));
}
Approach two, a more complex (if admittedly contrived) setup to demonstrate that we can still use var()
within calc()
(etc.) to set the progress bar to the full color, then essentially cover the remaining % with an ::after
pseudo-element.
Resources
- https://css-tricks.com/css-attr-function-got-nothin-custom-properties/
- https://developer.mozilla.org/en-US/docs/Web/CSS/attr
- https://developer.mozilla.org/en-US/docs/Web/CSS/var
- CSS
- HTML