{"id":312969,"date":"2020-06-22T07:47:49","date_gmt":"2020-06-22T14:47:49","guid":{"rendered":"https:\/\/css-tricks.com\/?p=312969"},"modified":"2022-05-23T10:40:35","modified_gmt":"2022-05-23T17:40:35","slug":"using-custom-property-stacks-to-tame-the-cascade","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-custom-property-stacks-to-tame-the-cascade\/","title":{"rendered":"Using Custom Property “Stacks” to Tame the Cascade"},"content":{"rendered":"\n

Since the inception of CSS in 1994, the cascade and inheritance have defined how we design on the web. Both are powerful features but, as authors, we’ve had very little control over how they interact. Selector specificity and source order provide some minimal “layering” control, without a lot of nuance — and inheritance requires an unbroken lineage<\/em>. Now, CSS Custom Properties allow us to manage and control both cascade and inheritance in new ways.<\/strong><\/p>\n\n\n\n

I want to show you how I’ve used Custom Property “stacks” to solve some of the common issues people face in the cascade: from scoped component styles, to more explicit layering of intents.<\/p>\n\n\n

A quick intro to Custom Properties<\/h3>\n\n\n

The same way browsers have defined new properties using a vendor prefix like -webkit-<\/code> or -moz-<\/code>, we can define our own Custom Properties with an \u201cempty\u201d --<\/code> prefix. Like variables in Sass or JavaScript, we can use them to name, store, and retrieve values — but like other properties in CSS, they cascade<\/strong> and inherit<\/strong> with the DOM.<\/p>\n\n\n\n

\/* Define a custom property *\/\nhtml {\n  --brand-color: rebeccapurple;\n}<\/code><\/pre>\n\n\n\n

In order to access those captured values, we use the var()<\/code> function. It has two parts: first the name of our custom property, and then a fallback in case that property is undefined:<\/p>\n\n\n\n

button {\n  \/* use the --brand-color if available, or fall back to deeppink *\/\n  background: var(--brand-color, deeppink);\n}<\/code><\/pre>\n\n\n\n

This is not a support fallback for old browsers. If a browser doesn\u2019t understand custom properties, it will ignore the entire var()<\/code> declaration. Instead, this is a built-in way of handling undefined variables, similar to a font stack defining fallback font families when one is unavailable. If we don’t provide a fallback, the default is unset<\/code>.<\/p>\n\n\n

Building variable “stacks”<\/h3>\n\n\n

This ability to define a fallback is similar to “font stacks” used on the font-family<\/code> property. If the first family is unavailable, the second will be used, and so on. The var()<\/code> function only accepts a single fallback, but we can nest var()<\/code> functions to create custom-property fallback “stacks” of any size:<\/p>\n\n\n\n

button {\n  \/* try Consolas, then Menlo, then Monaco, and finally monospace *\/\n  font-family: Consolas, Menlo, Monaco, monospace;\n\n  \/* try --state, then --button-color, then --brand-color, and finally deeppink *\/\n  background: var(--state, var(--button-color, var(--brand-color, deeppink)));\n}<\/code><\/pre>\n\n\n\n

If that nested syntax for stacked properties looks bulky, you can use a pre-processor like Sass to make it more compact.<\/p>\n\n\n\n