Saat membuat komponen UI yang dapat digunakan kembali (seperti badge atau tombol) atau mendukung tema dinamis, memastikan teks dapat dibaca dengan warna latar belakang yang tidak dapat diprediksi bisa menjadi tantangan. Fungsi CSS contrast-color() di-resolve ke black atau white, sehingga memaksimalkan rasio kontras terhadap warna latar belakang yang ditentukan.
Menentukan warna teks yang optimal
Jika elemen memiliki warna latar belakang variabel atau yang dimasukkan secara dinamis, Anda dapat mengandalkan browser untuk menghitung warna teks yang paling aman.
WAJIB: Tetapkan properti color menggunakan fungsi contrast-color(), dengan meneruskan warna latar belakang (atau properti kustomnya) sebagai argumen.
.badge {
/* Define the background color as a custom property */
--badge-bg: #e02424;
background-color: var(--badge-bg);
/* MANDATORY: Dynamic contrasting color */
color: contrast-color(var(--badge-bg));
}
JANGAN: Menggunakan contrast-color() untuk background-color. Warna ini dirancang khusus untuk warna latar depan (seperti teks atau batas) agar kontras dengan warna latar belakang tertentu.
Mengintegrasikan dengan tema
Karena contrast-color() menerima nilai <color> yang valid, termasuk properti kustom CSS, fungsi ini sangat efektif dalam sistem desain. Dengan memusatkan tema latar belakang sebagai variabel, Anda memastikan bahwa konten latar depan otomatis memperbarui kontrasnya setiap kali tema berubah, bahkan ke warna yang ditentukan pengguna.
LAKUKAN: Referensikan variabel latar belakang bersama di dalam contrast-color() untuk menjamin sinkronisasi di seluruh aplikasi Anda.
.theme-card {
background-color: var(--theme-surface-color);
color: contrast-color(var(--theme-surface-color));
}
.theme-container[data-theme="light"] {
--theme-surface-color: #f4f4f4;
}
.theme-container[data-theme="dark"] {
--theme-surface-color: #1a1a1a;
}
.theme-container[data-theme="custom"] {
--theme-surface-color: var(--user-custom-theme);
}
JANGAN: Melakukan hard code pada warna teks terpisah untuk setiap status interaksi saat latar belakang bersifat dinamis. Tindakan ini akan memunculkan kembali ketidakcocokan yang seharusnya dicegah oleh contrast-color().
Strategi penggantian
Untuk mendukung browser tanpa contrast-color(), Anda harus menyediakan penggantian. Jika warna latar belakang diketahui dan tetap, gunakan warna kontras hard code. Untuk latar belakang dinamis yang warnanya tidak diketahui, pilih strategi dari tabel di bawah berdasarkan persyaratan UI dan target dukungan browser Anda.
| Strategi | Paling Cocok Untuk... | Pertimbangan |
|---|---|---|
| Sintaksis Warna Relatif | Penghitungan kontras khusus CSS yang otomatis dan berkualitas tinggi. | Penggantian khusus CSS dengan kualitas tertinggi. |
| Bayangan Teks | Peningkatan keterbacaan cepat di latar belakang apa pun. | Dapat terlihat "kotor" atau "berkilau"; mungkin tidak cocok untuk semua desain. |
| Goresan Teks | Mempertahankan ketebalan font sekaligus memastikan kontras tepi. | Gunakan paint-order untuk menghindari penipisan bentuk huruf, jika tersedia. |
| Overlay Transparan | Memastikan area kontras minimum di belakang teks. | Mengubah tampilan warna latar belakang di bawah teks, memerlukan elemen teks terpisah. |
| Filter SVG | Kontras reaktif yang diperbarui saat latar belakang berubah. | Memerlukan elemen teks terpisah; implementasi yang rumit. |
Direkomendasikan: Sintaksis Warna Relatif (RCS)
Untuk browser yang mendukungnya, RCS menyediakan penggantian otomatis yang paling andal untuk warna dinamis.
@supports (color: oklch(from red l c h)) {
.badge {
/* Highest threshold that passes WCAG. Higher values may be more legible. */
--threshold: 0.623;
--l: max(0, sign(var(--threshold) - l));
color: oklch(from var(--badge-bg) var(--l) 0 h);
}
}
@supports (color: contrast-color(red)) {
.badge {
color: contrast-color(var(--badge-bg));
}
}
Penggantian CSS Alternatif
LAKUKAN: Pilih penggantian yang paling sesuai dengan batasan desain Anda jika RCS tidak memadai atau tidak didukung.
Opsi 1: Text Stroke
.badge--stroke {
-webkit-text-stroke: 4px black;
}
Opsi 2: Text Stroke dengan paint-order untuk mempertahankan bentuk huruf
.badge--stroke {
-webkit-text-stroke: 4px black;
paint-order: stroke fill;
}
Opsi 3: Overlay latar belakang transparan
.badge--overlay {
position: relative;
color: #fff;
overflow: hidden;
}
.badge--overlay::before {
content: "";
position: absolute;
inset: 0;
background-color: rgb(0 0 0 / 0.4);
z-index: 0;
}
.badge--overlay span {
position: relative;
z-index: 1;
}
Opsi 4: Bayangan Teks
.badge--shadow {
text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}
Opsi 5: Filter SVG
Muat definisi filter SVG ini. Elemen ini harus ditambahkan langsung ke dokumen HTML jika Anda perlu mendukung versi Safari yang terpengaruh oleh bug WebKit ini, yang mencegah referensi URL data dan eksternal untuk filter. Jika tidak, ikon harus dimuat dari file eksternal, baik file SVG atau inline di CSS.
<!-- Technique from https://miunau.com/posts/dynamic-text-contrast-in-css/ --> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0" style="display: none;"> <defs> <filter id="contrast-filter" color-interpolation-filters="sRGB"> <feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/> <feMorphology operator="dilate" radius="2"/> <feComponentTransfer> <feFuncR type="linear" slope="-255" intercept="128"/> <feFuncG type="linear" slope="-255" intercept="128"/> <feFuncB type="linear" slope="-255" intercept="128"/> </feComponentTransfer> <feComposite operator="in" in2="SourceGraphic"/> </filter> </defs> </svg>Gabungkan teks dalam
<span>.<div class="badge--svg"> <span>Badge content</span> </div>Terapkan filter ke
<span>.
.badge--svg span{
color: var(--badge-bg);
filter: url(#contrast-filter);
}