
Mein Name ist Vladimir und ich entwickle ein mobiles Frontend für Yandex Mail. Unsere Apps hatten eine Weile ein dunkles Thema, aber es war unvollständig: Nur die Benutzeroberfläche und einfache E-Mails waren dunkel. Nachrichten mit benutzerdefinierter Formatierung blieben hell und hoben sich von der dunklen Oberfläche ab, wodurch die Augen unserer Benutzer nachts verletzt wurden.
Heute werde ich Ihnen sagen, wie wir dieses Problem behoben haben. Sie lernen zwei einfache Techniken kennen, die bei uns nicht funktioniert haben, und die Methode, die schließlich den Trick ausgeführt hat - das adaptive Umfärben von Seiten. Ich werde auch einige Ideen zum Anpassen von Bildern an ein dunkles Thema teilen. Um fair zu sein, ist das Abdunkeln von Seiten mit benutzerdefiniertem CSS eine ziemlich eigenartige Aufgabe, aber ich glaube, einige von Ihnen finden unsere Erfahrung hilfreich.
Einfache Methoden
Bevor wir uns für unsere magische Farbbiegetechnik entschieden haben, haben wir zwei wirklich grundlegende Optionen ausprobiert: entweder zusätzliches dunkles Styling oder einen CSS-Filter auf Elemente anwenden. Keine der beiden Optionen hat bei uns funktioniert, aber in anderen Fällen sind sie möglicherweise besser geeignet (einfach ist cool, oder?).
Stile überschreiben
Dies ist eine kinderleichte Option, die das dunkle CSS-Thema der App logisch erweitert. Sie fügen einfach zusätzliche dunkle Stile in einen E-Mail-Container ein (oder im Allgemeinen in einen Container, damit der vom Benutzer generierte Inhalt dunkler wird):
.message--dark { background-color: black; color: white; }
Alle Stile für die Elemente in der E-Mail überschreiben jedoch unseren Stammstil. Und nein !important
hilft hier nicht. Die Idee kann noch einen Schritt weiter gehen, indem Vererbung verhindert wird:
.message--dark * { background-color: black !important; color: white !important; border-color: #333 !important; }
In diesem Fall können Sie nicht darauf verzichten !important
, da der Selektor selbst nicht sehr spezifisch ist. Dies überschreibt auch die meisten Inline-Stile (diejenigen mit Inline !important
wird immer noch Eingang finden, und Sie können nicht viel dagegen tun).
Unser Stil malt eifrig alles in der gleichen Farbe und bringt so ein weiteres Problem mit sich. Es besteht die Möglichkeit, dass der Designer etwas über die Art und Weise sagen wollte, wie sie die Farben angeordnet haben (Sie wissen, Prioritäten, Paarungen, all das Designermaterial), und wir haben einfach ihre Idee aufgegriffen und sie aus dem Fenster geworfen. Keine schöne Sache.

Wenn Sie Designer nicht so sehr respektieren wie ich und sich für diese Methode entscheiden, vergessen Sie nicht, die nicht so offensichtlichen Dinge zu behandeln:
box-shadow
. Sie können jedoch nicht nur die Farbe überschreiben. Entweder die Schatten ganz loswerden oder mit den hellen Frieden schließen.- Die Farben semantischer Elemente wie Links oder Eingaben.
- Inline-SVG. Verwenden Sie
fill
anstelle von background
und stroke
anstelle von color
, aber Sie können nie sicher sein, dass es auch umgekehrt sein kann.
Aus technischer Sicht ist dies eine solide Methode: Es werden drei Codezeilen benötigt (OK, dreißig für eine produktionsbereite Version mit allen Randfällen), es ist mit allen Browsern der Welt kompatibel Funktioniert sofort mit dynamischen Seiten, und die Art und Weise, wie CSS an das Dokument angehängt wird, ist völlig irrelevant. Es gibt auch einen schönen Bonus: Sie können die Farben im Stil leicht an die Hauptfarben der Anwendung #bbbbb8
(z. B. den Hintergrund #bbbbb8
anstelle von Schwarz).
Übrigens haben wir früher so E-Mails abgedunkelt. Wenn eine E-Mail einen eigenen Stil hätte, würden wir einfach aufgeben und sie für alle Fälle leicht lassen.
Verwenden eines CSS-Filters
Dies ist eine intelligente und elegante Methode. Sie können eine Seite mit einem CSS-Filter abdunkeln:
.message--dark { filter: invert(100) hue-rotate(180deg); }
Die Bilder werden gruselig, aber wir können das leicht beheben:
.message-dark img { filter: invert(100) hue-rotate(180deg); }

Dies löst jedoch nicht das Problem von Inhaltsbildern, die über die Hintergrundeigenschaft angehängt werden (sicher, es ist praktisch, um das Seitenverhältnis anzupassen, aber was ist mit der Semantik?). OK, nehmen wir an, wir können alle diese Elemente finden, explizit markieren und auch ihre Farben zurück ändern.
Das Gute an dieser Methode ist, dass die ursprüngliche Helligkeits- und Kontrastbalance erhalten bleibt. Auf der anderen Seite gibt es viele Probleme, die die Vorteile überwiegen:

- Dunkle Seiten werden hell.
- Sie können die endgültigen Farben nicht steuern. Welchen Filter wenden Sie auf den Hintergrund an, damit er zu Ihrer Marke
#bbbbb8
? Das ist ein echter Kopfkratzer. - Durch die doppelte Inversion werden die Bilder ausgeblendet.
- Die Leistung ist schleppend, insbesondere auf Mobilgeräten. Anstatt die Seite einfach zu rendern, führt der Browser bei jeder Ziehung Fourier-Transformationen aus.
Diese Methode würde für E-Mails mit neutralem Text funktionieren, aber ich habe noch nie jemanden mit einem Posteingang voller solcher Inhalte getroffen. Auf der anderen Seite sind Filter die einzige Möglichkeit, Elemente abzudunkeln, ohne auf deren Inhalt zuzugreifen - Frames, Webkomponenten oder Bilder.
Adaptives dunkles Thema
Und jetzt ist es Zeit für Magie! Basierend auf den Nachteilen der ersten beiden Ansätze haben wir eine Checkliste erstellt, um was wir uns kümmern sollten:
- Machen Sie den Hintergrund dunkel, den Text hell und die Ränder irgendwo dazwischen.
- Erkennen Sie dunkle Seiten und bewahren Sie deren Farben.
- Behalten Sie das ursprüngliche Gleichgewicht zwischen Helligkeit und Kontrast bei.
- Geben Sie die Kontrolle über die resultierenden Farben.
- Lassen Sie die Farbtöne unverändert.
Sie müssen also die Farben der Stile ändern, um den Hintergrund dunkel zu machen. Warum nicht einfach das buchstäblich tun? Nehmen Sie alle Stile, extrahieren Sie die farbbezogenen Regeln ( color
, background
, Rahmen, box-shadow
und ihre Untereigenschaften) und ersetzen Sie sie durch ihre "abgedunkelten" Versionen: Verdunkeln Sie den Hintergrund und die Ränder (aber nicht so stark wie die Hintergrund), heller den Text usw.
Diese Methode hat einen unglaublichen Vorteil, der das Herz eines jeden Entwicklers erwärmt. Sie können Farbkonvertierungsregeln für jede Eigenschaft konfigurieren - ja, mithilfe von Code! Mit ein wenig Fantasie können Sie die Farben an jedes externe Thema anpassen, jede gewünschte Farbkorrektur durchführen (z. B. ein helles Thema anstelle eines dunklen oder ein Thema einer beliebigen Farbe) und sogar ein hinzufügen ein bisschen Kontextualität - behandeln Sie zum Beispiel breite und schmale Grenzen unterschiedlich.
Die Nachteile sind das, was Sie von einem "Alles-in-Js" -Ansatz erwarten würden. Wir führen Skripte aus, bringen die Kapselung durcheinander und analysieren CSS mit Regex. Letzteres ist jedoch nicht so demütigend wie bei HTML, da die CSS-Grammatik regelmäßig ist (zumindest auf der Ebene, mit der wir arbeiten).
Hier ist unser dunkler Plan:
- Normalisieren Sie die
bgcolor
( bgcolor
und andere) und verschieben Sie sie in style="..."
. - Hier finden Sie alle Inline-Stile.
- Finden Sie alle farbbezogenen Regeln in jedem Stil (
background-color
, color
, box-shadow
und andere). - Nehmen Sie die Farben aus den farbbezogenen Eigenschaften und stimmen Sie sie mit dem richtigen Konverter ab (verdunkeln Sie den Hintergrund, erhellen Sie den Text).
- Rufen Sie den Konverter an.
- Fügen Sie die konvertierten Eigenschaften wieder in das CSS ein.
Der Wrapper-Code - Normalisierung, Suchen von Stilen, Parsen - ist ziemlich trivial. Mal sehen, wie genau unser Magic Converter funktioniert.
HSL-Konvertierungen
Das Abdunkeln einer Farbe ist nicht so einfach, wie es sich anhört, insbesondere wenn Sie den Farbton beibehalten möchten (z. B. Blau in Dunkelblau und nicht Orange umwandeln). Sie können dies in normalem RGB tun, aber es ist problematisch. Wenn Sie sich für algorithmisches Design interessieren, wissen Sie, dass in RGB sogar Farbverläufe unterbrochen sind. In der Zwischenzeit ist die Arbeit mit Farben in HSL ein wahrer Genuss: Anstelle von Rot, Grün und Blau, mit denen Sie keine Ahnung haben, was Sie tun sollen, haben Sie die folgenden drei Kanäle:
- Farbton - das, was wir bewahren wollen.
- Sättigung, die uns momentan nicht sehr wichtig ist.
- Leichtigkeit, die wir ändern werden.
Man kann es sich als Zylinder vorstellen. Wir müssen diesen Zylinder auf den Kopf stellen. Die Farbkorrektur macht ungefähr so: (h, s, l) => [h, s, 1-l]
.
Farben, die schon in Ordnung sind
Manchmal haben wir Glück und das benutzerdefinierte Design der E-Mail (oder eines Teils davon) ist bereits dunkel. Dies bedeutet, dass wir nichts ändern müssen - der Designer hat wahrscheinlich die Farben besser ausgewählt, als unser Algorithmus jemals träumen konnte. In HSL müssen Sie nur die L-Leichtigkeit berücksichtigen. Wenn der Wert höher oder niedriger (für den Text bzw. den Hintergrund) als der Schwellenwert (den Sie festlegen können) ist, lassen Sie ihn einfach in Ruhe.
Dynamischer Zirkus
Auch wenn wir nichts davon brauchten (vielen Dank, Desinfektionsmittel, Sie haben meinen Tag hier gerettet), werde ich die zusätzlichen Funktionen auflisten, die ein adaptives Thema benötigt, um ganze Seiten und nicht nur doofe statische E-Mails aus den 90ern abzudunkeln. Faire Warnung: Diese Aufgabe ist nicht jedermanns Sache.
Dynamische Inline-Stile
Das Ändern von Inline-Stilen ist der einfachste Fall, der unsere dunklen Seiten durcheinander bringt. Es ist üblich, aber es gibt eine einfache Lösung: Fügen Sie MutationObserver
und korrigieren Sie Inline-Stile, sobald die Änderungen eintreten.
Externe Stile
Das Arbeiten mit Stilen, auf die ein <link>
-Element innerhalb der Seite @import
kann aufgrund der Asynchronität und der @import
Anweisungen qualvoll sein. Und CORS macht die Dinge nicht besser. Es sieht so aus, als ob dieses Problem mit einem Web-Worker (Proxy für alle *.css
) recht elegant gelöst werden kann.
Dynamische Stile
Um die Sache noch schlimmer zu machen, können Skripte <style>
und <link>
-Elemente nach Belieben hinzufügen, entfernen oder neu anordnen und sogar die Regeln in <style>
ändern. Hier müssen Sie auch MutationObserver
, aber jede Änderung erfordert mehr Verarbeitung.
CSS-Variablen
Wenn CSS-Variablen ins Spiel kommen, wird es richtig wild. Sie können die Variablen nicht abdunkeln: Selbst wenn Sie vermuten, dass eine Variable eine Farbe enthält, die auf ihrem Format basiert (obwohl ich davon abraten würde), wissen Sie immer noch nicht, welche Rolle sie spielt - Hintergrund, Text, Rahmen oder alles sofort? Darüber hinaus werden die Werte von CSS-Variablen vererbt, sodass Sie nicht nur die Stile, sondern auch die Elemente verfolgen müssen, auf die sie angewendet werden. Dies eskaliert schnell außer Kontrolle.
Sobald die CSS-Variablen den Mainstream erreicht haben, sind wir in Schwierigkeiten. Auf der anderen Seite wird color()
bis dahin unterstützt, sodass wir alle unsere JS-Konvertierungen durch eine color(var(--bg) lightness(-50%))
ersetzen können.
Zusammenfassung

In unserem Fall wirkt die adaptive Verdunkelung auf CSS-Ebene wie ein Zauber, wenn der Desinfektionsmittel nur Inline-Stile belässt: Sie bietet eine Verdunkelung von höherer Qualität, stört die ursprüngliche Struktur nicht und ist relativ einfach und schnell. Die Erweiterung auf dynamische Seiten ist jedoch wahrscheinlich nicht die Mühe wert. Wenn Sie mit benutzergenerierten Inhalten arbeiten und keinen Browser entwickeln, funktioniert Ihr Desinfektionsprogramm wahrscheinlich genauso.
In der Praxis sollte der adaptive Modus mit Stilüberschreibungen gepaart werden, da Standardelemente wie <input>
oder <a>
häufig die Standardlichtstile verwenden.
So verdunkeln Sie Bilder
Die Bildverdunkelung ist ein separates Problem, das mich persönlich stört. Es ist eine Herausforderung und gibt mir eine Entschuldigung, endlich den Ausdruck "Spektralanalyse" zu verwenden. Es gibt einige typische Probleme mit Bildern in einem dunklen Thema.
Einige Bilder sind einfach zu hell. Diese bereiten uns die gleichen Probleme wie die hellen E-Mails, mit denen wir unsere Suche begonnen haben. Dieses Problem tritt häufig bei normalen Fotos auf, ist jedoch nicht ausschließlich für diese. Da das Schreiben von Newsletter-CSS nicht viel Spaß macht, überspringen einige Leute gerne Ecken, indem sie ein komplexes Layout als Bild einfügen, wodurch eine Verdunkelung verhindert wird. Wenn ich das sehe, stöhnt mein innerer Perfektionist frustriert. Diese Bilder sollten abgeblendet, aber nicht invertiert sein, es sei denn, Sie möchten Ihre Benutzer erschrecken.

Dann gibt es dunkle Bilder mit echter Transparenz. Dies ist ein typisches Problem bei Logos. Sie sind für einen hellen Hintergrund konzipiert. Wenn wir sie durch einen dunklen Hintergrund ersetzen, verschwindet das Logo darin. Diese Bilder müssen invertiert werden.

Irgendwo dazwischen befinden sich Bilder, die einen weißen Hintergrund verwenden, der Transparenz darstellen soll. Im dunklen Thema landen sie einfach in einem seltsamen weißen Dreieck. In einer perfekten Welt könnten wir den weißen Hintergrund in einen transparenten ändern, aber wenn Sie jemals einen Zauberstab verwendet haben, wissen Sie, wie schwierig es ist, dies automatisch zu tun.

Interessanterweise haben einige Bilder keinerlei Bedeutung. Dies sind normalerweise Tracking-Pixel oder "Formathalter" in besonders bizarren Layouts. Sie können sie sicher unsichtbar machen (z. B. mit einer opacity: 0
).

Analysieren, was drin ist
Um herauszufinden, wie ein Bild für ein dunkles Thema angepasst werden kann, müssen wir nach innen schauen und dessen Inhalt analysieren, vorzugsweise mit einer schnellen und einfachen Methode. Hier ist die erste Version eines Algorithmus, der dies löst.
Zählen Sie zuerst die dunklen, hellen und transparenten Pixel des Bildes. Als offensichtliche Optimierung kann nur eine kleine Teilmenge von Pixeln betrachtet werden. Bestimmen Sie als Nächstes die Gesamthelligkeit des Bildes (hell, dunkel oder mittel) und ob Transparenz vorhanden ist. Invertieren Sie dunkle Bilder mit Transparenz, dimmen Sie undurchsichtige helle Bilder und lassen Sie den Rest unverändert.
Ich habe mich sehr über diese Entdeckung gefreut, bis ich auf einen Charity-Newsletter stieß, der ein Foto einer Lektion an einer afrikanischen Schule enthielt. Der Designer zentrierte es, indem er transparente Pixel an den Seiten hinzufügte. Wir wollten uns nicht auf eine Geschichte über anstößige Bilderkennung einlassen, deshalb haben wir beschlossen, die Bildmanipulation aus unserer ersten Iteration herauszulassen.
In Zukunft können wir solche Probleme verhindern, indem wir diese Heuristik verwenden, die ich "Spektralanalyse" nenne. Das heißt, Sie zählen die Anzahl der verschiedenen Farbtöne im Bild und invertieren nur, wenn nicht zu viele vorhanden sind. Mit derselben Methode können Sie helle, skizzenhafte Bilder erkennen und auch invertieren.

Fazit
Um ein vollwertiges dunkles Thema zu entwerfen, mussten wir einen Weg finden, E-Mails mit benutzerdefinierten Formatierungen abzudunkeln - und das taten wir auch. Zuerst haben wir zwei einfache, reine CSS-Lösungen ausprobiert - Überschreiben von Stilen und Verwenden eines CSS-Filters. Keiner von beiden traf ins Schwarze: Der erste war zu hart für das ursprüngliche Design, und der andere funktionierte einfach nicht gut. Am Ende haben wir uns für die adaptive Verdunkelung entschieden. Wir nehmen die Stile auseinander, ersetzen die Farben und setzen sie wieder zusammen. Wir arbeiten derzeit daran, das dunkle Thema auf Bilder anzuwenden. Dazu müssen wir ihren Inhalt analysieren und dann nur einige davon anpassen.
Wenn Sie jemals die Farbe von benutzerdefinierten HTML-Snipets ändern müssen, um sie in ein dunkles Thema einzufügen, sollten Sie drei Methoden berücksichtigen:
- Stile überschreiben. Es ist eine unkomplizierte, keine Muss-Methode, und Sie werden sie sowieso für Ihre Anwendung benötigen. Die schlechte Nachricht ist, dass alle Originalfarben zerstört werden.
- CSS-Filter. Es macht Spaß, lässt aber zu wünschen übrig. Reservieren Sie es für Elemente, auf die nicht einfach zugegriffen werden kann, z. B. Frames oder Webkomponenten.
- Stilumschreibung. Diese Methode macht einen guten Job beim Abdunkeln, ist aber komplexer.
Selbst wenn Sie nichts davon ausprobieren, hoffe ich, dass Sie viel Spaß beim Lesen dieses Artikels hatten!