CSS Type Grinding: Casting Tokens (sm|md|etc) into Useful Values (aka Style Queries without Style Queries thanks to @property)

My favorite use case for Style Queries is the ability to change a bunch of styles based on the value of a so called “higher-order variable”. You use that variable as a switch to change a bunch of properties.

@container style(--theme: dark) {
  .card {
    background: royalblue;
    border-color: navy;
    color: white;

  .card button {
    border-color: navy;
    background-color: dodgerblue;
    color: white;

Current issue with Style Queries though is that:

  1. You need browser support (which is Chrome Canary only at the time of writing)
  2. Only parent elements can be containers that children can query. There is no way to have an element be both the container and the querying child targeting self (because: cycles)

While the first issue should get fixed over time, the second one never will …


Last week, Jane Ori surprised me a wonderful post that tackled the latter issue. Leveraging @property, they were able to implement Higher-Order Variables that work on the element itself! The technique is called Type Grinding:

Type Grinding allows your design tokens (keywords, or “<custom-ident>” values) written in your CSS to be transformed into any other values – like width, padding, color, etc – without relying on anything outside of CSS.

For example, you could have a --size Custom Property that accepts the values sm, md, or lg. Changing its value will act as a switch to change many other CSS properties, similar to Style Queries but without the need for Style Queries support!

The full code to achieve it is detailed in the post by Jane. It starts of with registering the --size with only its allowed values:

@property --size {
  syntax: "sm|md|lg";
  initial-value: md;
  inherits: true;

Based on the value of --size, it’s possible to have more properties that output a 1 or a 0:

@property --_sm-else-0 {
  syntax: "sm|";
  initial-value: 0;
  inherits: true;
@property --_if-sm-then-1-else-0 {
  syntax: "";
  initial-value: 1;
  inherits: true;

.type-grinding {
  --size: md;
  --_sm-else-0: var(--size);
  --_if-sm-then-1-else-0: var(--_sm-else-0);

With that at the base, Jane builds things up further, finally achieving the Type Grinding. Apart from being somewhat complicated, the only downside of the whole approach is that it needs @property support – a feature that’s only available in Chromium-based browsers at the time of writing.

If you happen to be visiting this site using Chrome, you can try it out yourself in the demo embedded below:

See the Pen CSS-Only Badge Component via the "Type Grinding" Trick! by Jane Ori 💜 (@propjockey) on CodePen.

CSS-Only Type Grinding: Casting Tokens (sm|md|etc) into Useful Values →

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.