
Nama saya Vladimir, dan saya mengembangkan mobile-end untuk Yandex Mail. Aplikasi kami memiliki tema gelap untuk sementara waktu, tetapi tidak lengkap: hanya antarmuka dan surel yang suram. Pesan dengan pemformatan khusus tetap ringan dan menonjol di antara antarmuka yang gelap, membuat mata pengguna kami terganggu di malam hari.
Hari ini saya akan memberitahu Anda bagaimana kami memperbaiki masalah ini. Anda akan belajar tentang dua teknik sederhana yang tidak berhasil bagi kami dan metode yang akhirnya melakukan trik - adaptasi halaman adaptif. Saya juga akan membagikan beberapa ide tentang mengadaptasi gambar ke tema gelap. Agar adil, menggelapkan halaman dengan CSS khusus adalah tugas yang agak aneh, tapi saya yakin beberapa dari Anda mungkin menemukan pengalaman kami bermanfaat.
Metode sederhana
Sebelum menentukan teknik pelengkungan warna ajaib kami, kami mencoba dua opsi yang sangat mendasar: menerapkan gaya gelap tambahan atau filter CSS ke elemen. Tidak ada opsi yang bekerja untuk kita, tetapi mereka mungkin lebih cocok dalam kasus lain (sederhana itu keren, kan?).
Gaya utama
Ini adalah opsi mati-sederhana, yang secara logis memperluas tema CSS gelap aplikasi itu sendiri. Anda cukup menempatkan gaya gelap tambahan ke wadah email (atau, secara umum, ke wadah untuk konten yang dibuat pengguna menjadi gelap):
.message--dark { background-color: black; color: white; }
Namun, gaya apa pun pada elemen di dalam email akan menimpa gaya root kami. Dan tidak !important
tidak membantu di sini. Idenya dapat diambil selangkah lebih maju dengan mencegah warisan:
.message--dark * { background-color: black !important; color: white !important; border-color: #333 !important; }
Dalam hal ini, Anda tidak dapat melakukannya tanpa !important
, karena pemilih itu sendiri tidak terlalu spesifik. Ini juga terjadi untuk menimpa sebagian besar gaya inline (yang dengan inline !important
masih akan menemukan jalan mereka, dan tidak banyak yang dapat Anda lakukan tentang hal itu).
Gaya kami dengan penuh semangat melukis semuanya dengan warna yang sama, sehingga menimbulkan masalah lain. Ada kemungkinan desainer ingin mengatakan sesuatu dengan cara mereka mengatur warna (Anda tahu, prioritas, pasangan, semua hal desainer), dan kami hanya mengambil ide mereka dan membuangnya ke luar jendela. Bukan hal yang baik untuk dilakukan.

Jika Anda tidak terlalu menghargai desainer seperti saya dan memutuskan untuk menggunakan metode ini, jangan lupa untuk menangani hal-hal yang tidak terlalu jelas:
box-shadow
. Anda tidak akan, hanya dapat menimpa warna. Entah menyingkirkan bayangan sama sekali atau berdamai dengan yang terang.- Warna elemen semantik, seperti tautan atau input.
- SVG sebaris. Gunakan
fill
alih-alih background
, dan stroke
bukan color
, tetapi Anda tidak pernah bisa memastikan, mungkin sebaliknya.
Dari sudut pandang teknis, ini adalah metode yang solid: dibutuhkan tiga baris kode (OK, tiga puluh untuk versi siap produksi dengan semua kasus tepi diurus), ini kompatibel dengan semua browser di dunia, itu berfungsi pada halaman dinamis out-of-the-box, dan cara CSS dilampirkan pada dokumen benar-benar tidak relevan. Ada juga bonus bagus: Anda dapat dengan mudah mengubah warna dalam gaya agar sesuai dengan warna utama aplikasi (misalnya, buat latar belakang #bbbbb8
alih-alih hitam).
Ngomong-ngomong, ini adalah cara kami digunakan untuk menggelapkan email sebelumnya. Jika sebuah email memiliki gaya sendiri, kami hanya akan menyerah dan membiarkannya terang untuk berjaga-jaga.
Menggunakan filter CSS
Ini adalah metode yang cerdas dan elegan. Anda dapat menggelapkan halaman menggunakan filter CSS:
.message--dark { filter: invert(100) hue-rotate(180deg); }
Gambar menjadi menyeramkan, tetapi kita dapat dengan mudah memperbaikinya:
.message-dark img { filter: invert(100) hue-rotate(180deg); }

Namun, ini tidak menyelesaikan masalah gambar konten yang dilampirkan melalui properti latar belakang (tentu, ini berguna untuk menyesuaikan rasio aspek, tetapi bagaimana dengan semantik?). OK, mari kita asumsikan kita dapat menemukan semua elemen ini, secara eksplisit menandai mereka, dan mengubah warna mereka kembali juga.
Hal yang baik tentang metode ini adalah menjaga kecerahan asli dan keseimbangan kontras. Di sisi lain, ini penuh dengan masalah yang melebihi keuntungan:

- Halaman gelap menjadi cerah.
- Anda tidak dapat mengontrol warna akhir. Filter apa yang Anda terapkan ke latar belakang sehingga cocok dengan merek Anda
#bbbbb8
? Itu kepala penggaruk yang nyata. - Pembalikan ganda membuat gambar memudar.
- Performanya lamban, terutama pada perangkat seluler - masuk akal, alih-alih hanya merender halaman, browser menjalankan transformasi Fourier pada setiap undian.
Metode ini akan berfungsi untuk email dengan teks berwarna netral, tetapi saya belum pernah bertemu orang dengan inbox yang penuh dengan konten seperti itu. Di sisi lain, filter adalah satu-satunya cara untuk menggelapkan elemen tanpa mengakses kontennya - bingkai, komponen web, atau gambar.
Tema gelap adaptif
Dan sekarang saatnya sihir! Berdasarkan kelemahan dari dua pendekatan pertama, kami membuat daftar periksa tentang apa yang harus kami tangani:
- Jadikan latar belakang gelap, cahaya teks, dan batas di suatu tempat di antaranya.
- Deteksi halaman gelap dan pertahankan warnanya.
- Pertahankan keseimbangan kecerahan dan kontras yang asli.
- Berikan kontrol atas warna yang dihasilkan.
- Biarkan rona tidak berubah.
Jadi, Anda perlu mengubah warna gaya untuk membuat latar belakang gelap. Mengapa tidak melakukan itu, secara harfiah? Ambil semua gaya, ekstrak aturan terkait color
( color
, background
, border
, box-shadow
, dan subproperti), dan ganti dengan versi "gelap": gelap latar dan perbatasan (tapi tidak sebanyak latar belakang), meringankan teks, dll.
Metode ini memiliki keuntungan luar biasa yang akan menghangatkan hati setiap pengembang. Anda dapat mengonfigurasi aturan konversi warna untuk setiap properti - ya, menggunakan kode! Dengan sedikit imajinasi, Anda dapat menyesuaikan warna dengan tema eksternal apa pun, melakukan koreksi warna apa pun yang Anda inginkan (misalnya, lakukan tema terang alih-alih yang gelap, atau tema warna apa pun yang Anda suka), dan bahkan tambahkan sedikit kontekstual - misalnya, memperlakukan batas yang lebar dan sempit secara berbeda.
Kerugiannya adalah apa yang Anda harapkan dari pendekatan "segalanya-dalam-js". Kami menjalankan skrip, mengacak enkapsulasi gaya, dan mengurai CSS dengan regex. Yang terakhir, bagaimanapun, tidak memalukan seperti dengan HTML, karena tata bahasa CSS biasa (setidaknya pada tingkat yang sedang kami kerjakan).
Inilah rencana gelap kami:
- Normalisasi properti gaya lawas (
bgcolor
dan lainnya) dan pindahkan ke style="..."
. - Temukan semua gaya inline.
- Temukan semua aturan terkait warna di setiap gaya (
background-color
, color
, box-shadow
, dan lainnya). - Ambil warna dari properti terkait warna dan cocokkan dengan konverter yang tepat (mempergelap latar belakang, meringankan teks).
- Panggil konverter.
- Masukkan properti yang dikonversi kembali ke CSS.
Kode wrapper - normalisasi, mencari gaya, parsing - cukup sepele. Mari kita lihat bagaimana sebenarnya konverter ajaib kita berfungsi.
Konversi HSL
Menggelapkan warna tidak sesederhana kedengarannya, terutama jika Anda ingin mempertahankan rona (misalnya, ubah biru menjadi biru tua, bukan oranye). Anda dapat melakukan ini dalam RGB biasa, tetapi bermasalah. Jika Anda tertarik dengan desain algoritmik, Anda tahu bahwa dalam RGB, bahkan gradien rusak. Sementara itu, bekerja dengan warna dalam HSL adalah suguhan yang nyata: alih-alih Merah, Hijau dan Biru, yang Anda tidak tahu harus melakukan apa, Anda memiliki tiga saluran berikut:
- Hue - hal yang ingin kami pertahankan.
- Kejenuhan, yang tidak terlalu penting bagi kita saat ini.
- Ringan, yang akan kita ubah.
Anda bisa menganggapnya sebagai silinder. Kita perlu membalikkan silinder ini. Koreksi warna melakukan sesuatu seperti ini: (h, s, l) => [h, s, 1-l]
.
Warna yang sudah OK
Terkadang kita beruntung dan desain khusus email (atau sebagian darinya) sudah gelap. Ini berarti kita tidak perlu mengubah apa pun - perancang mungkin melakukan pekerjaan yang lebih baik dalam memilih warna yang tidak bisa diimpikan oleh algoritma kita. Di HSL, Anda hanya perlu mempertimbangkan L-Lightness. Jika nilainya lebih tinggi atau lebih rendah (untuk teks dan latar belakang, masing-masing) daripada ambang (yang dapat Anda atur), biarkan saja.
Sirkus dinamis
Meskipun kami tidak memerlukan semua ini (terima kasih banyak, pembersih, Anda menyelamatkan hari saya di sini), saya akan mencantumkan fitur tambahan yang dibutuhkan tema adaptif untuk menggelapkan seluruh halaman dan bukan hanya email statis yang konyol dari tahun 90-an. Peringatan yang adil: tugas ini bukan untuk semua orang.
Gaya inline dinamis
Mengubah gaya sebaris adalah kasus paling sederhana yang mengacaukan halaman gelap kami. Itu biasa, tetapi ada perbaikan sederhana: tambahkan MutationObserver
dan perbaiki gaya inline segera setelah perubahan terjadi.
Gaya eksternal
Bekerja dengan gaya yang dirujuk oleh elemen <link>
dari dalam halaman bisa sangat menyakitkan karena asinkronisitas dan pernyataan @import
. Dan CORS tidak membuat segalanya lebih baik. Sepertinya masalah ini dapat diselesaikan dengan cukup elegan dengan pekerja web (proksi semua *.css
).
Gaya dinamis
Untuk memperburuk keadaan, skrip dapat menambahkan, menghapus, atau mengatur ulang elemen <style>
dan <link>
seperti yang mereka inginkan, dan bahkan mengubah aturan dalam <style>
. Di sini Anda juga perlu menggunakan MutationObserver
, tetapi setiap perubahan akan dikenakan lebih banyak pemrosesan.
Variabel CSS
Banyak hal menjadi sangat liar ketika variabel CSS ikut bermain. Anda tidak dapat menggelapkan variabel: bahkan jika Anda menebak bahwa suatu variabel berisi warna berdasarkan formatnya (meskipun saya menyarankan ini), Anda masih tidak tahu apa perannya - latar belakang, teks, perbatasan, atau semua sekaligus? Selain itu, nilai-nilai variabel CSS diwariskan, jadi Anda harus melacak tidak hanya gaya, tetapi elemen yang diterapkannya, dan ini dengan cepat meningkat di luar kendali.
Setelah variabel CSS berhasil masuk ke arus utama, kami dalam masalah. Di sisi lain, color()
akan didukung saat itu, memungkinkan kami untuk mengganti semua konversi JS kami dengan color(var(--bg) lightness(-50%))
.
Ringkasan

Dalam kasus kami, ketika sanitizer hanya menyisakan gaya inline, penggelapan adaptif di tingkat CSS berfungsi seperti pesona: ia memberikan penggelapan berkualitas tinggi, tidak mengganggu struktur asli, dan relatif sederhana dan cepat. Memperluasnya untuk menangani halaman dinamis mungkin tidak sepadan dengan masalahnya. Untungnya, jika Anda bekerja dengan konten yang dibuat pengguna dan Anda tidak mengembangkan browser, pembersih Anda kemungkinan akan bekerja dengan cara yang sama.
Dalam praktiknya, mode adaptif harus dipasangkan dengan style override, karena elemen standar seperti <input>
atau <a>
sering menggunakan gaya lampu default.
Cara menggelapkan gambar
Gelap gambar adalah masalah terpisah yang mengganggu saya secara pribadi. Ini menantang, dan memberi saya alasan untuk akhirnya menggunakan frasa "analisis spektral". Ada beberapa masalah umum dengan gambar dalam tema gelap.
Beberapa gambar terlalu terang. Ini memberi kami masalah yang sama dengan email cerah yang kami mulai dengan pencarian kami. Masalah ini sering muncul dalam foto biasa, tetapi tidak eksklusif untuk ini. Karena menulis CSS nawala tidak terlalu menyenangkan, beberapa pria suka melompati sudut dengan menyisipkan tata letak yang rumit sebagai gambar, yang mencegah penggelapan. Ketika saya melihat itu, perfeksionis batiniah saya mengerang frustrasi. Gambar-gambar ini harus diredupkan, tetapi tidak terbalik, kecuali jika Anda ingin menakuti pengguna Anda.

Lalu ada gambar gelap dengan transparansi nyata. Ini adalah masalah khas dengan logo - logo dirancang dengan latar belakang yang cerah, dan ketika kami menggantinya dengan latar belakang yang gelap, logo tersebut menghilang ke dalamnya. Gambar-gambar ini perlu dibalik.

Di suatu tempat di antaranya adalah gambar yang menggunakan latar belakang putih yang seharusnya mewakili transparansi. Dalam tema gelap, mereka berakhir dengan segitiga putih yang aneh. Di dunia yang sempurna, kita bisa mengubah latar belakang putih menjadi transparan, tetapi jika Anda pernah menggunakan alat tongkat sihir, Anda tahu betapa sulitnya melakukannya secara otomatis.

Yang cukup menarik, beberapa gambar tidak memiliki makna apa pun. Ini biasanya melacak piksel atau "pemegang format" di tata letak yang aneh. Anda dapat dengan aman membuat mereka tidak terlihat (katakanlah, dengan opacity: 0
).

Menganalisis apa yang ada di dalamnya
Untuk mengetahui cara menyesuaikan gambar untuk tema gelap, kita perlu melihat ke dalam dan menganalisis isinya, terutama dengan metode cepat dan sederhana. Inilah versi pertama dari suatu algoritma yang menyelesaikan ini.
Pertama-tama, hitung piksel gelap, terang, dan transparan gambar. Sebagai pengoptimalan yang jelas, hanya sebagian kecil piksel yang dapat dipertimbangkan. Selanjutnya, tentukan kecerahan keseluruhan gambar (terang, gelap, atau sedang) dan apakah ada transparansi. Balikkan gambar gelap dengan transparansi, gambar terang buram redup, dan biarkan sisanya tidak berubah.
Saya sangat senang dengan penemuan ini sampai saya menemukan buletin amal yang menampilkan foto pelajaran di sekolah Afrika. Perancang memusatkannya dengan menambahkan piksel transparan di sisinya. Kami tidak ingin terlibat dalam cerita tentang pengenalan gambar yang ofensif, jadi kami memutuskan untuk meninggalkan manipulasi gambar dari iterasi pertama kami.
Di masa depan, kita dapat mencegah masalah seperti itu dengan menggunakan heuristik yang saya sebut "analisis spektral". Yaitu, menghitung jumlah rona berbeda dalam gambar dan hanya membalik jika jumlahnya tidak terlalu banyak. Anda dapat menggunakan metode yang sama untuk mengenali gambar samar terang dan membalikkannya juga.

Kesimpulan
Untuk merancang tema gelap yang lengkap, kami harus menemukan cara untuk menggelapkan email yang berisi pemformatan khusus - dan kami melakukannya. Pertama, kami mencoba dua solusi CSS murni dan sederhana - mengganti gaya dan menggunakan filter CSS. Tak satu pun dari mereka yang tepat sasaran: yang pertama terlalu keras pada desain aslinya, dan yang lain tidak bekerja dengan baik. Pada akhirnya, kami memutuskan untuk menggunakan penggelapan adaptif. Kami mengambil gaya terpisah, mengganti warna, dan menempatkannya kembali. Kami sedang berupaya menerapkan tema gelap ke gambar. Untuk melakukan itu, kita perlu menganalisis isinya dan kemudian hanya menyesuaikan beberapa di antaranya.
Jika Anda perlu mengubah warna snipet HTML khusus agar sesuai dengan tema gelap, ingat tiga metode berikut:
- Gaya utama. Tidak perlu repot, tidak ada metode lain, plus Anda tetap akan membutuhkannya untuk aplikasi Anda. Berita buruknya adalah ia menghancurkan semua warna asli.
- Filter CSS. Ini menyenangkan tetapi masih banyak yang diinginkan. Cadangan untuk elemen yang tidak mudah diakses, seperti bingkai atau komponen web.
- Menulis ulang gaya. Metode ini sangat membantu dalam penggelapan, tetapi lebih kompleks.
Bahkan jika Anda tidak pernah mencoba semua ini, saya harap Anda bersenang-senang membaca artikel ini!