Quando crei componenti UI riutilizzabili (come badge o pulsanti) o supporti temi dinamici, garantire che il testo sia leggibile su un colore di sfondo imprevedibile può essere difficile. La funzione CSS contrast-color() viene risolta in black o white, massimizzando il rapporto di contrasto rispetto al colore di sfondo specificato.
Determina il colore ottimale del testo
Quando un elemento ha un colore di sfondo variabile o inserito dinamicamente, puoi fare affidamento sul browser per calcolare il colore del testo più sicuro.
OBBLIGATORIO: imposta la proprietà color utilizzando la funzione contrast-color(), passando il colore di sfondo (o la relativa proprietà personalizzata) come argomento.
.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));
}
DA EVITARE: utilizzare contrast-color() per background-color. È progettata specificamente per i colori di primo piano (come testo o bordi) in contrasto con un determinato colore di sfondo.
Integrazione con i temi
Poiché contrast-color() accetta qualsiasi valore <color> valido, incluse le proprietà personalizzate CSS, è particolarmente efficace nei sistemi di progettazione. Centralizzando i temi di sfondo come variabili, ti assicuri che il contrasto dei contenuti in primo piano venga aggiornato automaticamente ogni volta che il tema cambia, anche con i colori specificati dall'utente.
COSA FARE: fai riferimento alle variabili di background condivise all'interno di contrast-color() per garantire la sincronizzazione nell'applicazione.
.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);
}
DA EVITARE: impostare un colore del testo hardcoded separato per ogni stato di interazione quando lo sfondo è dinamico. In questo modo, si reintroduce la mancata corrispondenza che contrast-color() dovrebbe evitare.
Strategie di riserva
Per supportare i browser senza contrast-color(), devi fornire un'alternativa. Se il colore di sfondo è noto e fisso, utilizza un colore di contrasto hardcoded. Per gli sfondi dinamici in cui il colore è sconosciuto, scegli una strategia dalla tabella seguente in base ai requisiti della UI e ai target di supporto del browser.
| Strategia | Ideale per… | Considerazioni |
|---|---|---|
| Sintassi dei colori relativi | Calcolo automatico del contrasto di alta qualità solo per CSS. | Fallback solo CSS di altissima qualità. |
| Ombra del testo | Miglioramento rapido della leggibilità su qualsiasi sfondo. | Può sembrare "sporco" o "luminoso"; potrebbe non essere adatto a tutti i design. |
| Tratto del testo | Preservare lo spessore del carattere garantendo al contempo il contrasto dei bordi. | Se disponibile, utilizza paint-order per evitare di assottigliare le forme delle lettere. |
| Overlay traslucido | Garantire un'area di contrasto minima dietro il testo. | Modifica l'aspetto del colore di sfondo sotto il testo, richiede un elemento di testo separato. |
| Filtri SVG | Contrasto reattivo che si aggiorna in base alle modifiche dello sfondo. | Richiede un elemento di testo separato; implementazione complessa. |
Consigliato: sintassi del colore relativa (RCS)
Per i browser che lo supportano, RCS fornisce il fallback automatico più efficace per i colori dinamici.
@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));
}
}
Alternative CSS Fallbacks
COSA FARE: seleziona il fallback che meglio si adatta ai tuoi vincoli di progettazione se RCS non è sufficiente o supportato.
Opzione 1: tratto del testo
.badge--stroke {
-webkit-text-stroke: 4px black;
}
Opzione 2: tratto del testo con paint-order per preservare le forme delle lettere
.badge--stroke {
-webkit-text-stroke: 4px black;
paint-order: stroke fill;
}
Opzione 3: overlay di sfondo traslucido
.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;
}
Opzione 4: Ombreggiatura testo
.badge--shadow {
text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}
Opzione 5: filtri SVG
Carica questa definizione di filtro SVG. Deve essere aggiunto direttamente al documento HTML se devi supportare le versioni di Safari interessate da questo bug di WebKit, che impedisce i riferimenti a URL esterni e di dati per i filtri. In caso contrario, deve essere caricato da un file esterno, un file SVG o incorporato nel 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>Inserisci il testo in un tag
<span>.<div class="badge--svg"> <span>Badge content</span> </div>Applica il filtro a
<span>.
.badge--svg span{
color: var(--badge-bg);
filter: url(#contrast-filter);
}