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 la mia opinione su come creare un elemento <button> adattabile al colore, adattabile e accessibile. Prova la demo e visualizza la fonte

Nei temi chiaro e scuro, i pulsanti possono essere attivati tramite tastiera e mouse.

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

Panoramica

Supporto dei browser

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

Origine

L'elemento <button> è progettato per l'interazione con l'utente. L'evento click si attiva da tastiera, mouse, tocco, comandi vocali e altro ancora, con regole intelligenti relative ai relativi tempi. Inoltre, in ogni browser sono disponibili alcuni stili predefiniti, che puoi utilizzare 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'embed di Codepen precedente. Un <button> senza un tipo si adatterà all'inserimento in un <form>, cambiando 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">

Nel contest della GUI di questo mese, ogni pulsante avrà stili che aiuteranno a differenziarne visivamente lo scopo. I pulsanti di reimpostazione saranno di colore di avviso perché sono distruttivi, mentre i pulsanti di invio avranno un testo di colore blu per essere leggermente più in evidenza rispetto ai pulsanti normali.

Anteprima dell&#39;insieme finale di tutti i tipi di pulsanti, mostrati in un modulo e non in un modulo, con interessanti aggiunte per pulsanti con icone e pulsanti personalizzati.
Anteprima dell'insieme finale di tutti i tipi di pulsanti, mostrati in un modulo e non in un modulo, con ottime aggiunte per pulsanti con icone e pulsanti personalizzati

I pulsanti hanno anche pseudo classi che il CSS può utilizzare per gli stili. Queste classi forniscono hook CSS per personalizzare il pulsante: :hover per quando il mouse passa sopra il pulsante, :active per quando si preme il mouse o la tastiera e :focus o :focus-visible per l'assistenza nello 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 nel tema scuro.
Anteprima dell'insieme 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">

Poi, 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 di icone, passando da SVG in linea a SVG mascherato, per assicurarmi che entrambe funzionino allo stesso modo.

<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 scoraggiante. Tra tipi di pulsanti, pseudoclassi e presenza o meno in un modulo, esistono più di 20 combinazioni di pulsanti. È un bene che il CSS possa aiutarci a esprimerli chiaramente.

Accessibilità

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

Passare il mouse sopra e attivare lo stato attivo contemporaneamente

Mi piace raggruppare :hover e :focus con l'pseudo selettore funzionale :is(). In questo modo, le mie interfacce prendono sempre in considerazione gli stili di tastiera e delle tecnologie per la disabilità.

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 che utilizzano tastiera e tecnologie per la disabilità. Lo scopo viene raggiunto animando il contorno allontanandolo dal pulsante di 5 pixel, ma solo quando il pulsante non è attivo. In questo modo viene creato un effetto che fa sì che l'anello di messa a fuoco si rimpicciolisca alle dimensioni del pulsante quando viene premuto.

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

Garantire il superamento del contrasto di colore

Esistono almeno quattro diverse combinazioni di colori tra chiaro e scuro che devono essere prese in considerazione per il contrasto di colore: pulsante, pulsante di invio, pulsante di reimpostazione e pulsante disattivato. VisBug viene utilizzato qui per esaminare e mostrare tutti i punteggi contemporaneamente:

Nascondere le icone agli utenti che non possono vederle

Quando crei un pulsante con icona, l'icona deve fornire supporto visivo al testo del pulsante. Ciò significa anche che l'icona non è utile per chi ha perso la vista. Fortunatamente, il browser offre un modo per nascondere gli elementi alla tecnologia degli screen reader, in modo che le persone con problemi di vista non vengano disturbate dalle immagini decorative dei pulsanti:

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

Stili

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

Una strategia di proprietà personalizzata adattiva

La strategia di proprietà personalizzate utilizzata in questa sfida della GUI è molto simile a quella impiegata per creare una combinazione di colori. Per un sistema di colori chiari e scuri adattivi, viene definita e denominata una proprietà personalizzata per ogni tema. Poi viene utilizzata una singola proprietà personalizzata 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, quindi 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);
  }
}

Mi piace che i temi chiaro e scuro siano dichiarativi e chiari. La mediazione e l'astrazione vengono trasferite alla proprietà personalizzata --_bg, che ora è l'unica proprietà "reattiva"; --_bg-light e --_bg-dark sono statici. È inoltre chiaro che il tema chiaro è quello predefinito e quello scuro viene applicato solo in modo condizionale.

Preparazione per la coerenza del design

Il selettore condiviso

Il seguente selettore viene utilizzato per scegliere come target tutti i vari tipi di pulsanti e può sembrare un po' complicato all'inizio. Viene utilizzato :where(), pertanto la personalizzazione del pulsante non richiede alcuna specificità. I pulsanti sono spesso adattati per scenari alternativi e il selettore :where() garantisce che l'attività sia facile. 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 {
  
}

Tutte le proprietà personalizzate avranno come ambito questo selettore. È ora 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 scarsa illuminazione e movimento ridotto alla fine della sezione.

Colore di sfondo del pulsante

I pulsanti di invio e le icone sono un ottimo posto per aggiungere 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, ma sono versioni scurite o schiarite 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 hsl()pattern, tranne che per i 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 del riquadro del pulsante

Questo colore di sfondo serve a mostrare una superficie dietro altre, 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 dei pulsanti

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

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

Bordo del pulsante

Il raggio del bordo del pulsante viene memorizzato in una proprietà personalizzata in modo che l'input del file possa essere associato agli altri pulsanti. I colori dei bordi rispettano il sistema di colori adattivi stabilito:

--_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 del pulsante

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

Ombreggiatura testo pulsante

Ogni pulsante ha uno stile di ombra del testo delicato. In questo modo, il testo si posiziona sopra il pulsante, migliorandone 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 ridimensionare l'icona in proporzione al testo del pulsante. Il colore dell'icona si basa su --_accent-color per un colore adatto al tema e adattivo.

--_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 sia l'opacità. Le ombre del tema chiaro sono ideali se sono sottili e tinte in base al colore della superficie su cui vengono sovrapposte. Le ombre del tema scuro devono essere più scure e più sature in modo da poter sovrapporre i colori di 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, un'ombra interna 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 adattabili, creo due proprietà statiche per contenere le opzioni del sistema di design:

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

Tutte le proprietà 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 nei temi chiaro e scuro.

Adattamenti al tema scuro

Il valore del pattern degli elementi statici -light e -dark diventa chiaro quando vengono impostati gli elementi 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 è facile da leggere, ma gli utenti di questi pulsanti personalizzati possono utilizzare gli elementi di base con la certezza che si adatteranno in modo appropriato alle preferenze degli utenti.

Adattamenti con movimento ridotto

Se il movimento è accettabile per questo utente che visita il sito, 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 ai caratteri del resto della pagina. In caso contrario, verranno formattati dal browser. Lo stesso vale per letter-spacing. Se imposti line-height su 1.5, la dimensione della cassetta delle lettere viene impostata 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.

Aggiungere stili ai pulsanti

Regolazione del selettore

Il selettore input[type="file"] non è la parte del pulsante dell'input, ma lo è l'elemento pseudo ::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, applico lo stile pointer al cursore, in modo che il pulsante indichi agli utenti che usano il mouse che è interattivo. Poi aggiungo touch-action: manipulation per fare in modo che i clic non 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

A questo punto personalizzo le dimensioni dei caratteri, lo sfondo, il testo e i colori dei bordi utilizzando alcune delle proprietà personalizzate adattabili 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 ottime tecniche. Il pulsante text-shadow si adatta a temi chiari e scuri, creando un'estetica piacevole e discreta del testo del pulsante che si inserisce perfettamente sullo sfondo. Per box-shadow vengono assegnate tre ombre. La prima, --_shadow-2, è un'ombra riquadro normale. La seconda ombra è un trucco visivo che fa sembrare il pulsante leggermente smussato verso l'alto. L'ultima ombra è per l'evidenziazione al passaggio del mouse, inizialmente con una dimensione pari a 0, ma in seguito verrà assegnata una dimensione e verrà applicata una 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 assegnato al pulsante un layout flexbox, in particolare un layout inline-flex adatto 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 saranno 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 lo spazio tra i pulsanti, ho utilizzato gap per impedire il contatto tra elementi fratelli e le proprietà logiche per i margini, in modo che lo spazio tra i 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.

UX tocco e mouse

La sezione successiva è rivolta principalmente agli utenti che utilizzano dispositivi mobili con tocco. La prima proprietà, user-select, è per tutti gli utenti e impedisce l'evidenziazione del testo del pulsante. Questo è principalmente visibile 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 dei pulsanti (-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 degli utenti in merito ai pulsanti in generale, quindi li rimuoverò.

: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 --_transition adattiva viene 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);
}

Quando l'utente passa il mouse sopra il pulsante, senza premerlo, regola le dimensioni dell'evidenziazione dell'ombra per dare un'estetica accattivante allo stato attivo che sembra crescere all'interno del pulsante:

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

Quando il pulsante è attivo, aumenta l'offset del contorno attivo dal pulsante, dandogli anche un aspetto piacevole che sembra crescere dall'interno del pulsante:

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

Icone

Per gestire le icone, il selettore ha un selettore :where() aggiunto per gli elementi figli SVG diretti o gli elementi con l'attributo personalizzato data-icon. Le dimensioni dell'icona vengono impostate con la proprietà personalizzata utilizzando le proprietà logiche in linea e a blocchi. Il colore del tratto è impostato, nonché un drop-shadow in modo che corrisponda al text-shadow. flex-shrink è impostato su 0, quindi l'icona non viene mai schiacciata. Infine, selezioni le icone con linee e associo questi stili con i tratti iniziali e finali delle linee 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.

Personalizzare i 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 come colore di 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 reimpostazione

Volevo che i pulsanti di reimpostazione avessero alcuni segnali di avviso integrati per avvisare gli utenti del loro comportamento potenzialmente dannoso. Ho anche scelto di applicare uno stile al pulsante del 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 del contorno dell'elemento in primo piano fosse abbinato all'accento rosso. Il colore del testo passa da un rosso scuro a un rosso chiaro. Faccio in modo che il colore del contorno sia corrispondente alla 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

È molto comune che i pulsanti disattivati abbiano un cattivo contrasto di colore durante il tentativo di attenuare il pulsante disattivato in modo che appaia meno attivo. Ho testato ogni insieme di colori e mi sono assicurato che tutti 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 inserimento dei file

Il pulsante di inserimento del file è un contenitore per uno span e un pulsante. CSS è in grado di impostare un po' di stile al contenitore dell'input, nonché al pulsante nidificato, ma non allo span. Al contenitore viene assegnato max-inline-size in modo che non aumenti di dimensioni più del necessario, mentre inline-size: 100% si ridurrà per adattarsi a contenitori più piccoli. Il colore di sfondo è impostato su un colore adattivo più scuro rispetto ad altre superfici, quindi è visibile 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 di selezione del file e i pulsanti di tipo di input sono specificamente indicatiappearance: none per rimuovere gli stili forniti dal browser che non sono stati sostituiti 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 spazio 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 maggiore contrasto, 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 di varianti

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

Pulsante vivace

Per ottenere questo stile di pulsante, ho sovrascritto le proprietà di base direttamente con colori blu. Sebbene sia stato un processo rapido e semplice, rimuove gli elementi adattabili e ha lo stesso aspetto sia con il tema chiaro sia con 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 visualizzato in modalità chiara e scura. È di un blu molto vivace, come tendono ad essere i pulsanti di azione principali.

Pulsante grande

Questo stile di pulsante viene ottenuto modificando la proprietà personalizzata --_size. I margini e altri elementi dello spazio sono relativi a questa dimensione e vengono ridimensionati proporzionalmente in base 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 i nostri stili di pulsanti, ma mostra come ottenerlo con poche proprietà CSS e quanto bene il pulsante gestisce le icone che non sono SVG in linea.

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

Conclusione

Ora che sai come ho fatto, come faresti? 🙂

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

Crea una demo, twittami i link e io la aggiungerò alla sezione dei remix della community di seguito.

Remix della community

Ancora nessun elemento da visualizzare.

Risorse