Signatur
Beschreibung
Der Konstruktor CSSStyleSheet() erzeugt ein Stylesheet direkt in JavaScript, ohne dass ein <style>- oder <link>-Element im DOM nötig ist. Solche Stylesheets nennt man Constructable Stylesheets. Man befüllt sie mit replace() (asynchron, liefert ein Promise) oder mit replaceSync() (synchron) und kann einzelne Regeln mit insertRule() bzw. deleteRule() ändern.
Damit das Stylesheet wirkt, muss es über die Eigenschaft adoptedStyleSheets an ein Document oder einen ShadowRoot angehängt werden. Der große Vorteil: Ein einziges Stylesheet-Objekt lässt sich von beliebig vielen Shadow Roots gemeinsam nutzen. Der Browser parst die Regeln nur einmal und hält sie nur einmal im Speicher vor. Bei Web Components mit vielen Instanzen spart das deutlich Arbeit gegenüber einem eigenen <style>-Element pro Instanz.
Ändert man ein geteiltes Stylesheet, zum Beispiel beim Wechsel des Farbschemas, wirkt sich das sofort auf alle Dokumente und Shadow Roots aus, die es übernommen haben. Über das Optionsobjekt lassen sich schon beim Erzeugen Medienabfragen, der Deaktiviert-Zustand und die Basis-URL für relative URLs festlegen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | object | {} | Optionales Konfigurationsobjekt mit den unten aufgeführten Eigenschaften. |
| $options.baseURL | string | URL des Dokuments | Basis-URL, gegen die relative URLs im Stylesheet aufgelöst werden, z. B. in url(). |
| $options.media | string|MediaList | "" | Medienabfrage(n), für die das Stylesheet gilt, z. B. "screen and (min-width: 600px)". |
| $options.disabled | boolean | false | Mit true ist das Stylesheet von Anfang an deaktiviert und wird nicht angewendet. |
Rückgabewert
CSSStyleSheet-Objekt. Die Liste cssRules ist leer, und das Stylesheet gehört noch zu keinem Dokument.Beispiele
Stylesheet erzeugen und dem Dokument hinzufügen
const sheet = new CSSStyleSheet();
sheet.replaceSync(`
body { font-family: system-ui, sans-serif; }
.hinweis { color: darkorange; }
`);
// Bestehende Stylesheets erhalten und das neue anhängen
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
console.log(sheet.cssRules.length);
Ein Stylesheet von mehreren Web-Component-Instanzen gemeinsam nutzen
// Wird nur einmal geparst, egal wie viele Instanzen es gibt
const buttonStyles = new CSSStyleSheet();
buttonStyles.replaceSync(`
button { padding: .5rem 1rem; border-radius: 6px; border: none;
background: rebeccapurple; color: white; }
`);
class FancyButton extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.adoptedStyleSheets = [buttonStyles];
root.innerHTML = '<button><slot></slot></button>';
}
}
customElements.define('fancy-button', FancyButton);
document.body.insertAdjacentHTML('beforeend',
'<fancy-button>OK</fancy-button><fancy-button>Abbrechen</fancy-button>');
Optionen nutzen und Farbschema live umschalten
const darkTheme = new CSSStyleSheet({
media: 'screen',
disabled: true // zunächst aus
});
await darkTheme.replace(`
:root { --bg: #111; --fg: #eee; }
body { background: var(--bg); color: var(--fg); }
`);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, darkTheme];
const toggleDark = (on) => { darkTheme.disabled = !on; };
toggleDark(true);
console.log(darkTheme.media.mediaText, darkTheme.disabled);
Feature-Erkennung mit Fallback
const applyCss = (root, css) => {
if ('adoptedStyleSheets' in Document.prototype && 'replaceSync' in CSSStyleSheet.prototype) {
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);
root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
} else {
// Fallback für ältere Browser
const style = document.createElement('style');
style.textContent = css;
(root === document ? document.head : root).append(style);
}
};
applyCss(document, 'h1 { letter-spacing: .05em; }');
// Wichtig · Fallstricke
@importwird nicht unterstützt:replaceSync()ignoriert@import-Regeln (mit Konsolenwarnung). Beireplace()ist@importebenfalls nicht erlaubt, undinsertRule()mit@importwirft einenSyntaxError.- Nur im eigenen Dokument verwendbar: Ein konstruiertes Stylesheet lässt sich nur in dem Dokument (und dessen Shadow Roots) übernehmen, in dem es erzeugt wurde. Ein Stylesheet aus einem anderen Fenster oder iframe führt zu einem
NotAllowedError. adoptedStyleSheetswar früher unveränderlich: Ältere Browser lieferten ein eingefrorenes Array, undpush()schlug fehl. Die portable Lösung ist, jedes Mal ein neues Array zuzuweisen:[...alt, sheet]. Neuere Browser liefern ein veränderbaresObservableArray.- Nur für konstruierte Stylesheets:
replace()undreplaceSync()funktionieren nur bei Stylesheets, die mit diesem Konstruktor erzeugt wurden. Bei Stylesheets aus<style>- oder<link>-Elementen werfen sie einenNotAllowedError. - Reihenfolge der Kaskade: Übernommene Stylesheets gelten nach den Stylesheets in
document.styleSheets. Bei gleicher Spezifität gewinnen sie also. - Sicherheit: Wer CSS aus Nutzereingaben übernimmt, öffnet die Tür für CSS-Injection. Damit lassen sich über Attributselektoren mit
url()Daten abgreifen. Eine Content Security Policy mitstyle-srcregelt konstruierte Stylesheets dabei nicht wie Inline-Styles. Fremdes CSS sollte deshalb nie ungeprüft eingesetzt werden. - Kompatibilität: Chromium ab Version 73, Firefox ab 101, Safari erst ab 16.4. Für ältere Safari-Versionen braucht man eine Feature-Erkennung mit
<style>als Fallback oder ein Polyfill (construct-style-sheets-polyfill).