Uma visão geral fundamental de como criar componentes FAB adaptáveis a cores, responsivos e acessíveis.
Neste post, quero compartilhar minhas ideias sobre como criar componentes FAB adaptáveis a cores, responsivos e acessíveis. Teste a demonstração e veja a fonte.
Se preferir vídeo, confira uma versão desta postagem no YouTube:
Visão geral
Os FABs são mais comuns em dispositivos móveis do que em computadores, mas estão presentes nos dois cenários. Eles mantêm as ações principais em exibição, tornando-as convenientes e onipresentes. Esse estilo de experiência do usuário ficou famoso com o Material UI, e as sugestões de uso e posicionamento podem ser encontradas aqui.
Elementos e estilos
O HTML desses controles envolve um elemento de contêiner e um conjunto de um ou mais botões. O contêiner posiciona os FABs na janela de visualização e gerencia um espaço entre os botões. Os botões podem ser mini ou padrão, oferecendo uma boa variedade entre ações principais e secundárias.
Contêiner de FAB
Esse elemento pode ser um <div> comum, mas vamos ajudar nossos usuários com deficiência visual e adicionar alguns atributos úteis para explicar a finalidade e o conteúdo desse contêiner.
Marcação de FABs
Comece com uma classe .fabs para o CSS se conectar ao estilo e adicione role="group" e aria-label para que não seja apenas um contêiner genérico, mas sim nomeado e proposital.
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
Estilo dos FABs
Para que os FABs sejam convenientes, eles ficam na janela de visualização o tempo todo.
Esse é um ótimo caso de uso para a posição
fixed. Nessa posição da janela de visualização, escolhi usar inset-block e inset-inline para que a posição complemente o modo de documento do usuário, como da direita para a esquerda ou da esquerda para a direita. As propriedades personalizadas também são usadas para evitar repetições e garantir uma distância igual das bordas inferior e lateral da janela de visualização:
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
Em seguida, dou ao contêiner o display
flex e mudo a direção do layout para
column-reverse.
Isso empilha os filhos um em cima do outro (coluna) e também inverte a ordem visual deles. Isso faz com que o primeiro elemento focalizável seja o
elemento inferior em vez do superior, que seria onde o foco vai normalmente de acordo com
o documento HTML. Inverter a ordem visual une a experiência para usuários com visão e usuários de teclado. O estilo da ação principal como maior que os mini botões indica aos usuários com visão que é uma ação principal, e os usuários de teclado a focam como o primeiro item na origem.

.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
O alinhamento ao centro é processado com
place-items, e
gap adiciona espaço entre os botões
FAB colocados no contêiner.
Botões FAB
Agora vamos estilizar alguns botões para que pareçam estar flutuando sobre tudo.
FAB padrão
O primeiro botão a ser estilizado é o padrão. Essa será a base para todos os botões FAB. Mais tarde, vamos criar uma variante que tenha uma aparência alternativa, modificando o mínimo possível desses estilos básicos.
Marcação de FAB
O elemento <button> é a escolha certa. Vamos começar com isso como base porque ele oferece uma ótima experiência de usuário com mouse, toque e teclado. O aspecto mais
crucial dessa marcação é ocultar o ícone dos usuários de leitores de tela com
aria-hidden="true" e adicionar o texto do rótulo necessário à própria marcação <button>. Ao adicionar rótulos nesses casos, também gosto de incluir um title para que os usuários de mouse recebam informações sobre o que o ícone quer comunicar.
<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
Estilo do FAB
Primeiro, vamos transformar o botão em um botão redondo acolchoado com uma sombra forte, já que esses são os primeiros recursos definidores do botão:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
Agora vamos adicionar cor. Vamos usar uma estratégia que já usamos em desafios de GUI. Crie um conjunto de propriedades personalizadas com nomes claros que contenham estaticamente as cores claras e escuras. Em seguida, crie uma propriedade personalizada adaptável que será definida como as variáveis claras ou escuras, dependendo da preferência de cores do sistema do usuário:
.fab {
…
/* light button and button hover */
--_light-bg: var(--pink-6);
--_light-bg-hover: var(--pink-7);
/* dark button and button hover */
--_dark-bg: var(--pink-4);
--_dark-bg-hover: var(--pink-3);
/* adaptive variables set to light by default */
--_bg: var(--_light-bg);
/* static icon colors set to the adaptive foreground variable */
--_light-fg: white;
--_dark-fg: black;
--_fg: var(--_light-fg);
/* use the adaptive properties on some styles */
background: var(--_bg);
color: var(--_fg);
&:is(:active, :hover, :focus-visible) {
--_bg: var(--_light-bg-hover);
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg-hover);
}
}
/* if users prefers dark, set adaptive props to dark */
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg);
--_fg: var(--_dark-fg);
}
}
Em seguida, adicione alguns estilos para ajudar os ícones SVG a se encaixarem no espaço.
.fab {
…
& > svg {
inline-size: var(--_size);
block-size: var(--_size);
stroke-width: 3px;
}
}
Por fim, remova o destaque de toque do botão, já que adicionamos nosso próprio feedback visual para interação:
.fab {
-webkit-tap-highlight-color: transparent;
}
Mini FAB
O objetivo desta seção é criar uma variante para o botão FAB. Ao diminuir alguns FABs em relação à ação padrão, podemos promover a ação que o usuário realiza com mais frequência.
Marcação de mini FAB
O HTML é o mesmo de um FAB, mas adicionamos uma classe ".mini" para dar ao CSS um gancho na variante.
<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
Estilo de mini FAB
Graças ao uso de propriedades personalizadas, a única mudança necessária é um ajuste na variável --_size.
.fab.mini {
--_size: 1.25rem;
}

Acessibilidade
A parte mais importante para lembrar sobre acessibilidade com FABs é o posicionamento no fluxo do teclado da página. Esta demonstração só tem os FABs. Não há nada para competir em termos de ordem e fluxo do teclado, o que significa que ela não tem a oportunidade de demonstrar um fluxo de teclado significativo. Em um cenário em que há elementos concorrentes para o foco, sugiro pensar profundamente em qual parte desse fluxo um usuário deve entrar no fluxo do botão FAB.
Depois que o usuário foca no contêiner do FAB, já adicionamos
role="group" e aria-label="floating action buttons", que informam aos usuários de leitores de tela
sobre o conteúdo do que eles focaram. Estrategicamente, coloquei o FAB padrão primeiro para que os usuários encontrem a ação principal primeiro. Em seguida, uso flex-direction: column-reverse; para ordenar visualmente o botão principal na parte de baixo, perto dos dedos dos usuários para facilitar o acesso. Isso é uma boa vitória porque o botão padrão é visualmente proeminente e também o primeiro para usuários de teclado, oferecendo experiências muito semelhantes.
Por fim, não se esqueça de ocultar os ícones dos usuários de leitores de tela e fornecer um rótulo para o botão para que não seja um mistério. Isso já foi feito no HTML com aria-hidden="true" no <svg> e aria-label="Some action" nos <button>s.
Animação
Vários tipos de animação podem ser adicionados para melhorar a experiência do usuário. Como em
outros desafios de GUI, vamos configurar algumas propriedades personalizadas para manter a
intenção de uma experiência de movimento reduzido e uma experiência de movimento completo. Por padrão,
os estilos vão presumir que o usuário quer movimento reduzido. Em seguida, usando a
consulta de mídia prefers-reduced-motion, troque o valor da transição para movimento total.
Uma estratégia de movimento reduzido com propriedades personalizadas
Três propriedades personalizadas são criadas no seguinte CSS: --_motion-reduced, --_motion-ok e --_transition. As duas primeiras mantêm transições adequadas de acordo com a preferência do usuário, e a última variável --_transition será definida como --_motion-reduced ou --_motion-ok, respectivamente.
.fab {
/* box-shadow and background-color can safely be transitioned for reduced motion users */
--_motion-reduced:
box-shadow .2s var(--ease-3),
background-color .3s var(--ease-3);
/* add transform and outline-offset for users ok with motion */
--_motion-ok:
var(--_motion-reduced),
transform .2s var(--ease-3),
outline-offset 145ms var(--ease-2);
/* default the transition styles to reduced motion */
--_transition: var(--_motion-reduced);
/* set the transition to our adaptive transition custom property*/
transition: var(--_transition);
/* if motion is ok, update the adaptive prop to the respective transition prop */
@media (prefers-reduced-motion: no-preference) {
--_transition: var(--_motion-ok);
}
}
Com o acima em vigor, as mudanças em box-shadow, background-color,
transform e outline-offset podem ser transferidas, ao usuário um feedback
agradável da interface de que a interação foi recebida.
Em seguida, adicione um pouco mais de estilo ao estado :active ajustando
translateYum pouco. Isso dá ao botão um efeito de pressionado:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
Por fim, faça a transição de todas as mudanças nos ícones SVG nos botões:
.fab {
…
&[data-icon="plus"]:hover > svg {
transform: rotateZ(.25turn);
}
& > svg {
@media (prefers-reduced-motion: no-preference) {
will-change: transform;
transition: transform .5s var(--ease-squish-3);
}
}
}
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, me envie um tweet com o link, e eu vou adicionar à seção de remixes da comunidade abaixo.
Remixes da comunidade
Ainda não há nada aqui.
Recursos
- Código-fonte no GitHub