Verwendung des CSS Typed Object Model
Die CSS Typed Object Model API stellt CSS-Werte als typisierte JavaScript-Objekte bereit, um eine performante Manipulation zu ermöglichen.
Das Konvertieren von CSS Object Model-Wertestrings in bedeutungsvoll typisierte JavaScript-Darstellungen und zurück (über HTMLElement.style
) kann einen erheblichen Performance-Overhead verursachen.
Das CSS Typed OM macht die CSS-Manipulation logischer und performanter, indem es Objektfunktionen bereitstellt (anstatt die Manipulation von CSSOM-Strings), sowie Zugriff auf Typen, Methoden und ein Objektmodell für CSS-Werte erlaubt.
Dieser Artikel bietet eine Einführung in alle Hauptfunktionen.
computedStyleMap()
Mit der CSS Typed OM API können wir auf alle CSS-Eigenschaften und -Werte zugreifen – einschließlich benutzerdefinierter Eigenschaften –, die ein Element beeinflussen. Schauen wir uns an, wie dies funktioniert, indem wir unser erstes Beispiel erstellen, das computedStyleMap()
untersucht.
Abrufen aller Eigenschaften und Werte
HTML
Wir beginnen mit ein wenig HTML: einem Absatz mit einem Link sowie einer Definitionsliste, zu der wir alle CSS-Eigenschafts-/Wert-Paare hinzufügen werden.
<p>
<a href="https://example.com">Link</a>
</p>
<dl id="regurgitation"></dl>
JavaScript
Wir fügen JavaScript hinzu, um unseren ungestylten Link zu erfassen und eine Definitionsliste aller standardmäßigen CSS-Eigenschaftswerte, die den Link beeinflussen, mit computedStyleMap()
zurückzugeben.
// Get the element
const myElement = document.querySelector("a");
// Get the <dl> we'll be populating
const stylesList = document.querySelector("#regurgitation");
// Retrieve all computed styles with computedStyleMap()
const defaultComputedStyles = myElement.computedStyleMap();
// Iterate through the map of all the properties and values, adding a <dt> and <dd> for each
for (const [prop, val] of defaultComputedStyles) {
// properties
const cssProperty = document.createElement("dt");
cssProperty.appendChild(document.createTextNode(prop));
stylesList.appendChild(cssProperty);
// values
const cssValue = document.createElement("dd");
cssValue.appendChild(document.createTextNode(val));
stylesList.appendChild(cssValue);
}
Die computedStyleMap()
-Methode gibt ein StylePropertyMapReadOnly
-Objekt zurück, das die size
-Eigenschaft enthält, welche angibt, wie viele Eigenschaften sich in der Map befinden. Wir iterieren durch die Style-Map, erstellen ein <dt>
und ein <dd>
für jede Eigenschaft und jeden Wert.
Ergebnis
In Browsern, die computedStyleMap()
unterstützen, wird eine Liste aller CSS-Eigenschaften und Werte angezeigt. In anderen Browsern sehen Sie lediglich einen Link.
Haben Sie bemerkt, wie viele Standard-CSS-Eigenschaften ein Link hat? Ändern Sie den ersten document.querySelector
-Aufruf, um das <p>
anstelle des <a>
auszuwählen. Sie werden einen Unterschied in den standardmäßig berechneten Werten für margin-top
und margin-bottom
feststellen.
.get() Methode / benutzerdefinierte Eigenschaften
Lassen Sie uns unser Beispiel so aktualisieren, dass nur einige wenige Eigenschaften und Werte abgerufen werden. Beginnen wir mit der Hinzufügung einiger CSS-Regeln zu unserem Beispiel, einschließlich einer benutzerdefinierten Eigenschaft und einer vererbbaren Eigenschaft:
p {
font-weight: bold;
}
a {
--color: red;
color: var(--color);
}
Anstatt alle Eigenschaften abzurufen, erstellen wir ein Array von interessierenden Eigenschaften und verwenden die StylePropertyMapReadOnly.get()
-Methode, um jede ihrer Werte abzurufen:
// Get the element
const myElement = document.querySelector("a");
// Get the <dl> we'll be populating
const stylesList = document.querySelector("#regurgitation");
// Retrieve all computed styles with computedStyleMap()
const allComputedStyles = myElement.computedStyleMap();
// Array of properties we're interested in
const ofInterest = ["font-weight", "border-left-color", "color", "--color"];
// iterate through our properties of interest
for (const value of ofInterest) {
// Properties
const cssProperty = document.createElement("dt");
cssProperty.appendChild(document.createTextNode(value));
stylesList.appendChild(cssProperty);
// Values
const cssValue = document.createElement("dd");
cssValue.appendChild(document.createTextNode(allComputedStyles.get(value)));
stylesList.appendChild(cssValue);
}
Wir haben border-left-color
eingeschlossen, um zu demonstrieren, dass für alle Werte, die auf currentcolor
standardmäßig festgelegt sind (wie z. B. caret-color
, outline-color
, text-decoration-color
, column-rule-color
, usw.), rgb(255 0 0)
zurückgegeben würde. Der Link hat font-weight: bold;
von den Absatzstilen geerbt und listet dies als font-weight: 700
. Benutzerdefinierte Eigenschaften, wie unsere --color: red
, sind ebenfalls Eigenschaften und daher über get()
zugänglich.
Sie werden feststellen, dass benutzerdefinierte Eigenschaften den Wert beibehalten, wie er im Stylesheet geschrieben wurde, während berechnete Stile als berechneter Wert angezeigt werden – color
wird als rgb()
-Wert angezeigt und der zurückgegebene font-weight
war 700
, obwohl wir eine benannte Farbe und das Schlüsselwort bold
verwendet haben.
CSSUnitValue und CSSKeywordValue
Die Stärke des CSS Typed OM liegt darin, dass Werte getrennt von Einheiten sind; das Parsen und Konkatenieren von Stringwerten könnte der Vergangenheit angehören. Jede CSS-Eigenschaft in einer Style-Map hat einen Wert. Ist der Wert ein Schlüsselwort, wird ein CSSKeywordValue
-Objekt zurückgegeben. Ist der Wert numerisch, wird ein CSSUnitValue
zurückgegeben.
CSSKeywordValue
ist eine Klasse, die Schlüsselwörter wie inherit
, initial
, unset
und andere Nicht-quote-Zeichenfolgen wie auto
und grid
definiert. Diese Unterklasse gibt eine value
-Eigenschaft über cssKeywordValue.value
zurück.
CSSUnitValue
wird zurückgegeben, wenn der Wert ein Einheitentyp ist. Es handelt sich um eine Klasse, die Zahlen mit Maßeinheiten wie 20px
, 40%
, 200ms
oder 7
definiert. Sie wird mit zwei Eigenschaften zurückgegeben: einem value
und einer unit
. Mit diesem Typ können wir auf den numerischen Wert zugreifen — cssUnitValue.value
— und auf seine Einheit — cssUnitValue.unit
.
Schreiben wir einen einfachen Absatz, wenden keine Stile an und untersuchen einige seiner CSS-Eigenschaften, indem wir eine Tabelle mit Einheit und Wert zurückgeben:
<p>
This is a paragraph with some content. Open up this example in CodePen or
JSFiddle, and change some features. Try adding some CSS, such as a width
for this paragraph, or adding a CSS property to the ofInterest array.
</p>
<table id="regurgitation">
<thead>
<tr>
<th>Property</th>
<th>Value</th>
<th>Unit</th>
</tr>
</table>
Für jede interessierende Eigenschaft listen wir den Namen der Eigenschaft auf, verwenden .get(propertyName).value
, um den Wert zurückzugeben, und, wenn das von get()
zurückgegebene Objekt ein CSSUnitValue
ist, listen wir den Einheitstyp auf, den wir mit .get(propertyName).unit
abrufen.
// Get the element we're inspecting
const myElement = document.querySelector("p");
// Get the table we'll be populating
const stylesTable = document.querySelector("#regurgitation");
// Retrieve all computed styles with computedStyleMap()
const allComputedStyles = myElement.computedStyleMap();
// Array of properties we're interested in
const ofInterest = [
"padding-top",
"margin-bottom",
"font-size",
"font-stretch",
"animation-duration",
"animation-iteration-count",
"width",
"height",
];
// Iterate through our properties of interest
for (const value of ofInterest) {
// Create a row
const row = document.createElement("tr");
// Add the name of the property
const cssProperty = document.createElement("td");
cssProperty.appendChild(document.createTextNode(value));
row.appendChild(cssProperty);
// Add the unitless value
const cssValue = document.createElement("td");
// Shrink long floats to 1 decimal point
let propVal = allComputedStyles.get(value).value;
propVal = propVal % 1 ? propVal.toFixed(1) : propVal;
cssValue.appendChild(document.createTextNode(propVal));
row.appendChild(cssValue);
// Add the type of unit
const cssUnit = document.createElement("td");
cssUnit.appendChild(
document.createTextNode(allComputedStyles.get(value).unit),
);
row.appendChild(cssUnit);
// Add the row to the table
stylesTable.appendChild(row);
}
Für diejenigen von Ihnen, die einen Browser ohne Unterstützung verwenden, sollte die obige Ausgabe so aussehen:
Eigenschaft | Wert | Einheit |
---|---|---|
padding-top |
0 | px |
margin-bottom |
16 | px |
font-size |
16 | px |
font-stretch |
100 | % |
animation-duration |
0 | px |
animation-iteration-count |
1 | number |
width |
auto | undefined |
height |
auto | undefined |
Sie werden feststellen, dass die Einheit <length>
als px
zurückgegeben wird, <percentage>
als percent
, <time>
als s
für 'Sekunden' und die einheitslose Einheit <number>
als number
.
Wir haben keine width
oder height
für den Absatz deklariert, die beide standardmäßig auto
sind und daher einen CSSKeywordValue
anstelle eines CSSUnitValue
zurückgeben. CSSKeywordValue
s haben keine Einheit-Eigenschaft, sodass in diesen Fällen unser get().unit
undefined
zurückgibt.
Wären width
oder height
in einem <length>
oder <percent>
definiert, wäre die Einheit des CSSUnitValue
px
bzw. percent
.
Es gibt weitere verfügbare Typen:
- Ein
<image>
gibt einenCSSImageValue
zurück. - Ein
<color>
gibt einenCSSStyleValue
zurück. - Ein
transform
gibt einenCSSTransformValue
zurück. - Eine benutzerdefinierte Eigenschaft gibt einen
CSSUnparsedValue
zurück.
Sie können einen CSSUnitValue
oder CSSKeywordValue
verwenden, um andere Objekte zu erstellen.
CSSStyleValue
Die CSSStyleValue
-Schnittstelle des CSS Typed Object Model API ist die Basisklasse aller CSS-Werte, die über die Typed OM API zugänglich sind, einschließlich CSSImageValue
, CSSKeywordValue
, CSSNumericValue
, CSSPositionValue
, CSSTransformValue
und CSSUnparsedValue
.
Sie verfügt über zwei Methoden:
Wie oben erwähnt, gibt StylePropertyMapReadOnly.get('--customProperty')
einen CSSUnparsedValue
zurück. Wir können Instanzen von CSSUnparsedValue
-Objekten mit den geerbten Methoden CSSStyleValue.parse()
und CSSStyleValue.parseAll()
parsen.
Lassen Sie uns ein CSS-Beispiel mit mehreren benutzerdefinierten Eigenschaften, Transformationen, calc()
-Funktionen und anderen Features untersuchen. Wir werfen einen Blick darauf, welche Typen sie haben, indem wir kurze JavaScript-Ausschnitte verwenden, die in console.log()
ausgeben:
:root {
--mainColor: hsl(198 43% 42%);
--black: hsl(0 0% 16%);
--white: hsl(0 0% 97%);
--unit: 1.2rem;
}
button {
--mainColor: hsl(198 100% 66%);
display: inline-block;
padding: var(--unit) calc(var(--unit) * 2);
width: calc(30% + 20px);
background: no-repeat 5% center url(magic-wand.png) var(--mainColor);
border: 4px solid var(--mainColor);
border-radius: 2px;
font-size: calc(var(--unit) * 2);
color: var(--white);
cursor: pointer;
transform: scale(0.95);
}
Fügen wir die Klasse einem Button (einem Button, der nichts tut) hinzu.
<button>Styled Button</button>
Wir rufen unsere StylePropertyMapReadOnly
mit folgendem JavaScript ab:
const allComputedStyles = document.querySelector("button").computedStyleMap();
Die folgenden Beispiele beziehen sich auf allComputedStyles
:
CSSUnparsedValue
Der CSSUnparsedValue
repräsentiert benutzerdefinierte Eigenschaften:
// CSSUnparsedValue
const unit = allComputedStyles.get("--unit");
console.log(unit); // CSSUnparsedValue {0: " 1.2rem", length: 1}
console.log(unit[0]); // " 1.2rem"
Wenn wir get()
aufrufen, wird eine benutzerdefinierte Eigenschaft vom Typ CSSUnparsedValue
zurückgegeben. Beachten Sie das Leerzeichen vor dem 1.2rem
. Um Einheit und Wert zu erhalten, benötigen wir einen CSSUnitValue
, den wir mit der Methode CSSStyleValue.parse()
auf der CSSUnparsedValue
abrufen können.
const parsedUnit = CSSNumericValue.parse(unit);
console.log(parsedUnit); // CSSUnitValue {value: 1.2, unit: "rem"}
console.log(parsedUnit.unit); // "rem"
console.log(parsedUnit.value); // 1.2
CSSMathSum
Obwohl das <button>
-Element standardmäßig ein Inline-Element ist, haben wir display: inline-block;
hinzugefügt, um Größenänderungen zu ermöglichen. In unserem CSS haben wir width: calc(30% + 20px);
, was eine calc()
-Funktion zur Definition der Breite ist.
Wenn wir get()
für die width
aufrufen, erhalten wir einen CSSMathSum
zurück. CSSMathSum.values
ist ein CSSNumericArray
mit 2 CSSUnitValues
.
Der Wert von CSSMathValue.operator
ist sum
:
const btnWidth = allComputedStyles.get("width");
console.log(btnWidth); // CSSMathSum
console.log(btnWidth.values); // CSSNumericArray {0: CSSUnitValue, 1: CSSUnitValue, length: 2}
console.log(btnWidth.operator); // 'sum'
CSSTransformValue mit CSSScale
Das display: inline-block;
ermöglicht auch Transformationen. In unserem CSS haben wir transform: scale(0.95);
, was eine transform
-Funktion ist.
const transform = allComputedStyles.get("transform");
console.log(transform); // CSSTransformValue {0: CSSScale, 1: CSSTranslate, length: 2, is2D: true}
console.log(transform.length); // 1
console.log(transform[0]); // CSSScale {x: CSSUnitValue, y: CSSUnitValue, z: CSSUnitValue, is2D: true}
console.log(transform[0].x); // CSSUnitValue {value: 0.95, unit: "number"}
console.log(transform[0].y); // CSSUnitValue {value: 0.95, unit: "number"}
console.log(transform[0].z); // CSSUnitValue {value: 1, unit: "number"}
console.log(transform.is2D); // true
Wenn wir get()
für die transform
-Eigenschaft aufrufen, erhalten wir einen CSSTransformValue
. Wir können die Länge (oder Anzahl) der Transformationsfunktionen mit der length
-Eigenschaft abfragen.
Da wir eine Länge von 1
haben, die für eine einzelne Transformationsfunktion steht, protokollieren wir das erste Objekt und erhalten ein CSSScale
-Objekt. Wir erhalten CSSUnitValues
, wenn wir die x
-, y
- und z
-Skalierung abfragen. Die schreibgeschützte Eigenschaft CSSScale.is2D
ist in diesem Szenario true
.
Hätten wir translate()
, skew()
und rotate()
-Transformationsfunktionen hinzugefügt, wäre die Länge 4
, jede mit ihren eigenen x
-, y
-, z
-Werten und jeder mit einer .is2D
-Eigenschaft. Beispielsweise hätte transform: translate3d(1px, 1px, 3px)
in .get('transform')
einen CSSTranslate
mit CSSUnitValues
für x
, y
und z
zurückgegeben, und die schreibgeschützte .is2D
-Eigenschaft wäre false
gewesen.
CSSImageValue
Unser Button hat ein Hintergrundbild: einen Zauberstab.
const bgImage = allComputedStyles.get("background-image");
console.log(bgImage); // CSSImageValue
console.log(bgImage.toString()); // url("magic-wand.png")
Wenn wir get()
für 'background-image'
aufrufen, wird ein CSSImageValue
zurückgegeben. Während wir die CSS-background
-Kurzschreibweise verwendet haben, zeigt die vererbte Object.prototype.toString()
-Methode, dass wir nur das Bild 'url("magic-wand.png")'
zurückgegeben haben.
Beachten Sie, dass der zurückgegebene Wert der absolute Pfad zum Bild ist – dies wird auch zurückgegeben, wenn der ursprüngliche url()
-Wert relativ war. Hätte das Hintergrundbild ein Gradient oder mehrere Hintergrundbilder gehabt, hätte .get('background-image')
einen CSSStyleValue
zurückgegeben. Der CSSImageValue
wird nur dann zurückgegeben, wenn ein einziges Bild vorhanden ist und wenn diese einzelne Bilddeklaration eine URL ist.
Zusammenfassung
Dies sollte Ihnen einen Start zur Verständnis des CSS Typed OM geben. Werfen Sie einen Blick auf alle CSS Typed OM-Schnittstellen, um mehr zu erfahren.