La personalizzazione degli elementi dei moduli HTML standard, come le caselle di controllo e i pulsanti di opzione, è sempre stata difficile. Gli sviluppatori spesso dovevano scegliere se utilizzare le impostazioni predefinite del browser o creare componenti personalizzati da zero. La creazione di controlli personalizzati richiede tempo e può facilmente portare a problemi di accessibilità o a stati mancanti (come lo stato indeterminato per le caselle di controllo).
La proprietà CSS accent-color offre un modo semplice per applicare il colore del tuo brand agli input dei moduli HTML integrati con una singola riga di CSS, senza sacrificare l'accessibilità o le funzionalità integrate del browser.
Modalità di implementazione
Per applicare il colore del tuo brand ai controlli dei moduli:
- Identifica il colore del tuo brand: scegli un colore che rappresenti il tuo brand.
- Applica la proprietà
accent-color: aggiungiaccent-colorall'elemento o a un elemento contenitore (comebodyo un modulo specifico) nel CSS. - Supporta la modalità Buio (facoltativo, ma consigliato): utilizza
color-schemeper comunicare al browser che il tuo sito supporta la modalità Buio e, se necessario, regolaaccent-colorper un contrasto migliore.
Esempio di codice: controlli dei moduli coerenti con il brand
:root {
--brand-color: #6200ee;
}
/* Apply accent-color to the body or a specific container */
body {
accent-color: var(--brand-color);
}
/* Optional: Adjust for dark mode if needed */
@media (prefers-color-scheme: dark) {
:root {
--brand-color: #bb86fc; /* A lighter shade for dark mode */
}
}
<form>
<!-- Checkbox -->
<label for="subscribe">
<input type="checkbox" id="subscribe" checked>
Subscribe to newsletter
</label>
<!-- Radio Buttons -->
<label for="plan-monthly">
<input type="radio" id="plan-monthly" name="plan" value="monthly">
Monthly
</label>
<label for="plan-yearly">
<input type="radio" id="plan-yearly" name="plan" value="yearly" checked>
Yearly
</label>
<!-- Range Slider -->
<label for="volume">Volume:</label>
<input type="range" id="volume" min="0" max="100" value="70">
<!-- Progress Bar -->
<label for="file">Upload Progress:</label>
<progress id="file" max="100" value="70">70%</progress>
</form>
Implementazione strategica e best practice
- SÌ: utilizza
accent-colorper applicare facilmente un tema ai controlli dei moduli in modo che corrispondano al tuo brand. - NON affidarti ciecamente al browser per la gestione del contrasto. Sebbene i browser debbano determinare automaticamente un colore di contrasto idoneo, i bug noti nelle implementazioni come Safari (bug WebKit 244233) e Android Chrome (bug Chromium 343503163) possono non invertire i colori dei segni di spunta, rendendo i controlli invisibili o difficili da vedere quando si utilizzano colori che non hanno un contrasto sufficiente con lo sfondo (ad esempio, colori chiari in modalità Luce o colori scuri in modalità Buio).
- SÌ: combina
accent-colorconcolor-scheme: light darkper assicurarti che i controlli dei moduli abbiano un bell'aspetto sia nei temi chiari che in quelli scuri. - NON utilizzare un colore troppo simile a quello dello sfondo. Anche se i browser cercano di garantire il contrasto, è meglio fornire un colore con un buon contrasto di base.
- NON dare per scontato che
accent-colorfunzioni su tutti gli elementi del modulo. Attualmente, colora solo gli elementicheckbox,radio,rangeeprogress.
Strategia di riserva
Per i browser che non supportano accent-color, i controlli del modulo tornano all'aspetto predefinito del browser. Per garantire la massima coerenza del brand e un'elevata affidabilità in tutti gli ambienti, DEVI implementare una strategia di riserva personalizzata utilizzando la tecnica consolidata dell'"input visivamente nascosto".
Potenziamento progressivo con @supports not
DEVI utilizzare la regola @supports not per applicare stili di riserva personalizzati solo quando accent-color non è supportato. In questo modo, potrai sfruttare la semplicità di accent-color per i browser moderni, garantendo al contempo un'esperienza con il brand coerente per quelli meno recenti.
1. Struttura HTML
Assicurati che le etichette racchiudano il testo in un <span> per consentire i selettori di elementi di pari livello in CSS:
<label for="subscribe-fallback">
<input type="checkbox" id="subscribe-fallback" class="visually-hidden" checked>
<span>Subscribe to newsletter</span>
</label>
2. CSS di fallback
Applica stili personalizzati all'interno di un blocco @supports not:
/* Fallback for older browsers without accent-color */
@supports not (accent-color: var(--brand-color)) {
/* Visually hide the native input using the canonical accessible recipe */
form input[type="checkbox"].visually-hidden {
position: absolute !important;
clip-path: inset(50%) !important;
overflow: hidden !important;
width: 1px !important;
height: 1px !important;
margin: -1px !important;
padding: 0 !important;
border: 0 !important;
white-space: nowrap !important;
}
/* Style the wrapper label */
label {
position: relative;
padding-left: 2rem;
cursor: pointer;
display: inline-flex;
align-items: center;
}
/* Custom box for checkbox */
input[type="checkbox"] + span::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 1.2rem;
height: 1.2rem;
border: 2px solid #ccc;
background: white;
border-radius: 4px;
box-sizing: border-box;
transition: all 0.2s ease;
}
/* Ensure custom checkbox shows focus for keyboard users */
input[type="checkbox"]:focus-visible + span::before {
outline: 2px solid #000;
outline-offset: 2px;
}
/* Checked State */
input[type="checkbox"]:checked + span::before {
background-color: var(--brand-color, #6200ee);
border-color: var(--brand-color, #6200ee);
}
/* Checkmark (Unicode) */
input[type="checkbox"]:checked + span::after {
content: "✓";
position: absolute;
left: 0.25rem;
top: 50%;
transform: translateY(-50%);
color: white;
font-weight: bold;
font-size: 0.9rem;
}
/* Fallback for Range Slider */
input[type="range"] {
-webkit-appearance: none;
appearance: none;
background: transparent;
}
/* Webkit (Chrome, Safari, Edge) */
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 8px;
/* Use gradient to show progress for a static value (e.g., 70%) or update with JS */
background: linear-gradient(to right, var(--brand-color, #6200ee) 70%, #ccc 70%);
border-radius: 4px;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--brand-color, #6200ee);
cursor: pointer;
margin-top: -4px; /* Center vertically */
}
/* Firefox */
input[type="range"]::-moz-range-track {
width: 100%;
height: 8px;
background: #ccc;
border-radius: 4px;
}
input[type="range"]::-moz-range-thumb {
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--brand-color, #6200ee);
cursor: pointer;
}
/* Firefox specific progress bar */
input[type="range"]::-moz-range-progress {
background-color: var(--brand-color, #6200ee);
height: 8px;
border-radius: 4px;
}
/* Fallback for Progress Bar */
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
background: #ccc;
height: 8px;
border-radius: 4px;
}
progress::-webkit-progress-bar {
background-color: #ccc;
border-radius: 4px;
}
progress::-webkit-progress-value {
background-color: var(--brand-color, #6200ee);
border-radius: 4px;
}
progress::-moz-progress-bar {
background-color: var(--brand-color, #6200ee);
border-radius: 4px;
}
}
Avanzamento della gamma dinamica nel fallback di Webkit
Per fare in modo che il riempimento dell'avanzamento si sposti con il cursore su un dispositivo di scorrimento dell'intervallo nei browser Webkit (senza accent-color), puoi utilizzare una variabile CSS e una piccola quantità di JavaScript.
Aggiorna il CSS: utilizza una variabile CSS per il punto di interruzione del gradiente:
input[type="range"]::-webkit-slider-runnable-track { background: linear-gradient(to right, var(--brand-color) var(--progress, 0%), #ccc var(--progress, 0%)); }Aggiungi JavaScript: aggiorna la variabile nell'evento
input:
if (!CSS.supports('accent-color')) {
const slider = document.getElementById('volume');
slider.addEventListener('input', (e) => {
e.target.style.setProperty('--progress', `${e.target.value}%`);
});
}