Verwendung des CSS Typed Object Model
Die CSS Typed Object Model API stellt CSS-Werte als typisierte JavaScript-Objekte zur Verfügung, um deren performante Manipulation zu ermöglichen.
Das Konvertieren von CSS Object Model Wert-Strings in sinnvoll typisierte JavaScript-Darstellungen und zurück (über HTMLElement.style
) kann zu einem erheblichen Leistungsaufwand führen.
Das CSS Typed OM macht die CSS-Manipulation logischer und performanter, indem es Objektfeatures bereitstellt (statt CSSOM-String-Manipulation) und den Zugriff auf Typen, Methoden und ein Objektmodell für CSS-Werte ermöglicht.
Dieser Artikel bietet eine Einführung in alle seine Hauptmerkmale.
computedStyleMap()
Mit der CSS Typed OM API können wir auf alle CSS-Eigenschaften und -Werte – einschließlich benutzerdefinierter Eigenschaften – zugreifen, die ein Element beeinflussen. Sehen wir uns an, wie das 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-Eigenschaft-/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 Standard-CSS-Eigenschaftswerte zurückzugeben, die den Link mit 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 Methode computedStyleMap()
gibt ein StylePropertyMapReadOnly
-Objekt zurück, das die Eigenschaft size
enthält, die angibt, wie viele Eigenschaften sich in der Karte befinden. Wir iterieren durch die Stilkarte und erstellen je nach Eigenschaft und Wert ein <dt>
und ein <dd>
.
Ergebnis
In Browsern, die computedStyleMap()
unterstützen, sehen Sie eine Liste aller CSS-Eigenschaften und Werte. In anderen Browsern sehen Sie nur einen Link.
Wussten Sie, wie viele Standard-CSS-Eigenschaften ein Link hat? Aktualisieren Sie den ersten document.querySelector
-Aufruf, um das <p>
anstelle des <a>
auszuwählen. Sie werden einen Unterschied bei den Standardwerten von margin-top
und margin-bottom
feststellen.
.get() Methode / benutzerdefinierte Eigenschaften
Lassen Sie uns unser Beispiel aktualisieren, um nur ein paar Eigenschaften und Werte abzurufen. Beginnen wir damit, unserem Beispiel etwas 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 Methode StylePropertyMapReadOnly.get()
, 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
hinzugefügt, um zu demonstrieren, dass, falls wir alle Eigenschaften einbezogen hätten, jeder Wert, der auf currentcolor
standardisiert wird (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 Stilvorgaben des Absatzes geerbt und listet es als font-weight: 700
auf. Benutzerdefinierte Eigenschaften, wie unser --color: red
, sind Eigenschaften. Daher sind sie über get()
zugänglich.
Sie werden feststellen, dass benutzerdefinierte Eigenschaften den Wert im Stylesheet behalten, während berechnete Stile als der berechnete Wert aufgeführt werden – color
wurde als rgb()
-Wert aufgelistet 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 Zusammenfügen von String-Werten könnte der Vergangenheit angehören. Jede CSS-Eigenschaft in einer Stilkarte hat einen Wert. Wenn der Wert ein Schlüsselwort ist, wird das Objekt zurückgegeben, ist ein CSSKeywordValue
. 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 Strings wie auto
und grid
definiert. Diese Unterklasse bietet Ihnen eine value
-Eigenschaft über cssKeywordValue.value
.
CSSUnitValue
wird zurückgegeben, wenn der Wert ein Einheitstyp ist. Es ist eine Klasse, die Zahlen mit Messeinheiten 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 — cssUnitValue.value
— und seine Einheit — cssUnitValue.unit
— zugreifen.
Schreiben wir einen einfachen Absatz, wenden keine Stile an und überprüfen 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 interessante 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 nicht unterstützenden Browser verwenden, sollte die oben stehende Ausgabe in etwa 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 | Nummer |
width |
auto | undefiniert |
height |
auto | undefiniert |
Sie werden feststellen, dass die <length>
Einheit px
zurückgegeben wird, die <percentage>
Einheit percent
und die <time>
Einheit s
für 'seconds' ist, und die einheitslose <number>
Einheit Nummer
ist.
Wir haben keine width
oder height
für den Absatz festgelegt, von denen beide auf auto
standardmäßig gesetzt sind und daher ein CSSKeywordValue
anstelle eines CSSUnitValue
zurückgeben. CSSKeywordValue
s haben keine Einheits-Eigenschaft, sodass in diesen Fällen unser get().unit
undefined
zurückgibt.
Hätten wir die width
oder height
als <length>
oder <percent>
definiert, wäre die Einheit des CSSUnitValue
px
oder percent
gewesen.
Es sind weitere Typen verfügbar:
- Ein
<image>
gibt einenCSSImageValue
zurück. - Ein
<color>
würde einCSSStyleValue
zurückgeben. - Ein
transform
gibt einCSSTransformValue
zurück. - Eine benutzerdefinierte Eigenschaft gibt ein
CSSUnparsedValue
zurück.
Sie können ein CSSUnitValue
oder CSSKeywordValue
verwenden, um andere Objekte zu erstellen.
CSSStyleValue
Die CSSStyleValue
-Schnittstelle der 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 hat zwei Methoden:
Wie oben erwähnt, gibt StylePropertyMapReadOnly.get('--customProperty')
ein CSSUnparsedValue
zurück. Wir können CSSUnparsedValue
-Objektinstanzen mit den geerbten Methoden CSSStyleValue.parse()
und CSSStyleValue.parseAll()
parsen.
Sehen wir uns ein CSS-Beispiel mit mehreren benutzerdefinierten Eigenschaften, Transformationen, calc()
s und anderen Funktionen an. Wir werden uns ansehen, welche Typen sie haben, indem wir kurze JavaScript-Ausschnitte verwenden, die zur 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 (ein Button, der nichts tut).
<button>Styled Button</button>
Wir erfassen unsere StylePropertyMapReadOnly
mit dem folgenden JavaScript:
const allComputedStyles = document.querySelector("button").computedStyleMap();
Die folgenden Beispiele beziehen sich auf allComputedStyles
:
CSSUnparsedValue
Das CSSUnparsedValue
stellt benutzerdefinierte Eigenschaften dar:
// 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 den Abstand vor 1.2rem
. Um eine Einheit und einen Wert zu erhalten, benötigen wir ein CSSUnitValue
, das wir mithilfe der Methode CSSStyleValue.parse()
für das 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 die Größenanpassung zu aktivieren. In unserem CSS haben wir width: calc(30% + 20px);
, was eine calc()
-Funktion ist, um die Breite zu definieren.
Wenn wir die width
get()
abrufen, erhalten wir einen CSSMathSum
zurück. CSSMathSum.values
ist ein CSSNumericArray
mit 2 CSSUnitValues
.
Der Wert des 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 die Transformation. 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()
, erhalten wir ein 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 eine einzelne Transformationsfunktion darstellt, 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 CSSScale.is2D
-Eigenschaft 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 jeweils einer .is2D
-Eigenschaft. Wenn wir zum Beispiel transform: translate3d(1px, 1px, 3px)
hinzugefügt hätten, würde das .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: ein Zauberstab.
const bgImage = allComputedStyles.get("background-image");
console.log(bgImage); // CSSImageValue
console.log(bgImage.toString()); // url("magic-wand.png")
Wenn wir die 'background-image'
get()
, wird ein CSSImageValue
zurückgegeben. Während wir die CSS-background
-Kurzform 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 — dieser wird auch zurückgegeben, wenn der ursprüngliche url()
-Wert relativ war. Wäre das Hintergrundbild ein Gradient oder mehrere Hintergrundbilder, würde .get('background-image')
ein CSSStyleValue
zurückgeben. Das CSSImageValue
wird nur zurückgegeben, wenn es ein einzelnes Bild gibt und nur, wenn diese eine Bilddeklaration eine URL ist.
Zusammenfassung
Das sollte Ihnen den Einstieg in das Verständnis des CSS Typed OM erleichtern. Schauen Sie sich alle CSS Typed OM Schnittstellen an, um mehr zu erfahren.