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
Se preferisci i video, ecco una versione di questo post su YouTube:
Panoramica
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.
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 {}
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) {
…
}
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>
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
: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); }

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);
}

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);
}

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);
}

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

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);
}

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

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);
}

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

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);
}

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);
}

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);
}
}

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%);
}

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

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));
}
![]()
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
- Codice sorgente su GitHub