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

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 <http://trac.webkit.org/wiki/Styling%20Form%20Controls>
https://gist.github.com/webtobesocial/aefd6e25064c08e0cc9a <https://gist.github.com/webtobesocial/aefd6e25064c08e0cc9a>
https://www.tjvantoll.com/2013/04/15/list-of-pseudo-elements-to-style-form-controls/ <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/ <https://css-tricks.com/html5-meter-element/>
http://www.hongkiat.com/blog/html5-progress-bar/ <http://www.hongkiat.com/blog/html5-progress-bar/>
https://css-tricks.com/html5-progress-element/ <https://css-tricks.com/html5-progress-element/>
https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ <https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/>
http://codepen.io/collection/DgYaMj/8/ <http://codepen.io/collection/DgYaMj/8/>
https://css-tricks.com/webkit-html5-search-inputs/ <https://css-tricks.com/webkit-html5-search-inputs/>
https://css-tricks.com/numeric-inputs-a-comparison-of-browser-defaults/ <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/turn-off-number-input-spinners/>
https://css-tricks.com/snippets/css/custom-file-input-styling-webkitblink/ <https://css-tricks.com/snippets/css/custom-file-input-styling-webkitblink/>
http://qnimate.com/guide-to-styling-html5-input-elements/ <http://qnimate.com/guide-to-styling-html5-input-elements/>
https://css-tricks.com/custom-scrollbars-in-webkit/ <https://css-tricks.com/custom-scrollbars-in-webkit/>
https://codegeekz.com/customize-your-scrollbars-with-css3-and-jquery/ <https://codegeekz.com/customize-your-scrollbars-with-css3-and-jquery/>
http://poselab.com/en/custom-scrollbars-in-webkit/ <http://poselab.com/en/custom-scrollbars-in-webkit/>
http://webdesign.tutsplus.com/articles/quick-tip-styling-scrollbars-to-match-your-ui-design--webdesign-9430 <http://webdesign.tutsplus.com/articles/quick-tip-styling-scrollbars-to-match-your-ui-design--webdesign-9430>
https://davidwalsh.name/style-textarea-resizer <https://davidwalsh.name/style-textarea-resizer>
https://css-tricks.com/almanac/properties/s/scrollbar/ <https://css-tricks.com/almanac/properties/s/scrollbar/>
http://advprog.blogspot.com/2013/07/styling-html-media-inner-workings.html <http://advprog.blogspot.com/2013/07/styling-html-media-inner-workings.html>
https://css-tricks.com/custom-controls-in-html5-video-full-screen/ <https://css-tricks.com/custom-controls-in-html5-video-full-screen/>
http://tylergaw.com/articles/fun-with-html-form-validation-styles <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://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://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/ <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/ <https://drafts.csswg.org/css-forms/>
[4]: https://lists.w3.org/Archives/Public/www-style/2014Feb/0621.html <https://lists.w3.org/Archives/Public/www-style/2014Feb/0621.html>

Lea Verou ✿ http://lea.verou.me ✿ @leaverou

Received on Tuesday, 22 March 2016 02:34:04 UTC