Moduli coerenti con il brand

Funzionalità web: accent-color

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:

  1. Identifica il colore del tuo brand: scegli un colore che rappresenti il tuo brand.
  2. Applica la proprietà accent-color: aggiungi accent-color all'elemento o a un elemento contenitore (come body o un modulo specifico) nel CSS.
  3. Supporta la modalità Buio (facoltativo, ma consigliato): utilizza color-scheme per comunicare al browser che il tuo sito supporta la modalità Buio e, se necessario, regola accent-color per 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-color per 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-color con color-scheme: light dark per 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-color funzioni su tutti gli elementi del modulo. Attualmente, colora solo gli elementi checkbox, radio, range e progress.

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.

  1. 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%));
    }
    
  2. 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}%`);
  });
}