TWIL
CSS
HTML
Featured image for TWIL blog post illustrating dynamic CSS property updates with HTML integration for smarter, JavaScript-free styling.

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.

With just the HTML and CSS (either approach produces the same visual result) above, we get this. I should have set a border or background on the whole body to prove that the bottom bar is 75% wide, but here we are.

Resources

  • CSS
  • HTML
Katie Linero's profile picture
Katie Linero

Senior Software Engineer

Related Posts

Digital pioneer journeying through technological quirks, reminiscent of vast waterfalls and rocky terrains
April 5, 2017 • Kyle Misencik

Infinitely dispatching actions + React, Redux & React Router v4

While implementing JWT for an application, we ran into a quirk with React Router v4. Here, we hope to show how to implement protected client-side routes while avoiding some of the pitfalls we encountered.

Frank Valcarcel speaking at Denver Startup Week 2018 on healthcare technology and HIPAA compliance, highlighting the digital revolution in healthcare IT
October 5, 2018 • Frank Valcarcel

Scaling Healthcare Technologies at DSW 2018

Discover the transformative journey of healthcare technology at Denver Startup Week 2018 with Frank . Dive into the world of healthcare software, product management, and the critical balance between innovation and HIPAA compliance.