Wechseln Sie die Schriftfarbe für verschiedene Hintergründe mit CSS

0
36

Jemals einer von denen, “ich kann das mit CSS!” – Momente, während gerade jemand flex Ihre JavaScript-Muskeln? Das ist genau das Gefühl, das ich beim anschauen Dag-Inge Aas & Ida Aalen Vortrag auf CSSconf EU 2018.

Sie basiert in Norwegen, wo die WCAG Barrierefreiheit ist nicht nur eine gute übung, aber eigentlich gesetzlich vorgeschrieben ist (gehen, Norwegen!). Wie wurden Sie entwickelt eine Funktion, mit der Benutzer-auswählbaren Farb-themes für Ihre wichtigsten Produkte, Sie Stand vor einer Herausforderung: die automatische Anpassung der schriftart, die Farbe, die basierend auf der gewählten Hintergrundfarbe des Containers. Wenn der hintergrund dunkel ist, dann wäre es ideal, einen weißen text zu halten, WCAG Kontrast-konform. Aber was passiert, wenn eine helle Hintergrundfarbe ausgewählt ist, statt? Der text ist sowohl unleserlich ausfällt und Zugänglichkeit.

Sie verwendet einen eleganten Ansatz und das Problem gelöst, mit der “Farbe” npm-Paket, das hinzufügen von bedingten Grenzen und automatische sekundäre Farbe Stromerzeugung, während Sie schon dabei waren.

Das ist aber eine JavaScript-Lösung. Hier ist meine Reine CSS-alternative.

Die Herausforderung

Hier ist die Kriterien, die ich zu bewerkstelligen:

  • Ändern Sie die Schriftfarbe entweder schwarz oder weiß je nach Hintergrundfarbe
  • Wenden Sie die gleiche Art von Logik zu Grenzen, über eine dunklere Variante der Grundfarbe des Hintergrunds zu verbessern Schaltfläche Sichtbarkeit, nur wenn hintergrund ist eigentlich Licht
  • Generieren Sie automatisch eine sekundäre, 60º Farbton-Farbe gedreht

Die Arbeit mit HSL-Farben und CSS-Variablen

Der einfachste Ansatz, den ich denken konnte, für diese ausführen impliziert HSL-Farben. Einstellen der hintergrund-Deklarationen, wie HSL, wo jedem parameter ist eine benutzerdefinierte CSS-Eigenschaft ermöglicht einen wirklich einfachen Weg, um zu bestimmen, Leichtigkeit und verwenden Sie es als Ausgangspunkt für unsere bedingte Anweisungen.

:root {
–Farbton: 220;
– sa: 100;
–Licht: 81;
}

.btn {
hintergrund: hsl(var(–Farbton), calc(var (- sa) * 1%), calc(var(–Licht) * 1%));
}

Dies sollte es uns ermöglichen, tauschen Sie den hintergrund zu jeder Farbe, die wir gerne zur Laufzeit, indem Sie die Variablen und die Ausführung eines if/else-Anweisung zum ändern der Vordergrundfarbe.

Außer… wir haben keine if/else-Anweisungen auf CSS… oder doch nicht?

Einführung in CSS-bedingte Anweisungen

Seit der Einführung von CSS-Variablen, wir haben auch bedingte Anweisungen mit Ihnen zu gehen. Oder irgendwie so.

Dieser trick basiert auf der Tatsache, dass einige CSS-Parameter bekommen, begrenzt auf min-und max-Wert. Zum Beispiel, denken Sie die Deckkraft. Der gültige Bereich ist 0 bis 1, so dass wir normalerweise dort zu halten. Aber wir können auch erklären, eine Opazität von 2, 3, oder 1000, und es werden verschlossen werden, um 1 und als solche interpretiert. In ähnlicher Weise können wir sogar erklären einen negativen Wert für die Deckkraft ein, und bekommen Sie es begrenzt auf 0.

.etwas {
Deckkraft: -2; /* wird zu 0, transparent */
Deckkraft: -1; /* wird zu 0, transparent */
Deckkraft: 2; /*wird zu 1, voll deckend */
opacity: 100; /* wird zu 1, voll deckend */
}

Anwendung der trick, um unsere Schriftfarbe Deklaration

Die Leichtigkeit parameter eines HSL-Farbe-Deklaration verhält sich in ähnlicher Weise, capping ein negativer Wert auf null (0 Ergebnisse in black, was auch immer der Farbton und die Sättigung passiert zu sein) und alles über 100% ist begrenzt auf 100% (die ist immer weiß).

So können wir erklären der Farbe HSL, subtrahieren Sie die gewünschte Schwelle von der Leichtigkeit-parameter, dann multiplizieren Sie mit 100% zu zwingen, es zu überschreitung einer der Grenzen (entweder sub-zero oder höher als 100%). Da brauchen wir negative Ergebnisse zu beheben, in weiß und positive Ergebnisse zu beheben, in schwarz, müssen auch wir umkehren, es multipliziert das Ergebnis mit -1.

:root {
–Licht: 80;
/* die Schwelle, bei der die Farben als “Licht”. Wertebereich: Ganzzahlen von 0 bis 100,
empfohlen 50 – 70 */
–Schwellenwert: 60;
}

.btn {
/* Jeder Helligkeitswert unter die Schwelle, wird das Ergebnis in weiß, ein oben wird schwarz */
–Schalter: calc((var(–Licht) – var(–Schwellenwert)) * -100%);
color: hsl(0, 0%, var(–switch));
}

Lasst uns das bisschen code: ab einer Helligkeit von 80 und unter Berücksichtigung einer 60-Schwellenwert, wird der Subtraktion-Ergebnisse in 20, multipliziert mit -100%, Ergebnisse im -2000%, gedeckelt auf 0%. Ist der hintergrund heller ist als der Schwellenwert, so halten wir es für Licht und gelten schwarzem text.

Wenn wir uns gesetzt hatten, die-von Licht-Variablen als 20, wird der Abzug geführt hätte -40, welche multipliziert mit -100% drehen würde, 4000%, gedeckelt auf 100%. Unsere Licht-variable niedriger ist als der Schwellenwert, daher betrachten wir es als einen “dunklen” hintergrund und gelten weiße text zu halten, einen hohen Kontrast.

Die Erzeugung eines bedingten Grenze

Wenn der hintergrund eines Elements wird zu Licht, es kann leicht verloren gegen einen weißen hintergrund. Wir haben eine Taste und es gar nicht bemerkt. Um eine bessere Oberfläche auf wirklich hellen Farben, können wir eine Grenze gesetzt, basierend auf der selben hintergrund Farbe, nur dunkler.

Ein heller hintergrund und eine dunkle Grenze basiert auf die hintergrund-Farbe.

Um dies zu erreichen, können wir das gleiche Verfahren verwenden, aber es anwenden, um den Alphakanal des HSLA-Erklärung. Auf diese Weise können wir die Farbe anpassen, wie gebraucht, dann haben Sie entweder voll transparent oder voll deckend.

:root {
/* (…) */
–Licht: 85;
–Grenze-Schwelle: 80;
}

.btn {
/* setzt die border-color als 30% dunkleren Farbton der gleichen Farbe*/
–Grenze-Licht: calc(var(–Licht) * 0.7%);
–Grenze-alpha: calc((var(–Licht) – var(–border-Schwellenwert)) * 10);

Grenze: .1em solid hsla(var(–Farbton), calc(var (- sa) * 1%), var(–border-Licht), var(–Grenze-alpha));
}

Vorausgesetzt, Farbton 0 und Sättigung bei 100%, der obige code wird eine vollständig undurchsichtige, reines rot Grenze auf 70% der ursprünglichen Helligkeit, wenn der hintergrund-Helligkeit ist höher als 80, oder ein vollständig transparentes Grenze (und somit auch keine Grenze überhaupt), wenn es dunkler ist.

Einstellung der sekundären, 60º Farbton-Farbe gedreht

Wohl die einfachste der Herausforderungen. Es gibt zwei mögliche Ansätze:

  1. filter: hue-rotate(60): Dies ist die erste in den Sinn kommt, aber es ist nicht die beste Lösung, als wäre es auf die Farbe der untergeordneten Elemente. Wenn nötig, rückgängig gemacht werden können, mit einer entgegengesetzten rotation.
  2. HSL-Farbton + 60: Die andere option ist, um unsere Farbton-variable hinzufügen und 60. Da die Farbton-parameter nicht haben, dass capping Verhalten bei der 360 sondern wickelt sich um (wie jedes CSS <Winkel> geben tut), sollte es ohne Probleme funktionieren. Denke 400deg=40deg, 480deg=120deg, etc.

In Anbetracht dieser, können wir fügen Sie ein Modifikator Klasse für unseren Sekundär-farbigen Elementen fügt hinzu, dass 60 der hue-Wert. Da selbst-ändern von Variablen stehen nicht in CSS (d.h. es gibt keine solche Sache wie –Farbton: calc(var(–Farbton) + 60) ), können wir hinzufügen eines neuen Hilfs-variable für unsere Farbton manipulation zu unserer Basis-Stil und verwenden Sie es in den hintergrund und die Grenze der Erklärung.

.btn {
/* (…) */
–h: var(–Farbton);
hintergrund: hsl(var(–h), calc(var (- sa) * 1%), calc(var(–Licht) * 1%));
Grenze:.1em solid hsla(var(–h), calc(var (- sa) * 1%), var(–border-Licht), var(–Grenze-alpha));
}

Dann wieder erklären, dessen Wert in unserem modifier:

.btn–sekundäre {
–h: calc(var(–Farbton) + 60);
}

Beste an diesem Ansatz ist, dass es automatisch anpassen alle unsere Berechnungen auf den neuen Farbton und wenden Sie Sie auf die Eigenschaften, wegen CSS custom properties (scoping).

Und da sind wir. Setzen Sie alle zusammen, hier ist meine Reine CSS-Lösung, um alle drei Herausforderungen. Dieser funktioniert wie ein Charme und rette uns aus, darunter eine externe JavaScript-Bibliothek.

Finden Sie den Stift CSS-Automatik-Schalter Schriftfarbe je nach element hintergrund…. SCHEITERN von Facundo Corradini (@facundocorradini) auf CodePen.

Außer es funktioniert nicht. Einige Farben kommen wirklich problematisch (besonders gelb und Cyan), wie Sie angezeigt werden Weg heller als andere (z.B. rot-und Blautöne) trotz des gleichen Helligkeitswert. In der Folge werden einige Farben werden behandelt, wie dunkle und weiße text trotz extrem hell.

Was im Namen von CSS ist Los?

Einführung empfundene Helligkeit

Ich bin sicher, viele von Euch vielleicht bemerkt haben, ist es Weg, aber für den rest von uns, stellt sich heraus, die Helligkeit, die wir wahrnehmen, ist nicht die gleiche wie die HSL-lightness. Zum Glück haben wir einige Methoden Wiegen im Farbton Leichtigkeit und passen unser code so reagiert Sie auf den Farbton als auch.

Um das zu tun, müssen wir berücksichtigen, die empfundene Helligkeit der drei Grundfarben, von denen jede einen Koeffizienten entsprechend, wie hell oder dunkel das menschliche Auge Sie wahrnimmt. Dies ist üblicherweise als luma.

Es gibt mehrere Methoden, dies zu erreichen. Einige sind besser als andere, in bestimmten Fällen, aber nicht einer ist zu 100% perfekt. So wählte ich die beiden beliebtesten, die sind gut genug:

  • sRGB-Luma (ITU Rec. 709): L = (rote * 0.2126 + grün * 0.7152 + blau * 0.0722) / 255
  • W3C-Methode (working draft): L = (red * 0.299 + green * 0.587 + blue * 0.114) / 255

Die Umsetzung luma-Korrektur der Berechnungen

Die erste offensichtliche Folgerung aus Los mit einem luma-Korrektur-Ansatz ist, dass wir nicht verwenden können, HSL, da CSS nicht über native Methoden zum Zugriff auf die RGB-Werte HSL-Erklärung.

So, wir wechseln müssen, um ein RBG Erklärung für die Hintergründe, berechnen Sie die luma-von was auch immer Methode, die wir wählen, und verwenden Sie es auf unsere Vordergrundfarbe Erklärung, die kann (und wird) noch die HSL.

:root {
/* theme color-Variablen zu verwenden, die im RGB-Deklarationen */
–rot: 200;
–grün: 60;
–blau: 255;
/* die Schwelle, bei der die Farben als “Licht”.
Bereich: Dezimalzahlen von 0 bis 1, empfohlen 0.5 – 0.6 */
–Schwellenwert: 0.5;
/* die Schwelle, bei der ein dunkler Rand angewendet werden.
Bereich: Dezimalzahlen von 0 bis 1, empfohlen 0.8+ */
–Grenze-Schwelle: 0.8;
}

.btn {
/* legt die Hintergrundfarbe für die Basis-Klasse */
hintergrund: rgb(var (- rot), var (- grün), var (- blau));

/* Berechnung der wahrgenommenen Leichtigkeit der Verwendung des sRGB-Luma-Methode
Luma = (rote * 0.2126 + grün * 0.7152 + blau * 0.0722) / 255 */
–r: calc(var (- rot) * 0.2126);
–g: calc(var (- grün) * 0.7152);
–b: calc(var (- blau) * 0.0722);
–Summe: calc(var(–r) + var(–g) + var(–b));
–wahrgenommene Helligkeit: calc(var(–Summe) / 255);

/* zeigt entweder weiß oder schwarz je nach Farbe wahrgenommen Dunkelheit */
color: hsl(0, 0%, calc((var(–wahrgenommene Helligkeit) – var(–Schwellenwert)) * -10000000%));
}

Für die bedingte Grenzen, die wir brauchen, um die Erklärung in ein RGBA, und noch einmal, verwenden Sie den alpha-Kanal zu machen, entweder voll transparent oder voll deckend. So ziemlich das gleiche wie vorher, nur läuft RGBA statt HSLA. Die dunkleren Farbton erhält man durch die Halbierung der einzelnen Farbkanäle.

.btn {
/* (…) */
/* es gilt ein dunkler Rand, wenn die Helligkeit ist höher als die Grenze Schwellwert */
–Grenze-alpha: calc((var(–wahrgenommene Helligkeit) – var(–border-Schwellenwert)) * 100);
Grenze: .2em solid rgba(calc(var (- rot) * 0.5), calc(var (- grün) * 0.5), calc(var (- blau) * 0.5) var(–Grenze-alpha));
}

Da verloren wir unsere anfängliche HSL-hintergrund-Erklärung, unsere seitenthema Farbe sein muss, die über den Farbton-rotation:

.btn–sekundäre {
filter: hue-rotate(60deg);
}

Dies ist nicht die beste Sache der Welt. Neben der Anwendung des Farbtons auf mögliche Kind-Elemente wie bereits diskutiert, bedeutet es, dass der Schalter für schwarz/weiß und Grenze der Sichtbarkeit auf dem sekundären element wird davon abhängen, das wichtigste element ist Farbe, und nicht auf seine eigene. Aber soweit ich sehen kann, ist die JavaScript-Implementierung hat das gleiche Problem, also nenne ich es in der Nähe genug.

Und da haben wir es, diese Zeit für gut.

Finden Sie den Stift CSS Automatische WCAG Kontrast Schriftfarbe-je nach element-hintergrund von Facundo Corradini (@facundocorradini) auf CodePen.

Eine Reine CSS-Lösung, die den gleichen Effekt erzielt wie das original-JavaScript-Ansatz, aber eine deutliche Reduzierung der auf den footprint.

Browser-Unterstützung

IE ist ausgeschlossen, da die Verwendung von CSS-Variablen. Rand nicht haben, dass capping Verhalten, das wir ganz verwendet werden. So sieht es die Erklärung, hält es für Unsinn, und verwirft Sie ganz, als würde es alle fehlerhaften/unbekannten die Regel. Alle anderen großen browser funktionieren sollte.