Uma visão geral básica de como criar componentes de FAB adaptáveis, responsivos e acessíveis a cores.
Nesta postagem, quero compartilhar minhas ideias sobre como criar componentes de FAB adaptáveis, responsivos e acessíveis a cores. Teste a demonstração e veja a fonte.
Se preferir vídeo, aqui está uma versão do YouTube desta postagem:
Visão geral
Os FABs são mais comuns em dispositivos móveis do que em computadores, mas prevalem em ambos os cenários. Elas mantêm as ações principais em foco, tornando-as convenientes e onipresentes. Esse estilo de experiência do usuário ficou famoso pela interface do Material Design, e as sugestões de uso e posicionamento podem ser encontradas neste link (link em inglês).
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 uma lacuna 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 do FAB
Esse elemento pode ser um <div>
normal, mas vamos fazer um favor aos usuários sem visão
e marcá-lo com 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 com o estilo e, em seguida, adicione role="group"
e aria-label
para que não seja apenas um contêiner genérico, ele tenha um nome e tenha uma finalidade.
<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 permanecem 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ção 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, coloco a tela do contêiner
flex
e mudo a
direção do layout para
column-reverse
.
Isso empilha os filhos uns sobre os outros (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 topo, que seria para onde o foco normalmente é dirigido pelo
documento HTML. A inversão da ordem visual une a experiência de usuários
com visão e de teclado, já que o estilo da ação principal como maior
do que os minibotões indica para usuários com deficiência visual que essa é uma ação principal, e
usuários de teclado focam a ação como o primeiro item na fonte.
.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
A centralização é processada com
place-items
, e
gap
adiciona espaço entre todos os
botões do FAB colocados no contêiner.
Botões FAB
É hora de definir o estilo de alguns botões para que pareçam estar flutuando por cima de tudo.
FAB padrão
O primeiro botão de estilo é o padrão. Ele servirá como a base para todos os botões do FAB. Mais adiante, vamos criar uma variante que tenha uma aparência alternativa ao modificar o mínimo possível desses estilos base.
Marcação FAB
O elemento <button>
é a escolha certa. Vamos começar com isso como a base, porque ele oferece uma ótima experiência do 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 à marcação
<button>
. Ao adicionar rótulos nesses casos, também gosto de adicionar um title
para que os usuários
do mouse possam receber informações sobre o que o ícone espera 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 e preenchido com uma sombra forte, já que estes são os primeiros recursos que definem o botão:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
Em seguida, vamos adicionar cor. Usaremos uma estratégia que já usamos nos desafios de GUI antes. Crie um conjunto claramente nomeado de propriedades personalizadas que mantêm estaticamente as cores claras e escuras e, em seguida, uma propriedade personalizada adaptável que será definida como as variáveis claras ou escuras, dependendo da preferência do sistema do usuário por cores:
.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 caber 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 tornar alguns dos FABs menores do que a 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 é igual ao FAB, mas adicionamos uma classe ".mini" para dar ao CSS um gancho para a 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 a ser lembrada para acessibilidade com FABs é o posicionamento dentro do fluxo do teclado da página. Esta demonstração tem apenas os FABs. Não há com que competir em termos de ordem e fluxo do teclado, o que significa que não tem a oportunidade de demonstrar um fluxo de teclado significativo. Em um cenário em que há elementos conflitantes para se concentrar, sugiro pensar profundamente sobre em que parte desse fluxo um usuário deve entrar no fluxo de botões do FAB.
Quando o usuário se concentra no contêiner do FAB, já adicionamos
role="group"
e aria-label="floating action buttons"
, que informam os usuários
de leitores de tela sobre o conteúdo do foco. 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. Essa é uma boa vitória,
porque o botão padrão é visualmente proeminente e também é o primeiro para os usuários
de teclado, proporcionando experiências muito semelhantes.
Por fim, não se esqueça de ocultar os ícones dos usuários de leitores de tela e
forneça a eles um rótulo para o botão, para não haver mistério. Isso já foi
feito no HTML com aria-hidden="true"
nos <svg>
e
aria-label="Some action"
nos <button>
s.
Animação
Vários tipos de animação podem ser adicionados para aprimorar a experiência do usuário. Como em
outros desafios da GUI, vamos configurar algumas propriedades personalizadas para manter
a intenção de uma experiência de movimento reduzido e uma experiência de movimento completa. Por padrão,
os estilos presumem que o usuário quer movimento reduzido e, usando a
consulta de mídia prefers-reduced-motion
, troca o valor da transição para movimento total.
Uma estratégia de movimento reduzida 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 implementado, é possível fazer a transição das mudanças em box-shadow
, background-color
, transform
e outline-offset
, oferecendo ao usuário um bom feedback sobre a interface de que a interação foi recebida.
Em seguida, adicione um pouco mais de estilo ao estado :active
ajustando o
translateY
um pouco. Isso proporciona ao botão um bom efeito de pressionamento:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
Por fim, faça a transição das 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 isso, o que você faria ‽ 🙂
Vamos diversificar nossas abordagens e aprender todas as maneiras de criar na Web.
Crie uma demonstração, envie um tweet para mim e os adicionarei à seção de remixes da comunidade abaixo.
Remixes da comunidade
Ainda não há nada aqui.
Recursos
- Código-fonte no GitHub