Styling form states without JavaScript
webkit.org
webkit.org
In some cases, I actually agree that the default behavior is rough. For example, type a single character in the email input in the example in the article and notice that the field immediately transitions to the error state even though you’re still typing.
It’s not a friendly experience—at best it’s pedantic—and I’ve never met a designer who hasn’t requested that the error state only be used when the user removes focus from an input. You could perhaps use a sequence of pseudo classes, but in practice, it’s typically much harder to follow that logic in CSS vs JS.
My point is that this should be the exception, not the rule. I certainly don't think this level of abstracted complexity is necessary, or even better, in most scenarios. I'm talking at a design or implementation level.
So in fact I think it is the rule, not the exception.
Unfortunately you have to do a dumb JS dance to get these reasonable affordances. Hard to blame people for not reimplementing all this shit even if it’s critically useful for many folks.
The solution for this is :user-invalid. Firefox has had it for a year and a half, WebKit has https://github.com/WebKit/WebKit/pull/5958 hopefully landing soon, Chromium has no activity on https://bugs.chromium.org/p/chromium/issues/detail?id=115606.... For fresh development these days, I would recommend using :user-invalid and polyfilling, rather than implementing your own very similar semantics in your own way in JS.
See https://developer.mozilla.org/en-US/docs/Web/CSS/:user-inval... for a demo.
(:user-invalid as an alternative to :invalid joins the list of presentational nuance pseudoclasses that allow you to match what browsers themselves do in their default styling, joining :focus-visible which is an alternative to :focus.)
Is there a polyfill you can recommend?
Or use a transition to show the error a few seconds later than the input happened.
In general I agree that we should be looking for CSS/built-in solutions to these sorts of input state problems, but this is one of those cases where you either use JavaScript, or accept the accessibility hit. (Bearing in mind that JavaScript itself can be an accessibility hit in its own right.)
That said, personally I put a bit of effort into achieving (dynamic) ends without javascript (despite being a js dev) and find form styling, with it's intrinsic state, one of the less-problematic things to style. In fact, I tend to use input elements in a bunch of unconventional places as state machines in place of js. Hamburger menus, overlays (prior to the <dialog> tag), dark mode toggle, etc. have all been prime candidates for "previous-sibling" (or "parent-previous-sibling") input treatment.
In the form examples provided, the <labels> being styled could easily be included "after" the <input> in code (regardless of where they appear visually) allowing them to be targeted based on state/focus of the input. Similarly the :focus-within vs :has(:focus-visible) consideration is interesting, but in reality not really a massive concern and certainly not a blocker. The fact that people have relied on JS for this stuff traditionally I think is the bigger concern for me. Here's to progress!
P.S. I mainly like the idea of low/no js from an academic perspective. But I do think it comes in handy in surprising situations, both when a random no-js purist stumbles across your site and is able to do something, but also when something breaks (naughty browser plugin, broken script, dodgy refactor) and people are still able to open your nav / close your popover / fill in your complaints form.
https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
I'll also forever have a fondness for "cornflower blue" because it was the default fill color when you created a new C# Xbox 360 game using Microsoft XNA.
This file: https://github.com/freedesktop/xorg-rgb/blob/master/rgb.txt
> Supported in Firefox behind the `layout.css.has-selector.enabled` flag
see https://stackoverflow.com/q/73936048 etc.
NOTE: it looks like it's not ordinarily working even when switched on.
I find the :has() selector very useful in certain cases, but firefox doesn't support it yet and like you said, it doesn't work very well even when enabled. What I have done for Firefox is use the `@supports selector` query [1] and fallback to some equally functional but not as nicely styled UI with the hope that when Firefox supports it, it will automatically provide the nicer UI.
[1] https://developer.mozilla.org/en-US/docs/Web/CSS/@supports#f...
[1]: https://alistapart.com/article/understandingprogressiveenhan...
/* Warning message
about support for :has() */
@supports selector(:has(img)) {
body small {
display: none;
}
}
And I sure love it when CSS performs according my preference, but I'd never complain about a UA not implementing or a user prefer her own style over agent or author.All of that got worked out a while ago; you can read the CSSWG notes and check the bug trackers for WebKit, Firefox and Chrome.
It’s not that WebKit, which shipped :has() back in March, was too early but Mozilla had some difficulties with their implementation [1].
It took Google (and Igalia) until the end of August to ship their implementation in Chrome 105 [2].
Even though web developers have been asking for this for nearly 20 years, it only recently got figured out.
Based on Apple’s article [3] and Igalia's prototyping document [4], this is easily the most complex CSS selector that’s ever been implemented.
I would cut Mozilla some slack.
[1]: https://bugzilla.mozilla.org/show_bug.cgi?id=418039
[2]: https://developer.chrome.com/blog/new-in-chrome-105/
[3]: https://webkit.org/blog/13096/css-has-pseudo-class/
[4]: https://github.com/Igalia/explainers/blob/main/css/has/proto...