5 ms·
I spent years trying to make CSS states predictable
- bryzaguy 5mo agoReminds me of styled components. If the goal is generating the selector why not let the body be a string: ```{ Item: "color: red;" }```?
- tenphi 5mo agoBecause usually each style requires its own set of states, and raw strings are hard to type (in Typescript). But there are even more reasons. `styled-components` is just an advanced CSS injector. We used it as an injector in the early version of Tasty.
- tenphi 5mo agoHappy to take questions! I built this because I kept hitting the same wall: CSS state resolution is opaque when states overlap, and extending components means mentally re-deriving the whole selector matrix every time. Some topics I'm curious what people think about: - What’s the one thing this doesn’t cover that you’d expect it to? - Does the syntax feel natural to you, or did you find yourself confused by anything? - I'm looking for edge cases: what kind of complex selector scenario would trip this compiler up or be impossible to express with this model? AMA—happy to answer any questions about the tool, the implementation, or the design choices.
- chrismorgan 5mo agoThis 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.
- tenphi 5mo agoIt 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.
- chrismorgan 5mo ago> 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>.
- tenphi 5mo agoFor 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.
- chrismorgan 5mo agoAh, 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/Values/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.
- porsager 5mo agoProbably because you aren't using Sin
- wewewedxfgdf 5mo agoMy final conclusion about CSS is - program the damn machine. What I mean by this is STOP every single type of abstraction/library/programming layer for CSS - nothing gets it right, everything causes a problem. The ONLY way to deal with CSS is program it directly in the way the docs say, never anything else. There's nothing wrong with using Bootstrap or whatever, and I definitely use JavaScript to program CSS. What I am saying is - no abstractions - no "better way" - no trying to turn CSS into something it isn't via whatever your new abstraction is that can be added to the N other abstractions that other people have made over the years. Program the damn machine.
- yoz-y 5mo agoFor me nothing beats plain old classes and an external css file. For PWAs I just use lit css within the element, again with classes and plain css. If things cause problems, just figure out why and fix the classes.
- herpdyderp 5mo agoThis is exactly how I feel. Learn how to write CSS! Like you would do with any language!
- exogen 5mo agoBeen writing CSS since 1997. Your mistake is thinking that the authors of these frameworks (or their target audience) just don't know how to use CSS correctly. But it's far more likely that the authors know far, far more about the intricacies of CSS and how it works than most developers. These frameworks are almost always developed by people with deep experience in the trenches, who have realized that CSS scales fucking terribly... not because they are misinformed or did anything wrong. Namely: - Selectors are a global namespace. Imagine if every variable and function in your favorite programming languages were global and so had to be unique. No modules or namespaces. Developing a system to fix that would be pretty high on my list of priorities... coming up with a cool solution and then people telling me to "just learn the language" would be pretty fucking infuriating, don't you think? - Several fighting priority systems (did you know about newer ones like @layer?). And equivalent priority falls back to source order - OK, so how do you square that with dynamic loading? Some navigation paths through an app would inject some CSS first whereas others would inject other CSS first. Good luck!
- Pikamander2 5mo agoPersonally I just increase the specificity as needed. .thing .thing-container .thing html body .thing-container .thing.thing.thing.thing
- tenphi 5mo agoGreat, if it suits your needs. In a big enterprise product, it would be a waste to have so many CSS that are not actually used. Also, maintaining this seems like a nightmare to me.
- grebc 5mo agoI’ve made some gnarly custom forms over the years but never quite run into the problem you’re describing. These days if starting a greenfield web app, each page has its own style/css sent in the head tag. Because it’s usually just base layout + page specific styles/overrides then it barely adds any overhead in the scheme of things(couple of extra KB). Maybe the base layout could be moved into a static file to be cached but whatever, it’s already ridiculously quick to render plain html/css.
- tenphi 5mo agoIf you lack a solid component system, you likely do not require complex tools to manage CSS.
- danielvaughn 5mo agoI also spent years on the same problem. I was creating a programming language for designers, which was supposed to abstract away the complexity of CSS. Long story short, I gave up.
- tenphi 5mo agoSorry to hear it. I didn't. And now our designers can tweak the code directly to adjust component styling. They can finally read and edit styles.
- tenphi 5mo agoActually, most importantly, AI can read and edit styles. CSS is hard enough on its own; adding overrides makes it so complex that it becomes unmanageable at scale.
- efortis 5mo agoThe simple solution is :enabled:hover. For example: .btn { &:enabled:hover { background: dodgerblue; } &:disabled { background: gray; } }
- techbrovanguard 5mo agoFor every complex problem there is a solution that is clear, simple, and wrong.
- _alphageek 5mo ago[dead]
- invalidSyntax 5mo agoI can agree that CSS is really unpredictable. However ,not being able to put CSS in a file isn't a small change. It makes other people to read the code harder, and mixing css and js just doesn't feel right. But just to keep my self safe, I know how people reacted to react at first. This might be normal in the future. Maybe.
- tenphi 5mo agoExactly. And we won't find out if we don't try. Also, specifically, this approach is more JSON-based (compared to other CSS-in-JS). So you can easily put styles into a separate file if you want, JS or JSON. But I prefer defining styled components in a separate file, as `styled-components` recommends.
- efilife 5mo ago> You are no longer just writing styles. You are maintaining a resolution system in your head.
- tenphi 5mo agoI was, but now it's written in the code.