{"id":359886,"date":"2022-01-10T07:22:08","date_gmt":"2022-01-10T15:22:08","guid":{"rendered":"https:\/\/css-tricks.com\/?p=359886"},"modified":"2022-01-11T03:29:22","modified_gmt":"2022-01-11T11:29:22","slug":"dont-fight-the-cascade-control-it","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/dont-fight-the-cascade-control-it\/","title":{"rendered":"Don’t Fight the Cascade, Control It!"},"content":{"rendered":"\n

If you\u2019re disciplined and make use of<\/em> the inheritance that the CSS cascade provides, you\u2019ll end up writing less<\/em> CSS. But because our styles often comes from all kinds of sources \u2014 and can be a pain to structure and maintain\u2014the cascade can be a source of frustration, and the reason we end up with more<\/em> CSS than necessary.<\/p>\n\n\n\n

Some years ago, Harry Roberts came up with ITCSS<\/a> and it\u2019s a clever way of structuring CSS.<\/p>\n\n\n\n\n\n\n\n

\"\"<\/figure>\n\n\n\n

Mixed with BEM<\/a>, ITCSS has become a popular way that people write and organize CSS.<\/p>\n\n\n\n

However, even with ITCSS and BEM, there are still times where we still<\/em> struggle with the cascade. For example, I\u2019m sure you\u2019ve had to @import<\/code> external CSS components at a specific location to prevent breaking things, or reach for the dreaded !important<\/code> at some point in time.<\/p>\n\n\n\n

Recently, some new tools were added to our CSS toolbox, and they allow us to finally control the cascade. Let\u2019s look at them.<\/p>\n\n\n

O cascade, :where<\/code> art thou?<\/h3>\n\n\n

Using the :where<\/code> pseudo-selector<\/a> allows us to remove specificity to \u201cjust after the user-agent default styles,\u201d no matter where or when the CSS is loaded into the document. That means the specificity of the whole thing is literally zero \u2014 totally wiped out. This is handy for generic components<\/em>, which we\u2019ll look into in a moment.<\/p>\n\n\n\n

First, imagine some generic <table><\/code> styles, using :where<\/code>:<\/p>\n\n\n\n

:where(table) {\n  background-color: tan;\n}<\/code><\/pre>\n\n\n\n

Now, if you add some other table styles before<\/em> the :where<\/code> selector, like this:<\/p>\n\n\n\n

table {\n  background-color: hotpink;\n}\n\n:where(table) {\n  background-color: tan;\n}<\/code><\/pre>\n\n\n\n

\u2026the table background becomes hotpink<\/code>, even though the table<\/code> selector is specified before<\/em> the :where<\/code> selector in the cascade. That\u2019s the beauty of :where<\/code>, and why it\u2019s already being used for CSS resets<\/a>.<\/p>\n\n\n\n

:where<\/code> has a sibling, which has almost the exact opposite effect: the :is<\/code> selector<\/a>.<\/p>\n\n\n\n

The specificity of the :is()<\/code> pseudo-class is replaced by the specificity of its most specific argument. Thus, a selector written with :is()<\/code> does not necessarily have equivalent specificity to the equivalent selector written without :is()<\/code>. Selectors Level 4 specification<\/a><\/p><\/blockquote>\n\n\n\n

Expanding on our previous example:<\/p>\n\n\n\n

:is(table) {\n  --tbl-bgc: orange;\n}\ntable {\n  --tbl-bgc: tan;\n}\n:where(table) {\n  --tbl-bgc: hotpink;\n  background-color: var(--tbl-bgc);\n}<\/code><\/pre>\n\n\n\n

The <table class=\"c-tbl\"><\/code> background color will be tan<\/code> because the specificity of :is<\/code> is the same as table<\/code>, but table<\/code> is placed after.<\/p>\n\n\n\n