Verwendung des CSS Typed Object Model
Die CSS Typed Object Model API stellt CSS-Werte als typisierte JavaScript-Objekte bereit, um ihre performante Manipulation zu ermöglichen.
Das Konvertieren von CSS Object Model-Wertstrings in sinnvoll 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 leistungsfähiger, indem es Objektfunktionen (anstatt CSSOM-String-Manipulation) bereitstellt, Zugriff auf Typen, Methoden und ein Objektmodell für CSS-Werte bietet.
Dieser Artikel bietet eine Einführung in alle seine 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. Sehen wir uns an, wie dies funktioniert, indem wir unser erstes Beispiel erstellen, das computedStyleMap()
untersucht.
Abrufen aller Eigenschaften und Werte
HTML
Wir beginnen mit etwas HTML: einem Absatz mit einem Link sowie einer Definitionsliste, zu der wir alle CSS-Eigenschafts-/Werte-Paare hinzufügen.
<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 Standard-CSS-Eigenschaftswerte zurückzugeben, die den Link mithilfe von computedStyleMap()
beeinflussen.
// 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, die angibt, wie viele Eigenschaften sich in der Karte befinden. Wir iterieren durch die Stilkarte und erstellen ein <dt>
und <dd>
für jede Eigenschaft bzw. jeden Wert.
Ergebnis
In Browsern, die computedStyleMap()
unterstützen, sehen Sie eine Liste aller CSS-Eigenschaften und -Werte. In anderen Browsern sehen Sie nur einen Link.
Haben Sie erkannt, wie viele Standard-CSS-Eigenschaften ein Link hatte? Aktualisieren Sie den ersten document.querySelector
-Aufruf, um das <p>
anstelle des <a>
auszuwählen. Sie werden einen Unterschied in den Standardberechnungswerten von margin-top
und margin-bottom
bemerken.
.get() Methode / benutzerdefinierte Eigenschaften
Lassen Sie uns unser Beispiel aktualisieren, um nur wenige Eigenschaften und Werte abzurufen. Beginnen wir damit, unserem Beispiel einige CSS hinzuzufügen, 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 interessanten Eigenschaften und verwenden die StylePropertyMapReadOnly.get()
-Methode, um jeden ihrer Werte zu erhalten:
// 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, wenn wir alle Eigenschaften eingeschlossen hätten, jeder Wert, der standardmäßig auf currentcolor
gesetzt ist (einschließlich caret-color
, outline-color
, text-decoration-color
, column-rule-color
, usw.) rgb(255 0 0)
zurückgeben würde. Der Link hat font-weight: bold;
von den Stilen des Absatzes geerbt und wird als font-weight: 700
aufgelistet. Benutzerdefinierte Eigenschaften, wie unser --color: red
, sind Eigenschaften. Als solche sind sie ü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 aufgelistet werden — color
wurde als rgb()
-Wert und der zurückgegebene font-weight
war 700
, obwohl wir eine benannte Farbe und das bold
-Schlüsselwort verwenden.
CSSUnitValue und CSSKeywordValue
Die Stärke des CSS Typed OM besteht darin, dass Werte von Einheiten getrennt sind; das Parsen und Verketten von Zeichenfolgenwerten kann der Vergangenheit angehören. Jede CSS-Eigenschaft in einer Stilkarte hat einen Wert. Wenn der Wert ein Schlüsselwort ist, wird ein CSSKeywordValue
-Objekt zurückgegeben. Wenn der Wert numerisch ist, wird ein CSSUnitValue
zurückgegeben.
CSSKeywordValue
ist eine Klasse, die Schlüsselwörter wie inherit
, initial
, unset
und andere nicht zitierte Zeichenfolgen definiert, wie auto
und grid
. Diese Unterklasse bietet Ihnen eine value
-Eigenschaft über cssKeywordValue.value
.
CSSUnitValue
wird zurückgegeben, wenn der Wert ein Einheitentyp ist. Es ist eine Klasse, die Zahlen mit Einheitseinheiten wie 20px
, 40%
, 200ms
oder 7
definiert. Es wird mit zwei Eigenschaften zurückgegeben: einem value
und einer unit
. Mit diesem Typ können wir auf den numerischen Wert — cssUnitValue.value
— und seine Einheit — cssUnitValue.unit
zugreifen.
Lassen Sie uns einen einfachen Absatz schreiben, keine Stile anwenden und einige seiner CSS-Eigenschaften durch die Rückgabe einer Tabelle mit der Einheit und dem Wert inspizieren:
<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>
</thead>
</table>
Für jede interessante Eigenschaft listen wir den Namen der Eigenschaft auf, verwenden .get(propertyName).value
, um den Wert zurückzugeben, und, falls das von get()
zurückgegebene Objekt ein CSSUnitValue
ist, den Einheitstyp, den wir mit .get(propertyName).unit
erhalten.
// 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 unter Ihnen, die einen nicht unterstützenden Browser verwenden, sollte die obige Ausgabe ungefähr 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 | undefiniert |
height |
auto | undefiniert |
Sie werden feststellen, dass die <length>
-Einheit px
zurückgegeben wird, die <percentage>
-Einheit percent
, die <time>
-Einheit s
für 'Sekunden' ist und die einheitslose <number>
-Einheit number
ist.
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. CSSKeywordValues
haben keine Einheit-Eigenschaft, daher gibt unser get().unit
in diesen Fällen undefined
zurück.
Wäre die width
oder height
in einem <length>
oder <percent>
definiert gewesen, hätte die CSSUnitValue
-Einheit px
oder percent
betragen.
Es gibt noch weitere Typen:
- Ein
<image>
gibt einenCSSImageValue
zurück. - Ein
<color>
würde einenCSSStyleValue
zurückgeben. - 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
Das CSSStyleValue
-Interface 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
.
Es hat zwei Methoden:
Wie oben erwähnt, gibt StylePropertyMapReadOnly.get('--customProperty')
einen CSSUnparsedValue
zurück. Wir können Instanzen von CSSUnparsedValue
-Objekten mit den geerbten CSSStyleValue.parse()
und CSSStyleValue.parseAll()
-Methoden analysieren.
Schauen wir uns ein CSS-Beispiel mit mehreren benutzerdefinierten Eigenschaften, Transformationen, calc()
s und anderen Funktionen an. Wir werden uns ansehen, was ihre Typen sind, indem wir kurze JavaScript-Snippets verwenden, die auf 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 zu einem Button hinzu (einem Button, der nichts tut).
<button>Styled Button</button>
Wir erhalten unseren StylePropertyMapReadOnly
mit folgendem JavaScript:
const allComputedStyles = document.querySelector("button").computedStyleMap();
Die folgenden Beispiele verweisen 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 des Typs CSSUnparsedValue
zurückgegeben. Beachten Sie das Leerzeichen vor dem 1.2rem
. Um eine Einheit und einen Wert zu erhalten, benötigen wir einen CSSUnitValue
, den wir mit der CSSStyleValue.parse()
-Methode auf dem 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 das Größenverhalten zu ermöglichen. In unserem CSS haben wir width: calc(30% + 20px);
, was eine calc()
-Funktion ist, um die Breite zu definieren.
Wenn wir get()
auf die width
anwenden, erhalten wir ein CSSMathSum
zurückgegeben. 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 die transform
-Eigenschaft get()
-en, erhalten wir eine CSSTransformValue
. Wir können die Länge (oder die Anzahl) der Transformationsfunktionen mit der length
-Eigenschaft abfragen.
Da wir eine Länge von 1
haben, die eine einzelne Transformationsfunktion repräsentiert, 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 Fall 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 jeweils einer .is2D
-Eigenschaft. Zum Beispiel, hätten wir transform: translate3d(1px, 1px, 3px)
eingeschlossen, würde .get('transform')
ein CSSTranslate
mit CSSUnitValues
für x
, y
und z
zurückgeben, und die schreibgeschützte .is2D
-Eigenschaft wäre false
.
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 'background-image'
get()
-en, wird ein CSSImageValue
zurückgegeben. Während wir die CSS background
-Kurzschreibweise verwendet haben, zeigt die geerbte 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 zurückgegeben, selbst wenn der ursprüngliche url()
-Wert relativ war. Wäre das Hintergrundbild ein Gradient oder mehrere Hintergrundbilder gewesen, hätte .get('background-image')
ein CSSStyleValue
zurückgegeben. Der CSSImageValue
wird nur zurückgegeben, wenn es sich um ein einzelnes Bild handelt und nur dann, wenn diese einzelne Bilddeklaration eine URL ist.
Zusammenfassung
Dies sollte Ihnen einen Start beim Verständnis des CSS Typed OM geben. Schauen Sie sich alle CSS Typed OM-Interfaces an, um mehr zu lernen.