Shadow DOM is een stijlgrens: paginaregels dringen niet door en componentregels lekken niet uit, behalve overgenomen eigenschappen (waaronder aangepaste eigenschappen). Kruis het bewust aan via de onderstaande kanalen.
:host, :host(), :host-context()
/* The component's own host element, styled from inside its shadow tree. */
:host { display: block; }
/* Only when the host matches a selector (e.g. a reflected state attribute). */
:host([disabled]) { opacity: 0.5; pointer-events: none; }
/* Based on an ancestor in the Light DOM; useful for theming. */
:host-context([theme="dark"]) { background: #111; color: #eee; }
Vermijd :host-context(). De functie reikt buiten de grens om voorouders te testen, maar Firefox en Safari hebben geweigerd deze te leveren en de CSSWG neigt ernaar deze niet verder te ontwikkelen. Behandel de functie als een doodlopende weg die alleen voor Chromium geldt, niet als een toekomstgerichte optie. Thema via een overgenomen aangepaste CSS-eigenschap (hieronder): de consument stelt de eigenschap in op een bovenliggend element en de component leest deze over de grens, wat overal werkt en beide kanten ontkoppeld houdt.
Overgenomen eigenschappen en aangepaste eigenschappen overschrijden de grens
Overgenomen CSS-property's (color, font-family, line-height en aangepaste CSS-property's) worden doorgegeven via de schaduwgrens. Hierdoor zijn aangepaste eigenschappen de primaire thema-API: maak ze beschikbaar met verstandige fallbacks.
:host {
/* Consumers override --card-bg from outside; the fallback keeps it usable. */
background: var(--card-bg, white);
color: var(--card-fg, black);
}
Een aangepaste eigenschap die is gedefinieerd op :host, kan alleen worden overschreven door regels die specifiek het hostelement targeten. Als je wilt dat de openbare property wordt overgenomen en overschreven vanaf een hogere positie in de structuur, stel je de openbare property niet in op :host en vertrouw je op de fallback in elke var(). Seed de openbare property niet op :host.
Als je de fallback maar één keer wilt declareren in plaats van deze te herhalen bij elke var(), definieer je een privé-'schaduw'-property op :host die de openbare property leest en verwijs je intern naar de privé-property:
:host {
--_card-bg: var(--card-bg, white);
--_card-fg: var(--card-fg, black);
}
.card { background: var(--_card-bg); color: var(--_card-fg); }
Consumenten overschrijven --card-bg nog steeds van buitenaf. De leidende underscore geeft aan dat de alias intern is en de fallback op precies één plek staat.
::slotted(): styling van geprojecteerde Light DOM
::slotted(selector) target de nodes op het hoogste niveau die aan een slot zijn toegewezen. De regel kan de onderliggende elementen niet bereiken en verliest van elke Light DOM-regel (de consument is de eigenaar van de eigen content). Gebruik de regel dus voor kleine aanpassingen, niet voor beheer. ::slotted(...) !important kan consumentenregels overschrijven, maar overschrijft dan ook de stijl waar de consument recht op heeft. Gebruik dit alleen voor structurele oplossingen, niet voor esthetische overschrijvingen.
/* Matches a slotted <p>, but NOT a <p> nested inside a slotted <div>. */
::slotted(p) { margin: 0; }
::part() en exportparts: interne elementen tonen voor thema's
Markeer een intern element met part="name" zodat consumenten het kunnen stylen met een property, zonder dat ze je interne structuur hoeven te leren.
<!-- inside the shadow template -->
<button part="submit">Submit</button>
/* consumer stylesheet */
my-card::part(submit) { background: navy; color: white; }
Maak een paar overkoepelende onderdelen zichtbaar (knop, invoer, label), niet elk <div>; brede onderdelen worden een kwetsbare API. Als u de onderdelen van een geneste component opnieuw naar boven wilt weergeven via uw eigen component, stuurt u ze door met exportparts:
<inner-widget exportparts="submit: card-submit"></inner-widget>
Kies bewust tussen de 2 kanalen: aangepaste eigenschappen voor een beperkte, voor het ontwerpsysteem veilige set waarden; onderdelen voor onbeperkte styling van een specifiek element.
Stijlen doorsturen naar een verpakt native element
Als een aangepast element een systeemeigen bedieningselement verpakt (<my-button> rond een echte <button>), zijn er 3 dingen die vaak problemen veroorzaken:
- Formulierbesturingselementen nemen geen typografie over.
coloren aangepaste eigenschappen overschrijden de grens, maar<button>,<input>en<select>nemenfonten vergelijkbare elementen over van de UA-stylesheet, die niet wordt overgenomen. De verpakte bedieningselementen worden daarom weergegeven in het platformlettertype, niet in het paginalettertype, totdat jefont: inherit(en meestalcolor: inherit) instelt in de schaduwstructuur. Dit is de meest voorkomende fout. :host-stijlen bereiken het binnenste element niet. Als jebackground/border/paddinginstelt op:host, wordt het hostvak opgemaakt, niet de bedieningselementen erin. Stuur bewust door: maak de bediening beschikbaar als een::partvoor open styling of stuur een vaste set waarden door via aangepaste eigenschappen. Een:host-regel wordt niet trapsgewijs toegepast op het verpakte element.display: contents+all: inheritis een echte afweging, geen snelkoppeling. De host samenvouwen metdisplay: contentsen de interne bediening resetten metall: inheritis op dit moment de enige algemene manier om willekeurige stijlen door te geven aan een verpakt native element zonder dat consumenten per component onderdelen of aangepaste eigenschappen leren. De eigen box van de host verwijderen is meestal het doel van het patroon (compositie die compenseert voor een ontbrekende ingebouwde overerving). 2 echte kanttekeningen:all: inheritwist UA-standaardwaarden, dus beperk het bereik tot specifieke property's of gebruikrevertals je de standaardwaarden terug wilt. En de concrete blokkering:getBoundingClientRect()engetClientRects()retourneren nul voordisplay: contents-elementen, dus de ankerpositionering ten opzichte van de host is verbroken. Gebruik::partof aangepaste eigenschappen als die afwegingen niet passen.
:state(): de eigen statussen van de component opmaken
Een aangepast element kan interne booleaanse statussen tonen via ElementInternals via this.#internals.states.add('busy') en .delete('busy') (ga naar Aangepaste elementen voor gebruik van de levenscyclus). Deze statussen worden een stijlkanal over de grens, zoals ::part en aangepaste eigenschappen, maar voor status in plaats van structuur of waarden. Match ze in de schaduwstructuur met :host(:state(name)) en vanuit de stylesheet van een consument met tag-name:state(name):
/* Inside the component's shadow tree. */
:host(:state(busy)) button { opacity: 0.6; pointer-events: none; }
/* From the consumer's stylesheet — a read-only public hook. */
favorite-button:state(favorited) { filter: drop-shadow(0 0 4px crimson); }
In tegenstelling tot een gereflecteerd kenmerk is een aangepaste status alleen-lezen voor de buitenwereld: consumenten kunnen deze opmaken, maar niet instellen of vervalsen, zodat de component de enige schrijver blijft. Gebruik dit kenmerk in plaats van een data-*-kenmerk als de status eigendom is van de component en alleen moet worden opgemaakt.
@layer en containerquery's in componenten
- Cascade-lagen (
@layer) werken binnen een schaduwroot en zijn daarop gericht. Een laagnaam in de schaduwstructuur is onafhankelijk van een laag met dezelfde naam op de pagina. Gebruik ze om je eigen componentstijlen te ordenen (bijv.@layer base, theme;), zodat overschrijvingen door consumenten via aangepaste eigenschappen en::partnog steeds voorspelbaar winnen. - Containerquery's zijn de juiste tool voor responsieve componenten: een component moet reageren op de ruimte die deze krijgt, niet op de viewport. Declareer de host of een wrapper als container (geef
:hosteen indelingsvak zoalsdisplay: block, omdat aangepaste elementen standaarddisplay: inlinezijn en formaatbeperking niet van toepassing is opinline- ofcontents-elementen) en voer een query uit, zodat dezelfde component zich aanpast in een zijbalk of een gebied met volledige breedte.
:host {
display: block; /* Required: size containment does not apply to default display: inline */
container-type: inline-size;
}
@container (min-width: 30rem) {
.card { grid-template-columns: 1fr 2fr; }
}
Reservestrategieën
::part, cascadelaag en containerquery's zijn breed beschikbaar. Thema's zijn voornamelijk beschikbaar via overgenomen aangepaste eigenschappen, die zelfs werken als deze niet werken. Zoals hierboven vermeld, moet je niet vertrouwen op :host-context(). Dit is in feite alleen voor Chromium en geen toekomstbestendige optie.