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> è creato per l'interazione dell'utente. L'evento click viene attivato tramite tastiera, mouse, tocco, voce e altro ancora, con regole intelligenti sulle tempistiche. 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, ognuno dei quali è mostrato nell'incorporamento precedente del codepen. 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 applicare 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

Aumento

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 correttamente per il pulsante predefinito, che si comporta come un pulsante Invia. 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 faticosa. 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.

Passa il mouse e imposta lo stato attivo insieme

Mi piace raggruppare :hover e :focus con l'pseudo selettore funzionale :is(). In questo modo le mie interfacce prendono sempre in considerazione gli stili della 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 di tastiere e tecnologie per la disabilità. A questo scopo, anima il contorno allontanandolo dal pulsante di 5 px, 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;
}

Garanzia di trasmissione del contrasto di colore

Esistono almeno quattro diverse combinazioni di colori, per il colore chiaro e scuro, che devono tenere conto del contrasto di colore: pulsante, pulsante di invio, pulsante di ripristino e pulsante disattivato. VisBug viene utilizzato qui per esaminare e mostrare tutti i punteggi contemporaneamente:

Le icone vengono nascoste a persone 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é 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 adattabili del pulsante. Con queste proprietà personalizzate posso iniziare a selezionare gli elementi e personalizzarne l'aspetto.

Una strategia adattiva per le proprietà personalizzate

La strategia delle proprietà personalizzate utilizzata in questa sfida della GUI è molto simile a quella utilizzata nella creazione di una combinazione di colori. Per un sistema di colori chiari e scuri adattivi, viene definita e denominata una proprietà personalizzata per ogni tema. Successivamente, viene utilizzata una singola proprietà personalizzata che contiene 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 il fatto che i temi chiaro e scuro siano chiari e dichiarativi. La dipendenza indiretta 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.

Prepararsi alla 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 usato 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 il bianco o il nero, ma le versioni con scurimenti o schiariture di --_accent che utilizzano hsl() e 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()schema, tranne per i pulsanti del tema chiaro, che sono impostati su bianco in modo che la loro superficie li faccia sembrare 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 ben definito

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 intorno al testo nel pulsante viene eseguita utilizzando l'unità ch, una lunghezza relativa alla dimensione 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 sul pulsante

Queste proprietà stabiliscono una proprietà di dimensione per la transizione all'interazione e il colore di evidenziazione segue il sistema di colori adattivi. Parleremo di come questi interagiscono più avanti in questo post, ma alla fine verranno 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 viene posizionato sopra il pulsante, migliorando la leggibilità e aggiungendo un buon livello di perfezionamento della 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 la lettura è positiva, ma anche i consumatori di questi pulsanti personalizzati possono utilizzare gli oggetti di scena semplici e 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

Per i pulsanti e gli input, i caratteri devono essere impostati su inherit in modo da corrispondere al resto dei caratteri della pagina, altrimenti verranno impostati dal browser. Questo vale anche 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, 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, applico lo stile pointer al cursore, in modo che il pulsante indichi agli utenti che utilizzano 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 vengono applicate 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 riguarda l'evidenziazione al passaggio del mouse, inizialmente di dimensione pari a 0, ma verrà definita in un secondo momento e sarà sottoposta a transizione in modo che sembri crescere a partire 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 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 del pulsante 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 la spaziatura dei pulsanti, ho utilizzato gap per impedire ai fratelli di toccare e proprietà logiche per la spaziatura interna, quindi la spaziatura dei pulsanti funziona 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 prossima sezione è dedicata principalmente agli utenti touch sui dispositivi mobili. 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 notato che non si tratta dell'esperienza utente con i pulsanti nelle app integrate, quindi lo 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 dall'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 lo spazio tra il contorno attivo e il 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. È impostato il colore del tratto e una drop-shadow in modo che corrisponda a 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.

Personalizzazione dei pulsanti di invio

Volevo che i pulsanti avessero un aspetto leggermente promosso e l'ho fatto impostando il colore del testo dei pulsanti come colore di contrasto:

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

Volevo che i pulsanti di ripristino avessero alcuni segnali di avviso integrati per avvisare gli utenti del loro comportamento potenzialmente distruttivo. 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 in corrispondenza 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.

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 set di colori e mi sono assicurato che venissero superati, modificando il valore di leggerezza HSL fino a quando il punteggio è passato 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 immissione 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 relative al tema scuro

Ho dato ai pulsanti di azione principali uno sfondo più scuro per un testo con un maggiore contrasto, dando 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 dato che è 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 questa operazione sia stata rapida 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. È blu molto intenso, come in genere i pulsanti di azione principali.

Pulsante grande

Questo stile di pulsante viene ottenuto modificando la proprietà personalizzata --_size. La spaziatura interna e altri elementi dello spazio sono relativi a questa dimensione e vengono scalati 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 mostrato con temi chiari e scuri.

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 niente da visualizzare qui.

Risorse