Creazione di un componente di un pulsante

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

In questo post voglio condividere le mie idee su come creare un elemento <button> accessibile, reattivo e con colori adattabili. Prova la demo e visualizza il codice sorgente

I pulsanti vengono utilizzati tramite tastiera e mouse nei temi chiaro e scuro.

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

Panoramica

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

L'elemento <button> è progettato per l'interazione utente. I suoi click eventi vengono attivati da tastiera, mouse, tocco, voce e altro ancora, con regole intelligenti sulla tempistica. Inoltre, ogni browser include alcuni stili predefiniti, che puoi utilizzare direttamente senza alcuna personalizzazione. Utilizza color-scheme per attivare anche i pulsanti chiaro e scuro forniti dal browser.

Esistono anche diversi tipi di pulsanti, ognuno mostrato nell'incorporamento di Codepen precedente. Un <button> senza tipo si adatterà a essere all'interno di un <form>, passando al 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">

Nella GUI Challenge di questo mese, ogni pulsante riceverà stili per differenziare visivamente la sua intenzione. I pulsanti di ripristino avranno colori di avviso perché sono distruttivi, mentre i pulsanti di invio avranno un testo blu in evidenza, in modo che appaiano leggermente più in evidenza rispetto ai pulsanti normali.

Anteprima del set finale di tutti i tipi di pulsanti, mostrati in un modulo e non in un modulo, con belle aggiunte per i pulsanti con icone e i pulsanti personalizzati.
Anteprima del set finale di tutti i tipi di pulsanti, mostrati in un modulo e non in un modulo, con belle aggiunte per i pulsanti con icone e i pulsanti personalizzati

I pulsanti hanno anche pseudo classi per l'utilizzo di CSS per l'applicazione di stili. Queste classi forniscono hook CSS per personalizzare l'aspetto del pulsante: :hover per quando il mouse è sopra il pulsante, :active per quando il mouse o la tastiera preme e :focus o :focus-visible per facilitare lo stile della tecnologia assistiva.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Anteprima del set finale di tutti i tipi di pulsanti nel tema scuro.
Anteprima del set finale di tutti i tipi di pulsanti nel tema scuro

Segni e linee

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">

Per i test, ogni pulsante viene inserito all'interno di un modulo. In questo modo posso assicurarmi che gli stili vengano aggiornati in modo appropriato per il pulsante predefinito, che si comporta come un pulsante di invio. Inoltre, cambio la strategia delle icone, passando da SVG in linea a SVG mascherato, per garantire che entrambi funzionino altrettanto bene.

<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>

A questo punto, la matrice delle combinazioni è piuttosto travolgente. Tra tipi di pulsanti, pseudo-classi e presenza o assenza in un modulo, esistono oltre 20 combinazioni di pulsanti. È un bene che CSS possa aiutarci a esprimere chiaramente ciascuno di questi aspetti.

Accessibilità

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

Passare il mouse sopra e mettere a fuoco insieme

Mi piace raggruppare :hover e :focus con lo pseudo selettore funzionale :is(). In questo modo, le mie interfacce tengono sempre conto degli stili della tastiera e delle tecnologie assistive.

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

Anello di messa a fuoco interattivo

Mi piace animare l'anello di messa a fuoco per gli utenti di tastiere e tecnologie assistive. Per farlo, animo il contorno del pulsante allontanandolo di 5 px, ma solo quando il pulsante non è attivo. In questo modo, quando viene premuto, l'anello di messa a fuoco si riduce alle dimensioni del pulsante.

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

Garantire un contrasto cromatico sufficiente

Esistono almeno quattro diverse combinazioni di colori chiari e scuri che richiedono di considerare il contrasto cromatico: pulsante, pulsante Invia, pulsante Reimposta e pulsante disattivato. VisBug viene utilizzato qui per ispezionare e mostrare tutti i punteggi contemporaneamente:

Nascondere le icone alle persone che non possono vederle

Quando crei un pulsante con icona, l'icona deve fornire un supporto visivo al testo del pulsante. Ciò significa anche che l'icona non è utile per una persona con perdita della vista. Fortunatamente, il browser offre un modo per nascondere gli elementi dalla tecnologia screen reader, in modo che le persone con perdita della vista non siano disturbate dalle immagini dei pulsanti decorativi:

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

Stili

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

Una strategia di proprietà personalizzate adattiva

La strategia delle proprietà personalizzate utilizzata in questa GUI Challenge è molto simile a quella utilizzata per creare una combinazione di colori. Per un sistema di colori adattivo chiaro e scuro, viene definita e denominata di conseguenza una proprietà personalizzata per ogni tema. Quindi, una singola proprietà personalizzata viene utilizzata per contenere il valore corrente del tema e viene assegnata a una proprietà CSS. In un secondo momento, la singola proprietà personalizzata può essere aggiornata con un valore diverso, aggiornando poi 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);
  }
}

Mi piace che i temi chiaro e scuro siano dichiarativi e chiari. L'indirezione e l'astrazione vengono scaricate nella proprietà personalizzata --_bg, che ora è l'unica proprietà "reattiva"; --_bg-light e --_bg-dark sono statiche. Inoltre, è chiaro che il tema chiaro è quello predefinito e quello scuro viene applicato solo in determinate condizioni.

Preparazione per la coerenza della progettazione

Il selettore condiviso

Il seguente selettore viene utilizzato per scegliere come target tutti i vari tipi di pulsanti ed è un po' complicato all'inizio. :where() viene utilizzato, quindi la personalizzazione del pulsante non richiede specificità. I pulsanti vengono spesso adattati a scenari alternativi e il selettore :where() garantisce che l'attività sia semplice. All'interno di :where(), ogni tipo di pulsante è selezionato, 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 {
  
}

Tutte le proprietà personalizzate verranno incluse in questo selettore. È il momento di esaminare tutte le proprietà personalizzate. In questo pulsante vengono utilizzate diverse proprietà personalizzate. Descriverò ogni gruppo man mano che procediamo, poi condividerò i contesti di movimento ridotto e tema scuro alla fine della sezione.

Colore accento pulsante

I pulsanti di invio e le icone sono un ottimo posto per 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 bianco o nero, ma versioni più scure o più chiare di --_accent utilizzando hsl() e rispettando 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 hsl() pattern, ad eccezione dei pulsanti del tema chiaro, che sono impostati su bianco in modo che la loro superficie li faccia apparire vicini all'utente o davanti ad altre superfici:

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

Sfondo pulsante

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

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

Spaziatura interna del pulsante

La spaziatura intorno al testo nel pulsante viene eseguita utilizzando l'unità ch, una lunghezza relativa alla dimensione del carattere. Ciò diventa fondamentale quando i pulsanti grandi possono semplicemente aumentare proporzionalmente le scale font-size e dei pulsanti:

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

Bordo pulsante

Il raggio del bordo del pulsante viene memorizzato in una proprietà personalizzata in modo che l'input del file possa corrispondere agli altri pulsanti. I colori del bordo seguono il sistema di colori adattivi consolidato:

--_border-radius: .5ch;

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

Effetto di evidenziazione al passaggio del mouse sul pulsante

Queste proprietà stabiliscono una proprietà di dimensione per la transizione durante l'interazione e il colore di evidenziazione segue il sistema di colori adattivo. Vedremo come interagiscono più avanti in questo post, ma in definitiva vengono utilizzate 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);

Ombreggiatura testo pulsante

Ogni pulsante ha uno stile di ombreggiatura del testo sottile. In questo modo, il testo si trova sopra il pulsante, migliorando la leggibilità e aggiungendo un tocco di raffinatezza 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 le dimensioni di due caratteri grazie all'unità di lunghezza relativa ch, che consente di scalare l'icona in modo proporzionale al testo del pulsante. Il colore dell'icona si basa su --_accent-color per un colore adattivo e all'interno del tema.

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

Ombra pulsante

Affinché le ombre si adattino correttamente alla luce e al buio, devono cambiare sia il colore che l'opacità. Le ombre del tema chiaro sono migliori quando sono tenui e colorate in base al colore della superficie che ricoprono. Le ombre del tema scuro devono essere più scure e più sature per poter 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 colori e intensità adattivi posso assemblare 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 3D, una 1px box-shadow 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 affiancati nel tema chiaro e in quello scuro.

Adattamenti del tema scuro

Il valore del pattern delle proprietà statiche -light e -dark diventa chiaro quando vengono impostate le proprietà del 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 la lettura è più semplice, ma i consumatori di questi pulsanti personalizzati possono utilizzare le proprietà di base con la certezza che si adatteranno in modo appropriato alle preferenze degli utenti.

Adattamenti per il movimento ridotto

Se il movimento è accettabile per questo utente in 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 pulsanti e gli input devono avere i caratteri impostati su inherit in modo che corrispondano a quelli del resto della pagina; in caso contrario, verranno formattati dal browser. Questo vale anche per letter-spacing. Se imposti line-height su 1.5, le dimensioni della letterbox vengono impostate in modo da lasciare un po' di spazio sopra e sotto il testo:

: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.

Pulsanti di stile

Regolazione del selettore

Il selettore input[type="file"] non è la parte del pulsante dell'input, 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 del cursore e del tocco

Per prima cosa, assegno al cursore lo stile pointer, che aiuta il pulsante a indicare agli utenti che utilizzano il mouse che è interattivo. Poi aggiungo touch-action: manipulation per fare in modo che i clic non debbano aspettare 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

A questo punto, personalizzo le dimensioni del carattere, lo sfondo, il testo e i colori del bordo 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 sono state applicate alcune tecniche fantastiche. Il text-shadow si adatta alla luce e al buio, creando un aspetto piacevole e delicato del testo del pulsante che si adagia perfettamente sullo sfondo. Per box-shadow, vengono assegnate tre ombre. La prima, --_shadow-2, è un'ombreggiatura regolare. La seconda ombra è un trucco per l'occhio che fa sembrare il pulsante leggermente smussato. L'ultima ombra è per l'evidenziazione al passaggio del mouse, inizialmente con una dimensione pari a 0, ma le verrà assegnata una dimensione in un secondo momento e verrà eseguita la transizione in modo che sembri crescere dal 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 dato al pulsante un layout flexbox, in particolare un layout inline-flex che si adatti ai suoi contenuti. Poi centro il testo e allineo verticalmente e orizzontalmente gli elementi secondari al centro. In questo modo, le icone e gli altri elementi dei pulsanti si allineeranno 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 gli elementi fratelli si tocchino e proprietà logiche per il padding, 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 sezione successiva è pensata principalmente per gli utenti che utilizzano dispositivi mobili. La prima proprietà, user-select, è per tutti gli utenti; impedisce l'evidenziazione del testo del pulsante. Questo è più evidente sui dispositivi touch quando un pulsante viene toccato e tenuto premuto e il sistema operativo evidenzia il testo del pulsante.

In genere, ho riscontrato che questa non è l'esperienza utente con i pulsanti nelle app integrate, quindi la disattivo impostando user-select su nessuno. I colori di evidenziazione (-webkit-tap-highlight-color) e i menu contestuali del sistema operativo (-webkit-touch-callout) sono altre funzionalità dei pulsanti molto incentrate sul web che non sono in linea con le aspettative generali degli utenti dei pulsanti, quindi le rimuovo.

: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 preme attivamente, regola le dimensioni dell'evidenziazione dell'ombra per dare un aspetto di messa a fuoco che sembra crescere dall'interno del pulsante:

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

Quando lo stato attivo è impostato, aumenta l'offset del contorno dello stato attivo dal pulsante, conferendogli anche un aspetto gradevole che sembra crescere dall'interno del pulsante:

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

Icone

Per la gestione delle icone, il selettore ha un selettore :where() aggiunto per gli elementi secondari SVG diretti o gli elementi con l'attributo personalizzato data-icon. La dimensione dell'icona viene impostata con la proprietà personalizzata utilizzando le proprietà logiche in linea e di blocco. Il colore del tratto è impostato, così come un drop-shadow che corrisponde a text-shadow. flex-shrink è impostato su 0, quindi l'icona non viene mai schiacciata. Infine, seleziono le icone con linee e assegno questi stili qui con fill: none e round estremità e giunzioni delle linee:

: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 di invio avessero un aspetto leggermente in evidenza e ho ottenuto questo risultato impostando il colore del testo dei pulsanti sul colore accento:

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

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

Personalizzare i pulsanti di ripristino

Volevo che i pulsanti di ripristino avessero dei segnali di avvertimento integrati per avvisare gli utenti del loro comportamento potenzialmente distruttivo. Ho anche scelto di dare uno stile al pulsante del tema chiaro con più dettagli 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 pensato anche che sarebbe bello se il colore del contorno della messa a fuoco corrispondesse al colore rosso. Il colore del testo passa da un rosso scuro a un rosso chiaro. Faccio in modo che il colore del contorno corrisponda a quello della parola chiave currentColor:

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

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

Personalizzare i pulsanti disattivati

È fin troppo comune che i pulsanti disattivati abbiano un contrasto cromatico scarso durante il tentativo di attenuare il pulsante disattivato in modo che appaia meno attivo. Ho testato ogni set di colori e mi sono assicurato che superassero il test, modificando il valore di luminosità HSL finché il punteggio non è stato superato 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 uno span e un pulsante. CSS è in grado di dare uno stile al contenitore di input, nonché al pulsante nidificato, ma non allo span. Il contenitore è impostato su max-inline-size, quindi non diventerà più grande del necessario, mentre inline-size: 100% si ridurrà e si adatterà ai contenitori più piccoli. Il colore di sfondo è impostato su un colore adattivo più scuro rispetto ad altre superfici, quindi appare dietro il pulsante di selezione dei file.

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

I pulsanti di selezione dei file e di tipo di input sono stati creati appositamente appearance: none per rimuovere gli stili forniti dal browser che non sono stati sovrascritti dagli altri stili dei pulsanti.

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

Infine, viene aggiunto un margine al inline-end del pulsante per allontanare il testo dello span dal pulsante, creando uno 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 speciali per il tema scuro

Ho dato ai pulsanti di azione principali uno sfondo più scuro per un testo con un contrasto maggiore, conferendo loro un aspetto leggermente più in evidenza.

@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.

Creazione varianti in corso…

Per divertimento e perché è pratico, ho scelto di mostrare come creare alcune varianti. Una variante è molto vivace, simile all'aspetto dei pulsanti principali. Un'altra variante è Large. L'ultima variante ha un'icona con riempimento sfumato.

Pulsante vivace

Per ottenere questo stile del pulsante, ho sovrascritto le proprietà di base direttamente con i colori blu. Sebbene questa operazione sia rapida e semplice, rimuove le proprietà adattive e l'aspetto è lo stesso sia nel tema chiaro che in quello scuro.

.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 modalità Chiaro e Scuro. È di un blu molto vivace, come di solito sono i pulsanti di azione principali.

Pulsante grande

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

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

Il pulsante grande viene visualizzato accanto al pulsante personalizzato ed è circa 150 volte più grande.

Pulsante icona

Questo effetto icona non ha nulla a che fare con gli stili dei nostri pulsanti, ma mostra come ottenerlo con poche proprietà CSS e come il pulsante gestisce le icone che non sono SVG incorporati.

[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 nei temi chiaro e scuro.

Conclusione

Ora che sai come ho fatto, come faresti tu?‽ 🙂

Diversifichiamo i nostri approcci e impariamo tutti i modi per creare contenuti sul web.

Crea una demo, inviami un tweet con i link e la aggiungerò alla sezione dei remix della community qui sotto.

Remix della community

Ancora nessun elemento da visualizzare.

Risorse