简体   繁体   中英

How to build or customize a good (Vaadin) webcomponent so css is not too intrusive

As alternative solution for https://github.com/vaadin/web-components/issues/5214 we now have styled some css parts in the shadow DOM of the avatar(-group).

What I am wondering is:

  1. To what extend can/should we style css (parts) in Vaadin (but also in general) and not break backwards compatibilty?

  2. What are/where are best practices for building good webcomponents so API consumers will not break backwards compatility too fast.

For example: building a webcomponent with a root flex container will break when an API consumer changes the css display property, so in this case moving the flex container to the shadow DOM could make the component less fragile. But stil, the consumer can break a lot of stuff...

The same applies for css parts.

Product Owner of Vaadin components here. You are asking the very same questions we have been asking ourselves for years:

  • How far should we go in trying to prevent users from breaking our components with their CSS, or from applying custom CSS that is likely to be broken by our own implementation changes in later versions?
  • How do we balance these attempts at preventing breakages with the need to provide users with ways to customize the components styling?

etc.

Our initial approach, in Vaadin 10 where the Web Component based components first shipped, was to hide as much as possible of the components' internal structure in Shadow DOM, and to define only elements with part names (and the root elements) to be part of the "public styling API".

This approach had many drawbacks however:

  1. Even if styling is limited to named parts and the root, elements are not rendered in isolation from each other – CSS applied to shadow-parents affect their named part children (and in some case vice versa,), so it's far from a bullet proof protection against non-future-proof custom CSS
  2. You can still break the component in all kinds of ways through those exposed elements (although you do need to target them specifically, so it does protect against styles inadvertently getting applied to the component)
  3. Choosing which elements should be named parts is a difficult balancing act: too few and you're limiting custom styling too much; too many, and the whole point of shadow DOM style encapsulation is ruined
  4. It turns out Shadow DOM really hurts accessibility and many nice-to-have browser features like form autocomplete and password managers, so we had to move some elements from the shadow into slots, thus fully exposing them to custom CSS.

Today, my take on the matter is that it's simply futile to try to prevent any of this. We still have shadow DOM in the components, but the style encapsulation aspect is not really something we actively try to utilize. We move any elements to light DOM that benefit from it (while keeping other parts in the shadow DOM for different technical reasons), and we're ready to expose any element as a named part for which there is a clear use case for custom CSS.

What I'm saying here is of course about a very generic component library, that is not meant for internal use for a particular product or company, but for thousands of companies to use in any way they like, which often includes tweaking the look and feel, and in some cases even layout/structural CSS, to fit their needs.

If I were to build a set of components for a design system tailored for a particular company or product, I would probably be much more inclined to limit customizability, but I'd still need to balance that with accessibility etc.

So, in an attempt to answer your questions:

  1. If you stick to named parts and root elements (and pseudo elements), you'll probably be fine, but it's no guarantee. Follow the release notes to see if there are breaking changes, and read the upgrade guides when they're published. (Also, we're going to publish lists of officially supported selectors for Vaadin 24 – that will give you a better idea of what we consider the "public styling API", but it doesn't guarantee that none of those will change in future versions.)
  2. If it's meant for 3rd party use, don't even try. Just let them do whatever. But communicate clearly when a new version changes something that might break 3rd party CSS. (We try to do this ourselves with the upgrading guides we publish for major versions.) If it's for an internal product/org-specific library, you need to decide what (if anything) should be customizable.

For example: building a webcomponent with a root flex container will break when an API consumer changes the css display property, so in this case moving the flex container to the shadow DOM could make the component less fragile.

For this specific case, one option is to use !important in the shadow DOM styles, which prevent light DOM styles from overriding them:

:host {
  display: flex !important;
}

Another useful tool is to reset all properties on the host, so that there aren't any surprises coming from the light DOM (inherited properties mainly). Then set any properties with !important that are required for the component to work correctly:

:host {
  all: initial;
  display: flex !important;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM