Uma visão geral básica de como criar componentes <button>
responsivos, adaptáveis a cores e acessíveis.
Neste post, quero compartilhar minhas ideias sobre como criar um elemento <button>
adaptável a cores, responsivo e acessível.
Teste a demonstração e confira a
fonte.
Se preferir vídeos, confira a versão desta postagem no YouTube:
Visão geral
O elemento
<button>
é criado para a interação do usuário. O evento click
é acionado pelo teclado,
mouse, toque, voz e muito mais, com regras inteligentes sobre o
cronômetro. Ele também vem
com alguns estilos padrão em cada navegador, para que você possa usá-los diretamente sem
personalização. Use color-scheme
para ativar
os botões claros e escuros fornecidos pelo navegador.
Há também diferentes tipos de
botões,
cada um mostrado na incorporação do Codepen anterior. Um <button>
sem um tipo será
adaptado para estar em um <form>
, mudando para o tipo de envio.
<!-- 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">
No Desafio de GUI deste mês, cada botão vai receber estilos para ajudar a diferenciar visualmente a intenção dele. Os botões de redefinição têm cores de aviso, já que são destrutivos, e os botões de envio têm texto de destaque em azul para parecerem um pouco mais destacados do que os botões normais.
Os botões também têm pseudoclasses
para que o CSS use para estilizar. Essas classes fornecem ganchos CSS para personalizar a
sensação do botão: :hover
para quando um mouse está sobre o botão,
:active
para quando um mouse
ou teclado está pressionando e
:focus
ou
:focus-visible
para ajudar no estilo de tecnologia adaptativa.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Marcação
Além dos tipos de botão fornecidos pela especificação HTML, adicionei um
botão com um ícone e um botão com uma classe personalizada 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">
Em seguida, para testes, cada botão é colocado dentro de um formulário. Dessa forma, posso garantir que os estilos sejam atualizados adequadamente para o botão padrão, que se comporta como um botão de envio. Também mudei a estratégia de ícones, de SVG inline para SVG mascarado, para garantir que ambos funcionem igualmente bem.
<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 matriz de combinações está bastante confusa neste momento. Entre os tipos de botões, as pseudoclasses e o uso ou não de um formulário, há mais de 20 combinações de botões. É bom que o CSS possa nos ajudar a articular cada um deles com clareza.
Acessibilidade
Os elementos de botão são naturalmente acessíveis, mas há algumas melhorias comuns.
Passar o cursor e focar juntos
Gosto de agrupar :hover
e :focus
com o pseudoseletor funcional
:is()
. Isso ajuda a garantir que minhas interfaces sempre considerem os estilos de teclado
e tecnologia adaptativa.
button:is(:hover, :focus) {
…
}
Anel de foco interativo
Gosto de animar o anel de foco para usuários de teclado e tecnologias adaptativas. Para fazer isso, animação o contorno para longe do botão em 5 px, mas apenas quando o botão não está ativo. Isso cria um efeito que faz com que o anel de foco encolha de volta para o tamanho do botão quando pressionado.
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Como garantir o contraste de cor aprovado
Há pelo menos quatro combinações de cores diferentes entre claro e escuro que precisam considerar o contraste de cores: botão, botão de envio, botão de redefinição e botão desativado. O VisBug é usado aqui para inspecionar e mostrar todas as pontuações de uma vez:
Como ocultar ícones de pessoas que não podem ver
Ao criar um botão de ícone, o ícone precisa oferecer suporte visual ao texto do botão. Isso também significa que o ícone não é valioso para alguém com perda de visão. Felizmente, o navegador oferece uma maneira de ocultar itens da tecnologia de leitor de tela para que pessoas com perda de visão não sejam incomodadas com imagens decorativas de botões:
<button>
<svg … aria-hidden="true">...</svg>
Icon Button
</button>
Estilos
Nesta próxima seção, primeiro estabeleço um sistema de propriedade personalizado para gerenciar os estilos adaptáveis do botão. Com essas propriedades personalizadas, posso começar a selecionar elementos e personalizar a aparência deles.
Uma estratégia de propriedade personalizada adaptativa
A estratégia de propriedade personalizada usada neste Desafio de GUI é muito semelhante à usada na criação de um esquema de cores. Para um sistema de cores claras e escuras adaptável, uma propriedade personalizada para cada tema é definida e nomeada de acordo. Em seguida, uma única propriedade personalizada é usada para armazenar o valor atual do tema e é atribuída a uma propriedade CSS. Mais tarde, a única propriedade personalizada pode ser atualizada para um valor diferente e, em seguida, o estilo do botão.
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);
}
}
O que eu gosto é que os temas claros e escuros são declarativos e claros. A
indireção e a abstração são transferidas para a propriedade personalizada --_bg
,
que agora é a única propriedade "reativa". --_bg-light
e --_bg-dark
são
estáticos. Também fica claro que o tema claro é o padrão e
o escuro é aplicado apenas condicionalmente.
Como preparar a consistência do design
O seletor compartilhado
O seletor a seguir é usado para segmentar todos os tipos de botões e pode ser
um pouco confuso no início. :where()
é
usado para que a personalização do botão não exija especificidade. Os botões geralmente são
adaptados para cenários alternativos, e o seletor :where()
garante que a tarefa
seja fácil. Dentro de :where()
, cada tipo de botão é selecionado, incluindo o
::file-selector-button
, que não pode ser
usado
dentro de :is()
ou :where()
.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
…
}
Todas as propriedades personalizadas vão ser definidas dentro desse seletor. É hora de analisar todas as propriedades personalizadas. Há várias propriedades personalizadas usadas neste botão. Vou descrever cada grupo conforme avançamos e compartilhar os contextos de movimento escuro e reduzido no final da seção.
Cor de destaque do botão
Botões de envio e ícones são ótimos para dar um toque de cor:
--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);
Cor do texto do botão
As cores do texto do botão não são brancas ou pretas, são versões mais claras ou mais escuras
de --_accent
usando
hsl()
e
respeitando a matiz 210
:
--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);
Cor do plano de fundo do botão
Os planos de fundo dos botões seguem o mesmo padrão hsl()
, exceto os botões do tema claro,
que são definidos como branco para que a superfície os faça parecer próximos ao
usuário ou na frente de outras superfícies:
--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);
Fundo do botão
Essa cor de plano de fundo serve para fazer com que uma superfície apareça atrás de outras, útil para o plano de fundo da entrada de arquivo:
--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);
Padding do botão
O espaçamento ao redor do texto no botão é feito usando a
unidade ch
, uma extensão relativa ao tamanho da fonte. Isso se torna crítico quando botões grandes
podem simplesmente aumentar o font-size
e o botão é dimensionado
proporcionalmente:
--_padding-inline: 1.75ch;
--_padding-block: .75ch;
Borda do botão
O raio da borda do botão é armazenado em uma propriedade personalizada para que a entrada de arquivo possa combinar com os outros botões. As cores da borda seguem o sistema de cores adaptativas estabelecido:
--_border-radius: .5ch;
--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);
Efeito de destaque ao passar o cursor sobre o botão
Essas propriedades estabelecem uma propriedade de tamanho para a transição na interação, e
a cor de destaque segue o sistema de cores adaptável. Vamos abordar como eles
interagem mais adiante nesta postagem, mas, em última análise, eles são usados para um efeito
box-shadow
:
--_highlight-size: 0;
--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);
Sombra do texto do botão
Cada botão tem um estilo de sombra de texto sutil. Isso ajuda o texto a ficar na parte de cima do botão, melhorando a legibilidade e adicionando uma camada de apresentação.
--_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);
Ícone de botão
Os ícones têm o tamanho de dois caracteres, graças à unidade de comprimento relativo ch
,
que ajuda a escalar o ícone proporcionalmente ao texto do botão. A
cor do ícone se baseia no --_accent-color
para uma cor adaptativa e dentro do
tema.
--_icon-size: 2ch;
--_icon-color: var(--_accent);
Sombra do botão
Para que as sombras se adaptem adequadamente à luz e à escuridão, elas precisam mudar a cor e a opacidade. As sombras do tema claro são melhores quando são sutis e tingidas para a cor da superfície que elas sobrepõem. As sombras do tema escuro precisam ser mais escuras e mais saturadas para sobrepor cores de superfície mais escuras.
--_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);
Com cores e intensidades adaptativas, posso criar duas profundidades de sombras:
--_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%));
Além disso, para dar aos botões uma aparência um pouco em 3D, uma caixa de sombra 1px
cria a ilusão:
--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);
Transições de botões
Seguindo o padrão de cores adaptáveis, criei duas propriedades estáticas para armazenar as opções do sistema de design:
--_transition-motion-reduce: ;
--_transition-motion-ok:
box-shadow 145ms ease,
outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);
Todas as propriedades juntas no seletor
: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); }
Adaptações do tema escuro
O valor do padrão de propriedades estáticas -light
e -dark
fica claro quando
as propriedades do tema escuro são definidas:
@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);
}
}
Além de ser mais fácil de ler, os consumidores desses botões personalizados podem usar as propriedades simples com a confiança de que elas serão adaptadas adequadamente às preferências do usuário.
Adaptações de movimento reduzidas
Se o movimento estiver OK com esse usuário visitante, atribua --_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);
}
}
Alguns estilos compartilhados
Os botões e as entradas precisam ter as fontes definidas como inherit
para corresponder ao
resto das fontes da página. Caso contrário, elas serão estilizadas pelo navegador. Isso também
se aplica a letter-spacing
. A definição de line-height
como 1.5
define o tamanho da caixa de
letras para dar ao texto algum espaço acima e abaixo:
: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);
}
Estilizar botões
Ajuste do seletor
O seletor input[type="file"]
não é a parte do botão da entrada, o
pseudoelemento ::file-selector-button
é. Portanto, removi input[type="file"]
da lista:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
}
Ajustes de cursor e toque
Primeiro, estilizo o cursor com o estilo pointer
, que ajuda o botão a indicar
aos usuários do mouse que ele é interativo. Em seguida, adiciono touch-action: manipulation
para
que os cliques não precisem esperar e observar um possível clique duplo, deixando os
botões mais rápidos:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
cursor: pointer;
touch-action: manipulation;
}
Cores e bordas
Em seguida, personalizei o tamanho da fonte, o plano de fundo, o texto e as cores da borda usando algumas das propriedades personalizadas adaptáveis estabelecidas anteriormente:
: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);
}
Sombras
Os botões têm algumas técnicas excelentes aplicadas. O
text-shadow
se
adapta à luz e à escuridão, criando uma aparência sutil e agradável do texto
do botão sobre o plano de fundo. Para o
box-shadow
,
três sombras são atribuídas. A primeira, --_shadow-2
, é uma sombra de caixa normal.
A segunda sombra é um truque para os olhos que faz com que o botão pareça
um pouco chanfrado. A última sombra é para o destaque do cursor, inicialmente
com um tamanho de 0, mas vai receber um tamanho mais tarde e fazer a transição para parecer
que está crescendo do botão.
: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
Eu dei ao botão um layout de flexbox,
especificamente um layout inline-flex
que se encaixa no conteúdo. Em seguida, centralizo
o texto e alinhei as filhas vertical e horizontalmente ao
centro. Isso vai ajudar os ícones e outros
elementos do botão a se alinhar corretamente.
: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;
}
Espaçamento
Para o espaçamento de botões, usei
gap
para evitar que irmãos
se toquem e propriedades
lógicas para padding, para que o espaçamento
de botões funcione para todos os layouts de texto.
: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);
}
UX de toque e mouse
Esta próxima seção é principalmente para usuários de dispositivos móveis com tela touch. A primeira
propriedade,
user-select
,
é para todos os usuários. Ela impede que o texto destaque o texto do botão. Isso é mais
perceptível em dispositivos touchscreen quando um botão é pressionado e mantido e o sistema
operacional destaca o texto do botão.
Geralmente, essa não é a experiência do usuário com botões em apps
integrados. Por isso, desativei essa opção definindo user-select
como "none". Toque em cores de destaque
(-webkit-tap-highlight-color
)
e menus de contexto do sistema operacional
(-webkit-touch-callout
)
são outros recursos de botão muito focados na Web que não estão alinhados com as expectativas
gerais dos usuários, então também os removi.
: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;
}
Transições
A variável adaptativa --_transition
é atribuída à propriedade
transition:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
transition: var(--_transition);
}
Ao passar o cursor, enquanto o usuário não está pressionando ativamente, ajuste o tamanho do destaque de sombra para dar uma aparência de foco que parece crescer dentro do botão:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
):where(:not(:active):hover) {
--_highlight-size: .5rem;
}
Ao receber o foco, aumente o deslocamento do contorno do botão, a ele uma aparência de foco que parece crescer dentro do botão:
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Ícones
Para processar ícones, o seletor tem um seletor :where()
adicionado para filhos SVG
diretos ou elementos com o atributo personalizado data-icon
. O tamanho do ícone é definido
com a propriedade personalizada usando propriedades lógicas inline e de bloco. A cor do traço
é definida, assim como um
drop-shadow
para corresponder ao text-shadow
. flex-shrink
é definido como 0
para que o ícone nunca
seja reduzido. Por fim, seleciono ícones com linhas e atribuo esses estilos aqui com
fill: none
e round
, com as letras maiúsculas e as junções de linhas:
: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;
}
Personalizar botões de envio
Queria que os botões de envio tivessem uma aparência um pouco mais destacada. Para isso, fiz a cor do texto dos botões ser a cor de destaque:
:where(
[type="submit"],
form button:not([type],[disabled])
) {
--_text: var(--_accent);
}
Personalizar botões de redefinição
Queria que os botões de redefinição tivessem alguns sinais de aviso integrados para alertar os usuários sobre o comportamento potencialmente destrutivo. Também escolhi estilizar o botão do tema claro com mais detalhes em vermelho do que o tema escuro. A personalização é feita mudando a cor de fundo clara ou escura apropriada, e o botão vai atualizar o estilo:
: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%);
}
Também achei que seria bom se a cor do contorno de foco correspondesse ao destaque
vermelho. A cor do texto adapta um vermelho escuro para um vermelho claro. Eu faço com que a cor do contorno
corresponda a isso com a palavra-chave
currentColor
:
:where([type="reset"]):focus-visible {
outline-color: currentColor;
}
Personalizar botões desativados
É muito comum que botões desativados tenham um contraste de cor ruim durante a tentativa de atenuar o botão desativado para que ele pareça menos ativo. Testei cada conjunto de cores e me certifiquei de que eles foram aprovados, ajustando o valor de luminosidade do HSL até que a pontuação fosse aprovada no DevTools ou no 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);
}
Personalizar botões de entrada de arquivo
O botão de entrada de arquivo é um contêiner para um span e um botão. O CSS pode
dar um pouco de estilo ao contêiner de entrada, bem como ao botão aninhado, mas não
ao span. O contêiner recebe max-inline-size
para não crescer mais do que
precisa, enquanto inline-size: 100%
permite que ele encolha e se encaixe
em contêineres menores. A cor de fundo é definida como uma cor adaptativa
mais escura do que outras superfícies, para que ela fique atrás do botão do seletor de arquivos.
:where(input[type="file"]) {
inline-size: 100%;
max-inline-size: max-content;
background-color: var(--_input-well);
}
O botão de seleção de arquivo e os botões de tipo de entrada são especificamente
appearance: none
para remover todos os estilos fornecidos pelo navegador que não foram
substituídos pelos outros estilos de botão.
:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
appearance: none;
}
Por fim, a margem é adicionada ao inline-end
do botão para afastar o texto do span
do botão, criando algum espaço.
:where(input[type="file"])::file-selector-button {
margin-inline-end: var(--_padding-inline);
}
Exceções especiais do tema escuro
Dei aos botões de ação principais um plano de fundo mais escuro para aumentar o contraste do texto, a eles uma aparência um pouco mais destacada.
@media (prefers-color-scheme: dark) {
:where(
[type="submit"],
[type="reset"],
[disabled],
form button:not([type="button"])
) {
--_bg: var(--_input-well);
}
}
Criar variantes
Para fins de diversão e porque é prático, escolhi mostrar como criar algumas variantes. Uma variante é muito vibrante, semelhante à aparência dos botões principais. Outra variante é grande. A última variante tem um ícone preenchido com gradiente.
Botão vibrante
Para conseguir esse estilo de botão, substituí as propriedades básicas diretamente por cores azuis. Embora isso tenha sido rápido e fácil, ele remove os elementos adaptáveis e tem a mesma aparência nos temas claro e escuro.
.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%);
}
Botão grande
Esse estilo de botão é alcançado modificando a propriedade personalizada --_size
.
O padding e outros elementos de espaço são relativos a esse tamanho, dimensionando-se
proporcionalmente com o novo tamanho.
.btn-large {
--_size: 1.5rem;
}
Botão de ícone
Esse efeito de ícone não tem nada a ver com nossos estilos de botão, mas mostra como fazer isso com apenas algumas propriedades do CSS e como o botão processa ícones que não são SVGs inline.
[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));
}
Conclusão
Agora que você sabe como eu fiz, como você faria? 🙂
Vamos diversificar nossas abordagens e aprender todas as maneiras de criar na Web.
Crie uma demonstração, envie links para mim e vou adicionar à seção de remixes da comunidade abaixo.
Remixes da comunidade
Ainda não há nada aqui.
Recursos
- Código-fonte no GitHub