Strategien zur Beibehaltung einer niedrigen CSS-Spezifität

Avatar of Chris Coyier
Chris Coyier on

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

Eine niedrige CSS-Spezifität über alle Selektoren Ihres Projekts hinweg zu halten, ist ein lohnenswertes Ziel. Es ist im Allgemeinen ein Zeichen dafür, dass die Dinge in relativer Harmonie sind. Sie kämpfen nicht gegen sich selbst und haben viel Spielraum, um Stile zu überschreiben, wenn Sie dies benötigen. Die Spezifität von Selektoren neigt dazu, mit der Zeit anzusteigen, und dem ist eine harte Grenze gesetzt. Ich bin sicher, wir alle haben den Schmerz von !important-Tags und Inline-Stilen erlebt.

Wie halten wir also diese Spezifität mit der Zeit niedrig?

Geben Sie sich die benötigte Klasse

Vielleicht schreiben Sie einen Selektor mit hoher Spezifität, weil Sie einen bereits vorhandenen Selektor überschreiben. Vielleicht ist das Element, das Sie auswählen möchten, auf mehreren Seiten enthalten, also wählen Sie es aus einer höheren Klasse aus.

.section-header {
  /* normal styles */
}

body.about-page .section-header {
  /* override with higher specificity */
}

Unabhängig davon, wie Sie dazu stehen, erkennen Sie, dass die Spezifität hier ansteigt. Um dies zu verhindern, gibt es eine Möglichkeit, den Klassennamen des Elements, das Sie direkt gestalten möchten, zu ändern? Manchmal kann die Erstellung serverseitiger Hilfsfunktionen oder Variablen zum Ausgeben von Klassen hilfreich sein, um Logik in Views zu vermeiden.

<header class="<%= header_class %>">
  Which could output one class, or both, as desired.
</header>
.section-header {
  /* normal styles */
}

.about-section-header {
  /* override with same specificity */
  /* possibly extend the standard class */
}

Berücksichtigen Sie die Quellreihenfolge der Stylesheets

In der gleichen Art und Weise, wie Sie etwas überschreiben wollen, wenden Sie vielleicht einen zusätzlichen Klassennamen an, um eine Stilüberschreibung für Sie zu handhaben.

<header class="section-header section-header-about">
  
</header>

Aber wo Sie Ihre Überschreibungsstile mit .section-header-about schreiben, werden diese tatsächlich von der bestehenden Klasse überschrieben. Das kann wegen der Selektorreihenfolge im Stylesheet passieren. Beide Selektoren haben exakt die gleiche Spezifität, sodass die Regeln von dem, was zuletzt deklariert wird, gewinnen.

Dies zu beheben bedeutet einfach sicherzustellen, dass dort, wo immer Sie Ihre Überschreibungsklasse schreiben, diese später kommt. Vielleicht organisieren Sie Ihre Stylesheets wie folgt:

@import "third-party-and-libs-and-stuff";

@import "global-stuff";

@import "section-stuff";

@import "specific-things-and-potential-overrides";

Reduzieren Sie die Spezifität des Dings, das Sie überschreiben

Sie wissen, was man sagt, hinterlasse Dinge besser, als du sie vorgefunden hast. Das solltest du tun.

Wenn ein ID auf einem Element vorhanden ist und dieses damit gestylt wird, können Sie es entfernen? Suchen Sie auf jeden Fall im gesamten Projekt nach #diesem, bevor Sie es tun. Es könnte als JS-Hook verwendet werden (was vollkommen in Ordnung ist), in diesem Fall sollten Sie es in Ruhe lassen und entweder eine Klasse hinzufügen oder eine bereits vorhandene Klasse für das CSS verwenden.

Vermeiden Sie von vornherein keine Klassen

Ich habe schon Selektoren verwendet wie

.module > h2 {

}

Das funktioniert gut, bis zu dem Tag, an dem Sie einen speziellen Stil für dieses h2-Element wünschen. Sie gehen vielleicht in Ihr Markup und denken:

<div class="module">
  <h2 class="unique">
    Special Header
  </h2>
</div>

Aber leider

.module > h2 {
  /* normal styles */
}
.unique {
  /* I'm going to lose this specificity battle */
}
.module .unique {
  /* This will work, but specificity creep! */
}

Die Spezifität nimmt zu, weil der ursprüngliche Selektor uns zubeißt. Deshalb empfehlen fast alle CSS-Methoden flache Strukturen im Sinne von

<div class="module">
  <h2 class="module-header">
  </h2>
  <div class="module-content">
  </div>
</div>

Es kann sich anfangs wie mühsame Arbeit anfühlen, da Sie die Klassen vielleicht nicht sofort benötigen. Aber indem Sie diese Arbeit nicht vermeiden (seien Sie nicht faul!), können die Hooks, die Sie später haben, Ihnen Kummer ersparen.

Nutzen Sie den Kaskadenstil

Wenn ein Projekt älter wird, wird es immer gefährlicher, Selektoren mit *niedriger* Spezifität zu ändern, da sie potenziell mehr Dinge beeinflussen und unbeabsichtigte Folgen haben können.

#im #just .gonna[do] .this .to .be #safe {
  /* cries (ಥ_ʖಥ) */
}

Aber mehr Dinge zu beeinflussen, ist die Macht von CSS. Eine solide Basis, von der aus Sie aufbauen, bedeutet hoffentlich, dass weniger Überschreibungen jemals notwendig sind. Strategien dafür können sein...

Verwenden Sie eine Pattern Library und/oder Style Guide und/oder Atomic Design

Eine Pattern Library (etwas wie diese) kann bedeuten, dass Sie haben, was Sie brauchen, wenn Sie es brauchen. Brauchen Sie Tabs? Hier sind Sie, das ist die etablierte Methode dafür. Und es ist wahrscheinlich so aufgebaut, dass die Spezifität bereits gering ist, sodass die Überschreibung nicht übermäßig schwierig sein wird.

Atomic Design (Buch: hier) kann die Art und Weise leiten, wie Ihre Website (oder die Pattern Library) aufgebaut ist, so dass Sie auch dann, wenn Sie keine vollständige Vorlage für das haben, was Sie brauchen, die Bausteine darunter haben.

Ein Style Guide könnte Sie retten, da er möglicherweise spezifische Regeln bezüglich der Spezifität erzwingt, um Sie vor sich selbst zu bewahren.

Berücksichtigen Sie Opt-in-Typografie

Gleichzeitig, während Sie versuchen, den Kaskadenstil zu nutzen und für viele Elemente intelligente Standardwerte zu haben, möchten Sie vielleicht einige dieser intelligenten Standardwerte manchmal einschränken. Zum Beispiel wird ein Listenelement oft für Navigation und innerhalb von Inhalten verwendet. Die Stile dafür werden drastisch unterschiedlich sein. Warum also nicht mit einer sauberen Weste beginnen und Textstile nur bei Bedarf anwenden.

/* reset styles globally */
ul, ol, li {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* scope text styles to text content */
.text-content {
  h1, h2, h3 {
  }
  p {
  }
  ul {
  }
  ol {
  }
  /* etc */
}

Das erhöht zwar die Spezifität dieser Textselektoren, bedeutet aber, dass Regeln, die speziell für Text sind, nicht mehr beeinflussen als nötig und weniger Überschreibungen erforderlich sind.

Probleme außerhalb Ihrer Kontrolle

Vielleicht erwartet oder injiziert ein Drittanbieter-Code bestimmte HTML-Elemente auf Ihrer Seite. Damit müssen Sie arbeiten. Sie können immer noch versuchen, so wenige Spezifität wie möglich zu verwenden. Sie können Kommentare im Code hinterlassen, die erklären, warum die Selektoren so sind. Sie können Selektoren mit geringer Spezifität verwenden, aber !important-Überschreibungen verwenden. Sie können die Verantwortlichen für den nicht optimalen Code bitten, ihn zu korrigieren.

Erhöhen Sie die Spezifität nur leicht und vermerken Sie sie

Wenn Sie in einen Spezifitätskampf geraten müssen, anstatt zu einer Sledgehammer-Methode wie ID oder !important zu greifen, versuchen Sie etwas Leichteres.

Ein Tag-Qualifizierer ist die geringstmögliche Spezifitätssteigerung.

ul.override {
  /* I win */  
}
.normal {
}

Aber die Beschränkung eines Selektors auf ein bestimmtes Tag ist eine seltsame Einschränkung. Es könnte klug sein, stattdessen einfach eine zusätzliche Klasse hinzuzufügen. Wenn ein anderer Name keinen Sinn ergibt, können Sie sogar dieselbe Klasse verwenden, wenn nötig.

.nav.override {
}
.override.override {
}
.nav {
}

Nur weil Verschachtelung nett ist, heißt das nicht, dass die Spezifität steigen muss

Verschachtelung in Präprozessoren wird manchmal entmutigt, weil sie es so einfach macht, übermäßig komplizierte Selektoren zu schreiben. Aber Verschachtelung ist manchmal einfach visuell nett im Stylesheet, weil sie Dinge gruppiert und sie leichter zu lesen und zu verdauen macht.

Bohdan Kokotko erinnerte mich kürzlich daran, dass das kaufmännische Und in Sass verwendet werden kann, um im Wesentlichen Namespacing statt zusammengesetzter Selektoren zu betreiben.

.what {
    color: red;
   &-so {
      color: green;
      &-ever {
        color: blue;
      }
   }
}
.what {
  color: red;
}
.what-so {
  color: green;
}
.what-so-ever {
  color: blue;
}

Der Single-Class-Wrapper

Eine ziemlich drastische Methode, um eine Überschreibung zu handhaben, ist die Verwendung eines bestehenden Wrapper-Elements über dem Bereich, den Sie mit Stilüberschreibungen versehen müssen, oder die Hinzufügung eines neuen.

<div class="override">

   ... existing stuff ...

</div>

Sie haben nun die Möglichkeit, jeden bestehenden Stil dort zu überschreiben, indem Sie nur eine einzige Klasse zum Selektor hinzufügen. Das ist Spezifitätsanstieg, aber ein Versuch, ihn niedrig zu halten.

.override .existing {
}

Nur einmal

Wenn Sie jemals eine Überschreibung überschreiben, ist das ein guter Punkt, um innezuhalten und nachzudenken.

Können Sie sich selbst nur eine einzige Klasse geben, die Sie stattdessen verwenden können? Eine einzelne Überschreibung kann tatsächlich effizient sein, wie eine Variation eines Musters, anstatt ein neues Muster zu erstellen. Eine Überschreibung einer Überschreibung ist ein Rezept für Verwirrung und weiteren Kampf.

Machen Sie es beim nächsten Mal einfach besser

Wenn Sie von Spezifitätsproblemen geplagt wurden, auch wenn deren Behebung derzeit unpraktisch ist, wissen Sie zumindest jetzt, dass es problematisch ist und Sie die Dinge beim nächsten Mal anders angehen können.