Creazione di un componente di un pulsante

Una panoramica di base su come creare componenti <button> adattabili al colore, adattabili e accessibili.

In questo post voglio condividere le mie idee su come creare un elemento <button> adattabile al colore, adattabile e accessibile. Prova la demo e visualizza la fonte

I pulsanti consentono di interagire tramite tastiera e mouse nei temi chiaro e scuro.

Se preferisci i video, ecco una versione di YouTube di questo post:

Panoramica

Supporto dei browser

  • 1
  • 12
  • 1
  • ≤4

Fonte

L'elemento <button> è stato creato per l'interazione dell'utente. Il suo evento click viene attivato tramite tastiera, mouse, tocco, voce e altro, con regole intelligenti sulla tempistica. Include anche alcuni stili predefiniti in ciascun browser, quindi puoi utilizzarli direttamente senza alcuna personalizzazione. Utilizza color-scheme per attivare anche i pulsanti chiari e scuri forniti dal browser.

Esistono anche diversi tipi di pulsanti, ciascuno mostrato nell'incorporamento precedente di Codepen. Un <button> senza tipo si adatterà a essere all'interno di un <form>, cambiando il tipo di invio.

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

In GUI Challenge di questo mese, ogni pulsante riceverà stili che ti aiuteranno a distinguere visivamente l'intenzione. I pulsanti di reimpostazione avranno colori di avviso poiché sono distruttivi, mentre i pulsanti Invia assumeranno un testo intenso blu in modo che appaiano leggermente più in evidenza rispetto ai normali pulsanti.

Anteprima dell&#39;insieme finale di tutti i tipi di pulsanti, mostrato in un modulo e non in un modulo, con piacevoli aggiunte per pulsanti icona e pulsanti personalizzati.
Anteprima dell'insieme finale di tutti i tipi di pulsanti, mostrato in un modulo e non in un modulo, con aggiunte utili per i pulsanti delle icone e quelli personalizzati

I pulsanti contengono anche pseudo classi che il CSS può utilizzare per lo stile. Queste classi forniscono hook CSS per personalizzare l'aspetto del pulsante: :hover quando il mouse è posizionato sopra il pulsante, :active per la pressione di un mouse o della tastiera e :focus o :focus-visible per facilitare lo stile delle tecnologie per la disabilità.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Anteprima dell&#39;insieme finale di tutti i tipi di pulsanti con il tema scuro.
Anteprima dell'insieme finale di tutti i tipi di pulsanti con il tema scuro

Markup

Oltre ai tipi di pulsanti forniti dalla specifica HTML, ho aggiunto un pulsante con un'icona e un pulsante con una classe personalizzata btn-custom.

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

Quindi, per i test, ogni pulsante viene inserito all'interno di un modulo. In questo modo posso assicurarmi che gli stili vengano aggiornati correttamente per il pulsante predefinito, che si comporta come un pulsante Invia. Per assicurarmi che entrambe funzionino allo stesso modo, modifico anche la strategia per le icone, passando da SVG in linea a SVG mascherato.

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

La matrice di combinazioni è piuttosto schiacciante in questo momento. Tra tipi di pulsanti, pseudo-classi e l'interno o l'esterno di un modulo, ci sono oltre 20 combinazioni di pulsanti. è una cosa positiva che il CSS può aiutarci a illustrare chiaramente.

Accessibilità

Gli elementi pulsante sono naturalmente accessibili, ma ci sono alcuni miglioramenti comuni.

Passa il mouse e metti a fuoco insieme

Mi piace raggruppare :hover e :focus insieme allo pseudo-selettore funzionale :is(). Così le interfacce tengono sempre conto degli stili di tastiera e tecnologie per la disabilità.

button:is(:hover, :focus) {
  …
}
Prova una demo.

Anello di messa a fuoco interattiva

Mi piace animare l'anello di messa a fuoco per gli utenti che usano tastiera e tecnologie per la disabilità. Per risolvere questo problema, rimuovono i contorni dal pulsante di 5 px, ma solo quando il pulsante non è attivo. Questo crea un effetto che, quando premuto, riporta l'anello di messa a fuoco alle dimensioni del pulsante.

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Garanzia di un contrasto cromatico passeggero

Esistono almeno quattro diverse combinazioni di colori, chiaro e scuro, che devono essere valutate con il contrasto di colore: pulsante, pulsante Invia, pulsante di ripristino e pulsante disattivato. VisBug viene utilizzato qui per controllare e mostrare tutti i punteggi contemporaneamente:

Le icone verranno nascoste a chi non può vederle

Quando lo crei, l'icona deve fornire un supporto visivo al testo del pulsante. Significa anche che l'icona non è utile per chi soffre di perdita della vista. Fortunatamente il browser consente di nascondere gli elementi alla tecnologia di screen reader, in modo che le persone con problemi di vista non siano disturbati dalle immagini decorative dei pulsanti:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Chrome DevTools che mostra l&#39;albero dell&#39;accessibilità per il pulsante. L&#39;albero ignora l&#39;immagine del pulsante perché aria-hidden è impostato su true.
Chrome DevTools che mostra l'albero dell'accessibilità per il pulsante. L'albero ignora l'immagine del pulsante perché ha aria-hidden impostato su true.

Stili

In questa sezione, stabilisco innanzitutto un sistema di proprietà personalizzate per gestire gli stili adattivi del pulsante. Con queste proprietà posso iniziare a selezionare elementi e personalizzarne l'aspetto.

Una strategia di proprietà personalizzata adattiva

La strategia di proprietà personalizzata utilizzata in questa verifica GUI è molto simile a quella utilizzata per la creazione di una combinazione di colori. Per un sistema di colori chiaro e scuro adattivo, viene definita e denominata di conseguenza una proprietà personalizzata per ogni tema. Quindi viene utilizzata una singola proprietà personalizzata per contenere il valore corrente del tema e viene assegnata a una proprietà CSS. In seguito, la singola proprietà personalizzata può essere aggiornata a un valore diverso e poi aggiornando lo stile del pulsante.

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

Quello che mi piace è che i temi chiaro e scuro sono chiari e dichiarativi. L'indirezione e l'astrazione vengono trasferite nella proprietà personalizzata --_bg, che ora è l'unica proprietà "reattiva"; --_bg-light e --_bg-dark sono statiche. È anche chiaro che il tema chiaro è il tema predefinito e che il tema scuro viene applicato solo in modo condizionale.

Prepararsi per la coerenza del design

Il selettore condiviso

Il seguente selettore viene utilizzato per scegliere come target tutti i vari tipi di pulsanti e all'inizio è un po' complesso. Poiché viene utilizzato :where(), la personalizzazione del pulsante non richiede specificità. I pulsanti sono spesso adattati a scenari alternativi e il selettore :where() assicura che l'attività sia semplice. All'interno di :where(), è selezionato ogni tipo di pulsante, incluso ::file-selector-button, che non può essere utilizzato all'interno di :is() o :where().

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  …
}

L'ambito di tutte le proprietà personalizzate verrà limitato all'interno di questo selettore. È il momento di esaminare tutte le proprietà personalizzate. Questo pulsante utilizza un bel po' di proprietà personalizzate. Descriveremo i singoli gruppi man mano che procediamo, quindi parlerò dei contesti oscuri e ridotti di movimento alla fine.

Colore intenso pulsante

I pulsanti e le icone Invia sono un ottimo posto per dare un tocco di colore:

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

Colore testo del pulsante

I colori del testo dei pulsanti non sono bianchi o neri, sono versioni scure o schiacciate di --_accent utilizzando hsl() e mantenendo la tonalità 210:

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

Colore sfondo pulsante

Gli sfondi dei pulsanti seguono lo stesso pattern hsl() ad eccezione dei pulsanti del tema chiaro, che sono impostati sul bianco in modo che la loro superficie li faccia apparire vicino all'utente o davanti ad altre superfici:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

Pulsante sfondo

Questo colore di sfondo consente di far apparire una superficie dietro altre superfici, utile per lo sfondo del file di input:

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

Spaziatura interna pulsante

La spaziatura intorno al testo nel pulsante viene eseguita utilizzando l'unità ch, una lunghezza relativa alle dimensioni del carattere. Questo aspetto diventa fondamentale quando pulsanti di grandi dimensioni possono semplicemente aumentare proporzionalmente font-size e scalare i pulsanti in modo proporzionale:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

Bordo pulsante

Il raggio del bordo del pulsante è memorizzato in una proprietà personalizzata in modo che l'input del file possa corrispondere agli altri pulsanti. I colori dei bordi seguono il sistema di colori adattivo stabilito:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

Effetto di evidenziazione del pulsante al passaggio del mouse

Queste proprietà stabiliscono una proprietà delle dimensioni per la transizione al momento dell'interazione e il colore di evidenziazione segue il sistema di colori adattivi. Vedremo come interagiscono questi elementi più avanti in questo post, ma alla fine vengono utilizzati per un effetto box-shadow:

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

Ombra del testo del pulsante

Ogni pulsante ha un sottile stile di ombra del testo. Così il testo si posiziona sopra il pulsante, migliorando la leggibilità e aggiungendo un tocco di eleganza alla presentazione.

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

Icona del pulsante

Le icone hanno la dimensione di due caratteri grazie alla nuova unità di lunghezza relativa (ch), che consentirà di ridimensionare l'icona proporzionalmente al testo del pulsante. Il colore dell'icona si appoggia a --_accent-color per scegliere un colore adattivo all'interno del tema.

--_icon-size: 2ch;
--_icon-color: var(--_accent);

Ombra pulsante

Affinché le ombre si adattino correttamente alla luce e allo scuro, devono modificare sia il colore che l'opacità. Le ombre con il tema chiaro sono migliori quando sono discrete e con un gradiente in linea con il colore della superficie su cui si sovrappongono. Le ombre del tema scuro devono essere più scure e saturate per sovrapporsi ai colori della superficie più scuri.

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

Con i colori adattivi e i punti di forza posso combinare due profondità di ombre:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

Inoltre, per dare ai pulsanti un aspetto leggermente tridimensionale, un'ombra della casella 1px crea l'illusione:

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

Transizioni dei pulsanti

Seguendo il pattern per i colori adattivi, creo due proprietà statiche per contenere le opzioni del sistema di progettazione:

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

Tutte le proprietà insieme nel selettore

Tutte le proprietà personalizzate in un selettore

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

I pulsanti predefiniti vengono visualizzati con il tema chiaro e il tema scuro affiancati.

Adattamenti del tema scuro

Il valore del pattern degli oggetti di scena statici -light e -dark diventa chiaro quando vengono impostati gli oggetti di tema scuro:

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

Non solo va bene, ma i consumatori di questi pulsanti personalizzati possono usare gli strumenti semplici con la sicurezza di adattarsi in modo appropriato alle preferenze dell'utente.

Adattamenti dei movimenti ridotti

Se il movimento è OK per l'utente che effettua la visita, assegna --_transition a var(--_transition-motion-ok):

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

Alcuni stili condivisi

I caratteri dei pulsanti e degli input devono essere impostati su inherit in modo che corrispondano al resto dei caratteri della pagina, altrimenti verranno definiti dallo stile del browser. Questo vale anche per letter-spacing. Se imposti line-height su 1.5, le dimensioni della casella lettera vengono impostate per dare spazio al testo sopra e sotto:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Stili dei pulsanti

Regolazione del selettore

Il selettore input[type="file"] non è la parte del pulsante dell'input, ma lo è lo pseudo-elemento ::file-selector-button, quindi ho rimosso input[type="file"] dall'elenco:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Regolazioni cursore e tocco

Per prima cosa, definisco lo stile del cursore pointer, che consente al pulsante di indicare agli utenti del mouse che è interattivo. Aggiungo touch-action: manipulation per evitare che i clic debbano attendere e osservare un potenziale doppio clic, rendendo i pulsanti più veloci:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

Colori e bordi

Poi personalizzo la dimensione del carattere, lo sfondo, il testo e i colori dei bordi, utilizzando alcune delle proprietà personalizzate adattive stabilite in precedenza:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Ombre

Ai pulsanti vengono applicate tecniche eccezionali. text-shadow si adatta al chiaro e al buio, creando un piacevole aspetto del testo del pulsante ben posizionato sopra lo sfondo. Per box-shadow, vengono assegnate tre ombre. La prima, --_shadow-2, è una normale ombra del riquadro. La seconda ombra è un trucco per gli occhi che fa sembrare il pulsante un po' smussato. L'ultima ombra è per l'evidenziazione al passaggio del mouse, che inizialmente avrà una dimensione pari a 0, ma le verrà data una dimensione in seguito e verrà eseguita la transizione in modo che sembri ingrandita rispetto al pulsante.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Layout

Ho assegnato al pulsante un layout flexbox, in particolare un layout inline-flex che si adatta ai contenuti. Quindi centra il testo e allineo gli elementi secondari al centro verticalmente e orizzontalmente. In questo modo, le icone e altri elementi dei pulsanti verranno allineati correttamente.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Spaziatura

Per la spaziatura dei pulsanti, ho utilizzato gap per evitare che i fratelli e le sorelle possano toccare e usare le proprietà logiche per la spaziatura interna, in modo che la spaziatura dei pulsanti funzioni per tutti i layout di testo.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Esperienza utente con tocco e mouse

La prossima sezione riguarda soprattutto gli utenti touch su dispositivi mobili. La prima proprietà, user-select, è per tutti gli utenti e impedisce al testo di evidenziare il testo del pulsante. È per lo più visibile sui dispositivi touch quando si tocca e si tiene premuto un pulsante e il sistema operativo evidenzia il testo del pulsante.

In genere ho notato che non si tratta dell'esperienza utente con i pulsanti nelle app integrate, quindi la disattivo impostando user-select su Nessuno. Colori di evidenziazione dei tocchi (-webkit-tap-highlight-color) e menu contestuali del sistema operativo (-webkit-touch-callout) sono altre funzionalità dei pulsanti incentrate sul web che non sono in linea con le aspettative generali degli utenti dei pulsanti, quindi rimuovo anche queste funzionalità.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

Transizioni

La variabile adattiva --_transition è assegnata alla proprietà transition:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  transition: var(--_transition);
}

Al passaggio del mouse, mentre l'utente non sta premendo attivamente, regola le dimensioni di evidenziazione dell'ombra per ottenere un buon aspetto che appaia all'interno del pulsante:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

Dopo aver impostato lo stato attivo, aumenta lo spostamento dei contorni di messa a fuoco dal pulsante, dandogli anche un aspetto interessante che sembra crescere dall'interno del pulsante:

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Icone

Per gestire le icone, nel selettore è stato aggiunto un selettore :where() per gli elementi secondari SVG diretti o gli elementi con l'attributo personalizzato data-icon. Le dimensioni dell'icona vengono impostate con la proprietà personalizzata usando proprietà logiche incorporate e di blocco. Il colore del tratto è impostato, così come drop-shadow per corrispondere a text-shadow. flex-shrink è impostato su 0, pertanto l'icona non viene mai schiacciata. Infine, seleziono le icone a righe e assegno gli stili qui con i limiti di riga e i unioni delle righe fill: none e round:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Personalizzazione dei pulsanti di invio

Volevo che i pulsanti inviassero un aspetto leggermente promosso e l'ho fatto rendendo il colore del testo dei pulsanti il colore intenso:

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Personalizza i pulsanti di ripristino

Volevo che i pulsanti di reset avessero alcuni segnali di avviso integrati per avvisare gli utenti del loro potenziale comportamento distruttivo. Ho anche optato per il tema chiaro, con più accenti rossi rispetto al tema scuro. La personalizzazione viene eseguita modificando il colore di base chiaro o scuro appropriato e il pulsante aggiornerà lo stile:

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

Ho anche pensato che sarebbe stato bello che il colore dei contorni di messa a fuoco abbinasse l'accento rosso. Il colore del testo adatta un rosso scuro a un rosso chiaro. Faccio in modo che il colore dei contorni corrisponda a questo valore con la parola chiave currentColor:

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Personalizzazione dei pulsanti disattivati

È troppo comune che i pulsanti disattivati abbiano uno scarso contrasto di colore quando si tenta di sottrarre il pulsante disattivato in modo che risulti meno attivo. Ho testato ogni set di colori e mi sono assicurato che venissero superati, modificando il valore di luminosità HSL fino al punteggio trasmesso in DevTools o VisBug.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Personalizzazione dei pulsanti di input dei file

Il pulsante di input del file è un contenitore per una sezione e un pulsante. CSS è in grado di modificare leggermente il contenitore di input e il pulsante nidificato, ma non l'intervallo. Al container viene assegnato un valore max-inline-size in modo che non cresca più del necessario, mentre inline-size: 100% permette di ridurre e adattare i contenitori di dimensioni inferiori. Il colore di sfondo è impostato su un colore adattivo più scuro rispetto ad altre superfici, in modo che venga visualizzato dietro il pulsante di selezione dei file.

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

Il pulsante del selettore file e i pulsanti per il tipo di input vengono assegnati specificatamente a appearance: none per rimuovere tutti gli stili forniti dal browser che non sono stati sovrascritti dagli altri stili del pulsante.

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

Infine, viene aggiunto un margine al punto inline-end del pulsante per allontanare il testo dal pulsante, creando un po' di spazio.

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Eccezioni particolari per il tema scuro

Ho assegnato ai pulsanti di azione principali uno sfondo più scuro per un testo a contrasto più elevato, dando loro un aspetto leggermente più promosso.

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

Screenshot che mostra i pulsanti dopo l&#39;applicazione degli stili precedenti.

Creare varianti

Per divertimento e dato che è pratico, ho scelto di mostrare come creare alcune varianti. Una variante è molto vivace, simile alla frequenza con cui appaiono i pulsanti principali. Un'altra variante è grande. L'ultima variante ha un'icona piena di gradiente.

Pulsante Vivace

Per realizzare questo stile con i pulsanti, ho sovrascritto direttamente la base con i colori blu. Questa operazione è stata facile e veloce, ma rimuove gli oggetti di scena adattivi e ha lo stesso aspetto sia nei temi chiari che in quelli scuri.

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

Il pulsante personalizzato viene mostrato in condizioni di luce chiara e scura. È molto vivace di colore blu, come in genere i pulsanti di azione principali.

Pulsante grande

Questo stile di pulsante si ottiene modificando la proprietà personalizzata --_size. La spaziatura interna e gli altri elementi dello spazio sono relativi a questa dimensione e vengono scalati proporzionalmente alla nuova dimensione.

.btn-large {
  --_size: 1.5rem;
}

Il pulsante grande viene mostrato accanto al pulsante personalizzato, circa 150 volte più grande.

Pulsante icona

Questo effetto icona non ha nulla a che fare con gli stili dei pulsanti, ma mostra come ottenerlo con poche proprietà CSS e l'efficacia con cui il pulsante gestisce le icone non SVG incorporate.

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

Un pulsante con un&#39;icona viene mostrato in temi chiari e scuri.

Conclusione

Ora che sai come ci sono riuscito, come faresti? 🙂

Diversifica i nostri approcci e scopriamo tutti i modi per creare sul web.

Crea una demo, inviami un tweet con i link e lo aggiungerò alla sezione Remix della community di seguito.

Remix della community

Ancora niente da visualizzare.

Risorse