CSS Only COVID-19 Dashboard Dial
Tags: css, covid19, cssvariables
Published: 2020-05-21 03:16:05

---
title: CSS Only COVID-19 Dashboard Dial
published: true
description: CSS only is fun
tags: css, covid-19, css variables
---
In Washington State where I live, the governor's office is making decisions about reopening on a number of metrics. These metrics are grouped together in a [dial dashboard](https://coronavirus.wa.gov/what-you-need-know/covid-19-risk-assessment-dashboard) where each dial represents the risk level for a particular set of metrics.

I decided to make one with CSS only.

<figure>
![A dial pointing at an arc that is labeled low risk and high risk](https://dev-to-uploads.s3.amazonaws.com/i/ivznkbltx4x22tbz2xat.png)
<figcaption>The original image.</figcaption>

I was kind of surprised how quickly I made this. Apparently 10 years of loving CSS has paid off. Here are some observations about the process.

## Semantic HTML and accessibility first
I am proud that without thinking, I immediately sought out an appropriate semantic element for the dial - the `meter` element.

Because of the many problems with styling it, I opted to hide it using a tool that should be in every web dev's toolbox, the CSS clip, screen-reader only hack. This code will hide an element from sighted users, but keep it available for assistive technology.
```css
.sr-only {
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
}
```

In this case, I used it to hide the meter and to hide a more sensical label.

I also used `aria-hidden` to hide the less helpful "Low Risk High Risk" text.

Even though this was just a fun CSS exercise, it feels good to care!

### Knowing when to add HTML to help with styling
This is a particular virtue that I have came upon lately. In the past, I tried to use as few HTML elements as possible, keeping the DOM tree flat. I was a hypochondriac and avoid "divitis" like the plague. The separation of content and presentation was a holy command.

Over the years, I have spent countless hours and used pseudo-elements to do all sorts of obscene things rather than add an empty div to the page.

Now, I still reach for those pseudo-elements, but when things become fragile, I will add a `div` or two.

Don't get me wrong, meaningless `div`s aren't great, but neither is inscrutable CSS.

## The CSS triangle hack
The pointer on the dial is made of two transparent pseudo-elements with fat borders that are also transparent on two sides. As with most of these kinds of hacks, I used a tool to generate some CSS and tweaked the values until they were correct.

## Gradient tools
I have use old school [Colorzilla's gradient generator](https://www.colorzilla.com/gradient-editor/) for years, but I discovered a slightly slicker generator at [css-gradient.io](https://cssgradient.io/).

## Attribute, sibling selectors, and `calc`, and CSS variables<sup>[1](#footnote1)</sup> to sync presentation with content

This is probably the fanciest thing I did. In order to rotate the dial in sync with the value of the `meter` element, I used this combination of awesome CSS features.

In the dial css, I added a `rotateZ` transform with a `calc` function that uses a the value of a CSS variable to compute the rotation. Turn is a great unit to use with with rotate transforms. 

```css
transform: rotateZ(calc(var(--turn) * .05turn - .25turn));
```

The CSS variables are set in rules that target the `value` attribute of the meter. Cool thing about 
```css
meter[value="1"] ~ .dashboard-meter__container { --turn: 1 }
meter[value="2"] ~ .dashboard-meter__container { --turn: 2 }
meter[value="3"] ~ .dashboard-meter__container { --turn: 3 }
meter[value="4"] ~ .dashboard-meter__container { --turn: 4 }
meter[value="5"] ~ .dashboard-meter__container { --turn: 5 }
meter[value="6"] ~ .dashboard-meter__container { --turn: 6 }
meter[value="7"] ~ .dashboard-meter__container { --turn: 7 }
meter[value="8"] ~ .dashboard-meter__container { --turn: 8 }
meter[value="9"] ~ .dashboard-meter__container { --turn: 9 }
```

## Google-Fu
My google-fu is so strong I just used google to spell google-fu. Really, it is usually duck-duck-go-fu, which sounds delicious.

Bad jokes aside, going to the docs or the countless web development blogs and getting the answers is a cybernetic enhancement that may be more valuable than any other skill. I look up things I know that I don't want to have to remember

## The code

{% codepen https://codepen.io/tinynow/pen/QWjzRRP %}

<small id="footnote1">1. I know they are called custom properties, but I'm not going to do that anymore; just because they are declared the same way that other properties are set, it isn't worth the cognitive load and confusion it causes learners.</small>