Hacker News new | ask | show | jobs
by chrismorgan 56 days ago
This sounds interesting, but I’d need to think about it more so I could picture how things fit together as they get more complex and different styles logically overlap. This looks to head in the utility direction possibly too far for that to work nicely. But it may well work better than I’m initially imagining.

Unfortunately I can’t give it more attention now, because I should have gone to sleep a couple of hours ago…

—⁂—

Another approach entirely is to embrace last-declaration-wins, by :where()ing everything:

  :where(.t0)           { background: var(--primary-color); }
  :where(.t0:hover)     { background: var(--primary-hover-color); }
  :where(.t0:active)    { background: var(--primary-pressed-color); }
  :where(.t0[disabled]) { background: var(--surface-color); }
I’d be interested to know which approach performs better once you have altogether too many elements and altogether too complex selectors. I suspect the :where() would win, but that the difference would be impossible to detect in any sort of realistic load.
1 comments

It took me years to picture "how things fit together as they get more complex and different styles logically overlap". I hope we didn't lose you :)

Considering the `:where` approach, I would say it might work most of the time, but it doesn't cover cases where you don't need to set a value, or when your condition requires a more complex selector (e.g., a parent/root context). It was very important for me to support all cases, so I don't feel limited by the tool.

> cases where you don't need to set a value

I don’t know what you mean.

> when your condition requires a more complex selector (e.g., a parent/root context)

I don’t see the problem. :where() takes a <complex-selector-list>.

For example, I want to set (override the inherited one) a custom property by default, but not when some condition is met. Yes, it might be solved with `inherit`, but in other cases `initial` should be used. I prefer not to define anything unless necessary, so the default (from the cascade) can still be used.

You are probably right about `:where`, but using it with complex selectors might noticeably affect the performance, as it does with `:has`. Didn't run any test for `:where` specifically, though. Also, we apply lots of styles to the same elements, most of which are overridden.

Another issue is using a different set of longhand/shorthand properties for different states that won't be correctly overridden in this approach.

So it might work pretty well in most of the cases, especially simple ones. But it's definitely not better than mutually exclusive selectors.

Ah, unsetting. I get what you’re pointing at there, but my immediate reaction is surprise that this is relevant for your approach, which seems to be all about avoiding situations where that has an effect in the first place. Utility styles and explicitly shunning the cascade.

revert-layer <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/V...> may be relevant to the situation you describe. Not the simplest thing, but it’s a tool most don’t know about yet which can do that kind of thing.

—⁂—

On :where(). It’s easy to see why :has() can tank performance: it’s doing a whole new complicated thing. :where() is a good deal simpler, and this specific form of it (where it’s the entire selector) has only the effect of zeroing specificity. I’d be mildly surprised if the performance difference from wrapping an entire selector in :where(…) was measurable even in a worst-case synthetic document.

You are right. I doubt it can cause any issue by itself, but with complex states it might end up being `.class:where(.root .class:is([state1], [state2])`. Still, it should be fast enough. Anyway, I prefer a fully deterministic approach that eliminates any potential issue. `revert-layer` is just `revert` for layers. It's not a lack of value.

Tasty doesn't fight cascase; it fights ambiguity in source order and specificity. Cascade might still be useful for many things.