Ein Interview mit Elad Shechter über "The New CSS Reset"

Avatar of Elad Shechter
Elad Shechter am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Hallo Leute! Elad hat sich an mich gewandt, um mir sein neues CSS-Reset-Projekt namens the-new-css-reset zu zeigen. Es ist ziemlich interessant! Ich dachte, eine nette Art, es mit euch zu teilen, ist nicht nur, euch darauf hinzuweisen, sondern Elad einige Fragen dazu für euer Lesevergnügen zu stellen.

Hier ist der gesamte Code für das Reset vorab

/*** The new CSS Reset - version 1.2.0 (last updated 23.7.2021) ***/

/* Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property */
*:where(:not(iframe, canvas, img, svg, video):not(svg *)) {
  all: unset;
  display: revert;
}

/* Preferred box-sizing value */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/*
  Remove list styles (bullets/numbers)
  in case you use it with normalize.css
*/
ol, ul {
  list-style: none;
}

/* For images to not be able to exceed their container */
img {
  max-width: 100%;
}

/* Removes spacing between cells in tables */
table {
  border-collapse: collapse;
}

/* Revert the 'white-space' property for textarea elements on Safari */
textarea {
  white-space: revert;
}

Zuerst einmal gibt es zwei Ansätze, wenn wir über "CSS-Resets" sprechen

  • Nicolas Gallaghers Normalize.css ist der sanfte Ansatz. Normalize.css behebt Unterschiede in der Implementierung zwischen verschiedenen Browsern.
  • Eric Meyers CSS Reset ist der harte Ansatz, der besagt, dass wir in den meisten Fällen keine grundlegenden Stile von den Browsern wollen, wie z. B. den font-size-Wert, den wir von Elementen wie <h1> bis <h6> erhalten, oder die Standardstile für die Listen-Elemente <ul> und <ol>. Wir verwenden die Liste zum Beispiel nur wegen ihrer semantischen Bedeutung, und weil sie auch in anderer Hinsicht für Barrierefreiheit und SEO hilfreich ist.

Ich liebe Normalize.css. Ich denke, es ist ein Muss in jedem Projekt, auch wenn man die CSS-Reset-Idee bevorzugt.

Und warum ist Normalize.css so wichtig? Normalize.css greift auf Shadow DOM-Elemente zu, die der CSS Reset nicht berührt. Wenn man sich Normalize.css ansieht, findet man spezielle Pseudoklassen wie ::-moz-focus-inner, ::-webkit-file-upload-button und mehr. Es deckt so viele Bereiche ab, und deshalb glaube ich, dass Normalize.css ein Muss in jedem Projekt ist.

Ich liebe den harten CSS Reset auch. Ich denke, in den meisten Fällen wollen wir nicht die grundlegenden Stile des Browsers, und wenn wir sie an einer bestimmten Stelle brauchen, definieren wir sie nach unseren Bedürfnissen. Das bringt mich zu dem Punkt, dass ich sowohl Normalize.css als auch CSS Reset kombiniert verwende. Normalize.css wird also zuerst geladen, gefolgt von dem harten CSS Reset.

Warum brauchen wir also ein neues CSS Reset? Die vorhandenen CSS Resets basieren auf alten CSS-Funktionen. Aber in den letzten Jahren haben wir neue Funktionen erhalten, die speziell für das Zurücksetzen von Dingen in CSS entwickelt wurden, und das hat mich denken lassen, dass wir jetzt mit diesen neuen, hochmodernen CSS-Funktionen ein viel valideres CSS Reset erstellen können.

Für mich scheint der saftigste Teil hier dieser allererste Regelsatz zu sein. Beginnen wir mit der ersten CSS-Eigenschaft und dem ersten Wert: all: unset;. Das ist es doch, was die Hauptarbeit in diesem CSS-Reset leistet? Wie funktioniert das?

all ist die außergewöhnlichste CSS-Eigenschaft, da sie es uns ermöglicht, alle vorhandenen CSS-Eigenschaften auf einmal zurückzusetzen.

Die Eigenschaft akzeptiert mehrere Schlüsselwörter. Die beiden grundlegenden sind initial und inherit; es gibt zwei intelligentere, nämlich unset und revert. Um zu verstehen, was all: unset bewirkt, müssen wir zum grundlegenden Verhalten unserer CSS-Eigenschaften springen.

In CSS haben wir zwei Gruppen von Eigenschaften

  • Gruppe der vererbten Eigenschaften: Dies sind Eigenschaften, die standardmäßig vererbt werden – hauptsächlich Typografie-Eigenschaften.
  • Gruppe der nicht vererbten Eigenschaften: Dies sind alle anderen Eigenschaften, die nicht standardmäßig vererbt werden, z. B. die Box-Model-Eigenschaften, zu denen padding, border und margin gehören.

Wie bei den Typografie-Eigenschaften möchten wir das inherit-Verhalten beibehalten, wenn wir versuchen, sie zurückzusetzen. Dort können wir also den Schlüsselwortwert inherit verwenden.

/* Will get values from the parent element value */
font-size: inherit;  
line-height: inherit;
color: inherit;

Für die anderen Eigenschaften in der Gruppe der nicht vererbten Eigenschaften möchten wir in den meisten Fällen deren Anfangswert erhalten. Es ist erwähnenswert, dass das initial-Schlüsselwort für verschiedene Eigenschaften unterschiedlich berechnet wird.

max-width: initial; /* = none */ 
width: initial; /* auto */
position: initial; /* = static */

Nachdem wir die Grundlagen sowie die Schlüsselwortwerte inherit und initial verstanden haben, begreifen wir, dass wir, wenn wir alle Eigenschaften zusammen zurücksetzen wollen, diese nicht direkt mit der all-Eigenschaft verwenden können. Denn wenn wir alle Eigenschaften auf den Anfangswert zurücksetzen, d. h. all: initial, verlieren wir das inhärente Verhalten bei den vererbten Eigenschaften. Und wenn wir alle Eigenschaften mit dem Wert inherit zurücksetzen. In diesem Fall erbt alles, selbst Box-Model-Eigenschaften, die wir vermeiden wollen.

Deshalb haben wir den Wert unset. unset setzt die Eigenschaft entsprechend ihrem Typ zurück. Wenn wir sie auf eine vererbte Eigenschaft anwenden, ist sie gleichbedeutend mit inherit; wenn wir sie auf eine natürliche, nicht vererbte Eigenschaft anwenden, ist sie gleichbedeutend mit initial.

max-width: unset; /* = initial = none */
font-size: unset; /* = inherit = get parent element value */ 

Das bringt uns zurück zur Hauptfunktion meines CSS-Resets. Was all: unset tut, ist, alle vererbten Eigenschaften auf den Wert inherit und alle anderen Eigenschaften in der Gruppe der nicht vererbten Eigenschaften auf ihren initial-Wert zurückzusetzen.

Diese Operation entfernt alle Standard-User-Agent-Stylesheet-Stile, die der Browser hinzufügt. Um diese wesentlichen neuen CSS-Funktionen zu verstehen, geschah all dies, während ich nur eine Operation für alle HTML-Elemente durchführte.

/* 
  Reset all: 
  - Inherited properties to inherit value
  - Non-inherited properties to initial value
*/
* {
  all: unset;
}

Und dann folgen Sie mit display: revert; – macht all: unset; Dinge mit der display-Eigenschaft, die unerwünscht wären?

Kurze Antwort: ja. Die display-Eigenschaft repräsentiert die grundlegende Struktur, die wir aus unserem User-Agent-Stylesheet *wollen*. Wie wir bei den meisten unserer Eigenschaften gesehen haben, leistet der unset-Wert hervorragende Arbeit für uns, und wir setzen alle Eigenschaften in einer Operation zurück.

Um nun zu verstehen, was der einzigartige revert-Schlüsselwortwert für die display-Eigenschaft bewirkt, sprechen wir über die beiden Arten von Stilen, die wir von unseren Browsern erhalten. Die Stile, die wir von unseren Browsern erhalten, sind aus zwei Ebenen aufgebaut

  • Ebene 1, der CSS initial-Wert: Wie wir bereits gesehen haben, ist die erste Ebene der initial-Wert aller unserer CSS-Eigenschaften, einschließlich des inherit-Verhaltens bei einigen Eigenschaften.
  • Ebene 2, das User-Agent-Stylesheet: Dies sind die Stile, die der Browser für bestimmte HTML-Elemente definiert.

In den meisten Fällen, wenn wir Dinge zurücksetzen wollen, wollen wir die grundlegenden Stile von Ebene 2 entfernen. Und wenn wir mit all: unset zurücksetzen, entfernen wir alle Stile des User-Agent-Stylesheets.

Aber die display-Eigenschaft ist eine Ausnahme. Wie wir bereits gesehen haben, hat jede Eigenschaft in CSS nur einen Anfangswert. Das bedeutet, dass, wenn wir die display-Eigenschaft auf ihren Anfangswert zurücksetzen, wie bei einem <div>-Element oder jedem anderen HTML-Element, dieser immer den Wert inline zurückgibt.

Wenn wir dieser Logik weiter folgen, verbinden wir das <div>-Element mit der Standarddeklaration display: block, die wir von Browsern erhalten. Aber dieses Verhalten erhalten wir nur wegen Ebene 2, dem User-Agent-Stylesheet, das diese definiert. Es basiert auf derselben Idee, dass die font-size bei Überschriften-Elementen, <h1> bis <h6>, größer ist als bei anderen HTML-Elementen.

div { 
  display: unset; /* = inline */ 
}
span { 
  display: unset; /* = inline */ 
}
table { 
  display: unset; /* = inline */ 
}
/* or any other HTML element will get inline value */

Das ist natürlich unerwünschtes Verhalten. Die display-Eigenschaft ist die einzige Ausnahme, die wir von unserem Browser erhalten wollen. Aus diesem Grund verwende ich den einzigartigen Schlüsselwortwert revert, um den Standardwert display aus dem User-Agent-Stylesheet zurückzuholen.

Der revert-Wert ist einzigartig. Zuerst prüft er, ob es einen Standardstil für die spezifische Eigenschaft im User-Agent-Stylesheet für das spezifische HTML-Element gibt, auf dem er sitzt, und wenn er ihn findet, nimmt er ihn. Wenn er ihn nicht findet, verhält sich revert wie der unset-Wert, was bedeutet, dass, wenn die Eigenschaft standardmäßig eine vererbte Eigenschaft ist, sie den Wert inherit verwendet; wenn nicht, verwendet sie den Wert initial.

Eine Grafik aller CSS-Reset-Schlüsselwörter

Dann sind diese beiden Regeln innerhalb eines Regelsatzes mit einem Selektor, bei dem Sie *fast* alles auswählen. Es sieht so aus, als würden Sie über den universellen Tag-Selektor (*) alles auf der Seite auswählen, aber dann eine Handvoll Dinge entfernen. Stimmt das? Warum diese spezifischen Dinge anvisieren?

Als ich begann, mir "The New CSS Reset" vorzustellen, dachte ich nicht, dass ich Ausnahmen brauchen würde. Es war in meiner Vorstellung viel einfacher.

Aber als ich anfing, Erfahrungen zu sammeln, ersetzte ich mein altes CSS-Reset durch mein neues CSS-Reset (ohne all die Ausnahmen), und ich sah einige Dinge, die meine alten Projekte, die ich getestet hatte, kaputt machten.

Die Hauptsachen, die kaputt gingen, waren Elemente, die Größen über die Attribute width und height erhalten können – Elemente wie <iframe>, <canvas>, <img>, <svg> und <video>. Leider werden, wenn ich alles zurücksetze, die Breite und Höhe dieser Elemente durch den Wert auto definiert, der stärker ist und die Wirkung der Attribute width und height der Elemente entfernt.

Das kann problematisch sein, weil wir die genaue Größe vom HTML-Element erhalten wollen, wenn wir die Abmessungen über die HTML-Attribute width und height hinzufügen. Wir ziehen es vor, es von HTML zu erhalten, nicht von CSS, denn wenn es von CSS kommt, kann es zu Glitches beim Laden der Seite kommen.

Der einzige Weg, den ich gefunden habe, um den Reset-Effekt für all diese spezifischen Elemente zu entfernen, ist, sie unter den :not()-Selektor zu stellen. In diesem Fall ist mein neues CSS-Reset schädlich und nicht hilfreich, und deshalb habe ich den Effekt für diese spezifischen Elemente entfernt.

Die Spezifität gering zu halten scheint wichtig für ein Reset zu sein, damit man sich nicht mit dem Reset selbst auseinandersetzen muss. Ist das die Idee hinter :where()?

Ja, die Idee von :where() ist es, die Spezifität zu entfernen. Wir müssen keine höhere Spezifität in unserem CSS beschreiben, nur um das CSS-Reset zu überschreiben.

Im Allgemeinen denke ich, dass wir bald viele weitere Fälle sehen werden, in denen :where() Dinge umhüllt, um ihre Spezifität zu entfernen, und nicht nur, um mehrere Selektoren zu ersetzen.

Es sieht so aus, als ob einige besondere Vorkehrungen für Kinder von <svg> getroffen wurden. Worum geht es dabei?

Der zweite Fall, :not(svg *), wird mit einem separaten :not() gemacht, nur weil es um ein anderes Problem geht. Das Berühren der inneren Elemente eines SVG kann das visuelle Bild beeinträchtigen, und dies ist eines der Dinge, bei denen es keinen vernünftigen Grund gibt, den Browser zu stören.

Lassen Sie das Bild ein Bild sein, sage ich.

Nach dem großen Reset-Teil folgen einige Teile, die meinungsfreudiger sind. Zum Beispiel gibt es keine Browser-Meinungsverschiedenheiten bezüglich des Anfangswerts von box-sizing, aber Sie ändern ihn trotzdem. Ich bin selbst ein Fan davon, aber ich bin neugierig auf die Philosophie, was in ein Reset einfließt und was nicht.

Generell denke ich, dass ein CSS-Reset eine Meinungsfrage ist. Zum Beispiel entscheidet Eric Meyers CSS Reset, die Stile bestimmter Dinge zu entfernen, und andere Dinge wie die display-Eigenschaft bleiben unberührt, womit ich, wie Sie bereits gesehen haben, vollkommen einverstanden bin.

Was box-sizing angeht, ja, das ist meinungsfreudig. Ich bin seit 15 Jahren Webentwickler. In dieser Zeit habe ich viele Webentwickler darum kämpfen sehen, das Standardverhalten von box-sizing zu verstehen, an das ich mich früher so gewöhnt hatte. Als vor vielen Jahren über die Hinzufügung zum CSS-Reset gesprochen wurde, fürchteten sich Webentwickler, von denen viele schon lange in der Branche tätig waren, vor dieser Änderung, da die Leute im Allgemeinen Angst vor Veränderungen haben.

Aber heutzutage sehe ich fast kein Projekt mehr, das nicht alle Elemente auf box-sizing: border-box zurücksetzt. Browser-Engines können das standardmäßig unbeholfene Verhalten von box-sizing: content-box nicht beheben, denn wenn sie es tun, brechen sie die Unterstützung für ältere Websites. Aber für neuere Projekte ist die Einbeziehung dieses Elements ein Muss, da wir es selbst lösen müssen.

Und wieder, das ist rein meinungsfreudig.

Zwei weitere Regelsätze, das Entfernen von Listenstilen und das Zusammenfallen von Rändern, sind ebenfalls im Eric Meyer's Reset enthalten, also sind sie schon lange dabei! Beginnend mit den Listenstilen, kann ich verstehen, dass man diese auswischen möchte, da Listen oft für Dinge verwendet werden, die keinen Marker benötigen, wie z. B. Navigation. Aber es fühlt sich heutzutage etwas umstritten an, da list-style: none; die Semantik einer Liste auslöscht, auch auf iOS. Irgendwelche Bedenken diesbezüglich?

Kurze Antwort: nein. Keine Bedenken meinerseits. Hier ist warum.

Wenn wir uns entscheiden, list-style nicht zurückzusetzen, bedeutet das, dass wir keine Listenelemente für die Navigation verwenden können. Das bedeutet auch, dass wir für keine anderen Browser Semantik erhalten.

Und jetzt, wenn ich wählen muss, ob die meisten Browser diese Semantik erhalten und keine Browser diese Semantik erhalten, wähle ich das Erstere, da mehr Browser davon profitieren als verlieren.

Können Sie sich vorstellen, im Laufe der Zeit etwas hinzuzufügen? Wie wenn Sie feststellen, dass Sie auf Projekten immer wieder dasselbe tun? Das Setzen der max-width auf Bilder fühlt sich für mich so an. Auch hier gibt es keine Browser-Meinungsverschiedenheiten, aber es ist auch etwas, das praktisch jedes Projekt tut.

Natürlich. Wenn diesem Reset etwas fehlt, das ich nicht berücksichtigt habe, werde ich es hinzufügen und eine neue Version veröffentlichen. Aber es muss so sein wie in Ihrem Beispiel mit max-width, wo es keinen guten Fall gibt, in dem wir wollen, dass ein Bild seinen Container überläuft.

Haben Sie dieses neue Cascade Layers Zeug gesehen? Irgendwelche Gedanken, wie das zukünftig in CSS-Resets einfließen könnte?

Ich habe nicht darüber nachgedacht, bis Sie mich gefragt haben. Das Cascade Layers Modul ist ein spannendes Feature. Es gibt noch keine Unterstützung, aber die meisten Browser-Engines haben diese Funktion bereits unter einem Flag gesetzt, und das bedeutet, dass die Chance groß ist, dass wir diese Funktion in einem Jahr in allen Evergreen-Browsern unterstützt sehen werden.

Für diejenigen, die noch nie von Cascade Layers gehört haben: Die Idee ist, dass @layer Stile überschreiben kann, ohne eine stärkere Spezifität zu erzeugen, da jede Schicht, die danach geladen wird, automatisch stärker ist als die vorherigen Schichten.

Wenn dieses Feature eintrifft, werden wir zuerst die "Reset"-Schichten laden. Zum Beispiel: zuerst Normalize.css, dann the-new-css-reset und dann die @layer-Stile des Projekts.

@layer normalize; /* Create 1st layer named “normalize” */
@layer the-new-css-reset; /* Create 2nd layer named “the-new-css-reset” */
@layer project-styles; /* Create 3rd layer named “project-styles” */

Dies sollte sicherstellen, dass die unterste Schicht immer die oberste schlägt. Das bedeutet auch, dass das Entfernen der Spezifität mit :where(), wie ich es getan habe, nicht mehr notwendig sein wird.

@layer ist eines der aufregendsten zukünftigen Features für CSS, dank Miriam Suzanne, die wie immer fantastische Arbeit leistet.

Danke für deine Zeit, Elad!