color-mix() – Hover- und Dark-Mode-Farben ausrechnen lassen, statt sie zu pflegen
Für jede Markenfarbe eine hellere, eine dunklere und eine transparente Variante von Hand zu pflegen, ist Fleißarbeit mit Fehlerquote. color-mix() mischt sie im Browser – aus genau einer Quellfarbe.
Ein typisches Theme hat nicht eine Markenfarbe, sondern acht Abstufungen davon: Hover etwas dunkler, aktiver Zustand noch dunkler, Hintergrund sehr blass, Rand halbtransparent. Wer die alle als Hex-Werte pflegt, pflegt sie beim nächsten Rebranding auch alle wieder – und übersieht zwei.
color-mix() nimmt zwei Farben und einen Anteil und rechnet das Ergebnis im Browser aus.
Die Grundform
:root {
--marke: #2f6fed;
}
.btn {
background: var(--marke);
}
.btn:hover {
/* 85 % Marke, 15 % Schwarz = dezent abgedunkelt */
background: color-mix(in srgb, var(--marke) 85%, black);
}
.btn:active {
background: color-mix(in srgb, var(--marke) 72%, black);
}Der erste Wert ist der Farbraum, in dem gemischt wird (in srgb ist der sichere Standard), danach kommen die beiden Farben mit ihren Anteilen. Fehlt beim zweiten Anteil die Angabe, ergänzt der Browser den Rest auf 100 %.
Transparenz ohne zweiten Farbwert
.karte {
border: 1px solid color-mix(in srgb, var(--marke) 25%, transparent);
background: color-mix(in srgb, var(--marke) 8%, white);
}Das ist der praktischste Fall: transparent mitmischen ersetzt das ständige Umrechnen von Hex nach rgba(). Und weil die Quelle eine Variable ist, zieht jede Änderung durch das ganze Design.
Ein Theme, das sich selbst umdreht
.hinweis {
--grund: var(--marke);
background: color-mix(in srgb, var(--grund) 10%, white);
color: color-mix(in srgb, var(--grund) 75%, black);
}
@media (prefers-color-scheme: dark) {
.hinweis {
background: color-mix(in srgb, var(--grund) 22%, black);
color: color-mix(in srgb, var(--grund) 30%, white);
}
}Hell wird zu Weiß gemischt, dunkel zu Schwarz – dieselbe Quellfarbe, zwei Stimmungen, kein zweites Farbset.
Fallstrick
Zwei Punkte. Erstens: Mische in srgb, solange du klassische Hex-Farben benutzt. in oklab oder in oklch liefern wahrnehmungsgerechtere Verläufe, ergeben aber leicht andere Töne – gut für Farbpaletten, überraschend, wenn du nur schnell abdunkeln willst. Zweitens: color-mix() rechnet keine Kontraste aus. Ein automatisch erzeugter Hover-Ton kann unter den 4,5:1 der WCAG landen; prüf die Kombinationen, die Text tragen, einmal nach.
Design-Systeme, die man in einem Jahr noch pflegen kann, baue ich gern. Melde dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
:is() und :where() – kürzere Selektoren, und einer davon wiegt nichts
Drei fast gleiche Selektoren untereinander, nur weil die Überschrift mal h2 und mal h3 heißt? :is() fasst das zusammen. Und :where() macht dasselbe, ohne die Spezifität hochzutreiben – der Unterschied ist der ganze Trick.
content-visibility – lange Seiten rendern, ohne dass der Browser alles auf einmal baut
Bei sehr langen Seiten rechnet der Browser Layout und Malen für jeden Abschnitt – auch für die, die 8.000 Pixel weiter unten liegen. Eine CSS-Eigenschaft verschiebt diese Arbeit auf den Moment, in dem sie gebraucht wird.
Ankerlinks unter einem klebenden Header – scroll-margin-top rettet die Überschrift
Du klickst im Inhaltsverzeichnis auf einen Abschnitt – und der klebende Header verdeckt genau die Überschrift, zu der du wolltest. Zwei CSS-Zeilen lösen das, ganz ohne JavaScript und ohne unsichtbare Platzhalter-Elemente.