W3C home > Mailing lists > Public > www-style@w3.org > March 2016

Re: [css-forms][css-ui] Styling native components, a proposal

From: Amelia Bellamy-Royds <amelia.bellamy.royds@gmail.com>
Date: Sat, 26 Mar 2016 19:14:01 -0600
Message-ID: <CAFDDJ7zTqdup=HzK+9G+us8r6LyiUB9UFdmqC-wj=iGQ+Dmc_g@mail.gmail.com>
To: Lea Verou <lea@verou.me>
Cc: www-style list <www-style@w3.org>
A hearty "hear, hear" to all of Lea's arguments.  Authors need a consistent
and extensible way to pass styles to user agents for use within native
widgets.  And the biggest obstacle to doing so right now is that CSS
selectors for styling widget components in one browser are invalid CSS in
any other.

But would it be possible to simplify even further?

Native widgets aren't the only case where the non-robust parsing rules are
a problem.  It comes up every time a new standard pseudo-class or
pseudo-element is introduced.  If you want to use a JS polyfill to add a
class or aria-attribute instead of an unsupported pseudo-class, you'll
either need to duplicate your CSS code, or use JS to find and replace the
unrecognized selectors in the CSS plain text.

So rather than defining a new selector for sub-components, would it be
possible to define generic ::pseudo-element and :pseudo-class selectors?
In other words, make it so that one or two colons followed by a valid CSS
token is treated as a valid selector in any CSS parser.  If the user agent
doesn't recognize the pseudo-* name, it just skips over it the same way it
does a class or tag name that doesn't match anything.  That particular
selector doesn't match, but other selectors in the same rule can still be
evaluated.

So you could do:

input[type="range"]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb,
input[type="range"]::-ms-thumb { /* styles for all */ }


But you could also do:


form:hover,

form:focus,

form:focus-within, /* if not supported yet, breaks the whole rule currently
*/

form.contains-focus /* the fallback-class added by JS if :focus-within not
supported */
{ /* styles */}


I realize that suggesting a change to the fundamental CSS parsing rules
could have wide-reaching implications.  However, I'd be interested in
whether anyone can come up with practical examples where changing an
invalid selector to a valid-but-doesn't-match-anything selector would break
existing code.  Possibly there are horrible hacks for targetting CSS to
specific browsers that rely on this behavior, but that's all I can think of.

~Amelia Bellamy-Royds

On 21 March 2016 at 20:33, Lea Verou <lea@verou.me> wrote:

> The current situation
> —————————————————
>
> There is a large number of native, UA-dependent controls that authors want
> to style. To name a few: select, option, meter (and its various states),
> progress, input[type="whatever"], video & audio media controls, validation
> messages, placeholder text, details marker, scrollbars, resize widget.
>
> Currently, every UA exposes a bunch of proprietary pseudo-elements [1] for
> this. These pseudos come and go, or change at any time, and since they’re
> prefixed and inconsistent, authors have to duplicate their styles multiple
> times to work around invalid selector parsing rules. Despite these issues,
> authors STILL prefer to use these proprietary pseudo-elements, but there is
> a lot of pain and duplication involved. There are numerous tutorials and
> Q&As on the Web revolving around which pseudo-elements to use for any given
> component (see [2] for a tiny sample).
>
> There is also a number of scripts duplicating native behavior, just for
> styling purposes (fake scrollbars, fake select dropdowns etc etc. We’ve all
> seen them). This is even worse as it leads to decreased usability and
> accessibility.
>
> At this point, I don’t think anybody can reasonably continue arguing that
> authors should "just stop" styling native controls. They clearly need to,
> and UAs are trying to accommodate their use cases as they best can, while
> there is no standard to make this less painful for authors. I think this is
> a problem we need to address asap. The landscape of styling native
> components is currently as inconsistent as general CSS was in the early
> 2000s, and authors are using this CSS anyway and leaving tons of future web
> compat issues behind them.
>
> Problems with standardizing a solution
> ——————————————————
>
> The internal implementations of these components are vastly different on
> different UAs and platforms. E.g. a calendar widget on Mobile Safari is
> completely different than a calendar widget on Chrome Desktop. Therefore,
> using the shadow DOM piercing combinator and targeting specific elements
> (e.g. video >>> input[type=range]) is flimsy, not to mention that browsers
> need to be free to change their internal representations.
>
> Most importantly, *not every part that authors want to style is part of
> the shadow DOM*. For example scrollbars or resizer widgets are not.
>
> Efforts to standardize which parts are exposed or which properties are
> allowed by explicitly defining them [3] is bound to become a lowest common
> denominator solution and not actually address authors’ use cases.
> Standardizing pseudos on a case-by-case basis (e.g. :placeholder-shown,
> ::placeholder,
>
> A modest proposed solution
> ——————————————————
>
> Let’s leave the identifiers, what they correspond to, and which properties
> are allowed UA-dependent, but define a parameterized pseudo-element for
> addressing them en masse. Most of the pain in styling native components
> today is not so much due to the varying pseudo-element identifiers, but due
> to the duplication and prefixes. E.g. to style a slider thumb, one has to
> write:
>
> input[type="range"]::-webkit-slider-thumb { /* styles */ }
> input[type="range"]::-moz-range-thumb { /* styles, again */ }
> input[type="range"]::-ms-thumb { /* styles, again */ }
>
> With this proposal, authors would be able to write:
>
> input[type="range"]::parts(slider-thumb, range-thumb, thumb) { /* styles
> */ }
>
> On platforms where the range input does not have a thumb, the selector
> just doesn’t match anything.
>
> One could argue that we can do this with the Shadow DOM + classes and
> write something like:
>
> input[type="range"] >>> ::matches(.slider-thumb, .range-thumb, .thumb) {
> /* styles */ }
>
> However, note that:
> - Native controls are not always part of the Shadow DOM (e.g. scrollbars,
> resizers, selects and date pickers on mobile)
> - Even when native controls could have been part of the Shadow DOM, they
> are often not implemented that way.
> - Some of the existing pseudos correspond to states, not just elements,
> e.g. ::-webkit-meter-optimum-value, ::-webkit-meter-suboptimum-value,
> ::-webkit-meter-even-less-good-value
> - Given that this essentially syntactic sugar over the various existing
> pseudo-elements [1], it should be relatively quick/easy to implement and
> doesn’t require implementing the entire Shadow DOM spec (also, not all
> parts can be expressed as Shadow DOM).
> - In addition, if the Shadow DOM provides a mechanism for hooking into
> this, author components can also expose select parts similarly.
> - Hopefully, given that this leaves so much implementation-dependent, it
> should provide enough motivation for UAs to stop creating more proprietary
> pseudo-elements.
>
> We could still define a list of minimum properties that apply to these
> parts, e.g. fonts, colors, backgrounds, shadows etc. Also, there could be a
> centralized list for recommended identifiers when multiple conflicting ones
> exist for the same part (e.g. slider-thumb, range-thumb, thumb), so that
> UAs eventually converge, organically. But I believe the first version of
> this should leave a lot up to the UA to stop this pseudo-element madness in
> its tracks.
>
> PS: Turns out there is a very similar earlier proposal by hober [4], very
> good arguments there as well!
>
> [1]: Lists of the various pseudo-elements currently in use:
> http://trac.webkit.org/wiki/Styling%20Form%20Controls
> https://gist.github.com/webtobesocial/aefd6e25064c08e0cc9a
>
> https://www.tjvantoll.com/2013/04/15/list-of-pseudo-elements-to-style-form-controls/
>
> [2]: A tiny sample of tutorials:
> https://css-tricks.com/html5-meter-element/
> http://www.hongkiat.com/blog/html5-progress-bar/
> https://css-tricks.com/html5-progress-element/
> https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/
> http://codepen.io/collection/DgYaMj/8/
> https://css-tricks.com/webkit-html5-search-inputs/
> https://css-tricks.com/numeric-inputs-a-comparison-of-browser-defaults/
> https://css-tricks.com/snippets/css/turn-off-number-input-spinners/
> https://css-tricks.com/snippets/css/custom-file-input-styling-webkitblink/
> http://qnimate.com/guide-to-styling-html5-input-elements/
> https://css-tricks.com/custom-scrollbars-in-webkit/
> https://codegeekz.com/customize-your-scrollbars-with-css3-and-jquery/
> http://poselab.com/en/custom-scrollbars-in-webkit/
>
> http://webdesign.tutsplus.com/articles/quick-tip-styling-scrollbars-to-match-your-ui-design--webdesign-9430
> https://davidwalsh.name/style-textarea-resizer
> https://css-tricks.com/almanac/properties/s/scrollbar/
> http://advprog.blogspot.com/2013/07/styling-html-media-inner-workings.html
> https://css-tricks.com/custom-controls-in-html5-video-full-screen/
> http://tylergaw.com/articles/fun-with-html-form-validation-styles
>
> http://webdesign.tutsplus.com/tutorials/bring-your-forms-up-to-date-with-css3-and-html5-validation--webdesign-4738
> http://thereforei.am/2011/07/01/css-selectors-for-html5-input-validation/
>
> http://www.useragentman.com/blog/2012/05/17/cross-browser-styling-of-html5-forms-even-in-older-browsers/
>
> Also numerous stackoverflow Q&A omitted for brevity.
>
> [3]: https://drafts.csswg.org/css-forms/
> [4]: https://lists.w3.org/Archives/Public/www-style/2014Feb/0621.html
>
> Lea Verou ✿ http://lea.verou.me ✿ @leaverou
>
>
>
>
>
>
>
>
Received on Sunday, 27 March 2016 01:14:30 UTC

This archive was generated by hypermail 2.4.0 : Friday, 25 March 2022 10:09:01 UTC