Este é o episódio # 20 de uma série que examina soluções CSS modernas para problemas que venho resolvendo nos últimos 13 anos como um desenvolvedor front-end.
O CSS moderno nos oferece uma gama de propriedades para alcançar estilos selecionados personalizados que têm uma aparência quase idêntica aparência inicial de elementos select
únicos, múltiplos e desabilitados nos principais navegadores.
Algumas propriedades e técnicas que nossa solução usará:
-
clip-path
para criar a seta suspensa personalizada - layout de grade CSS para alinhar a seleção nativa e seta
- variáveis CSS personalizadas para estilo flexível
-
em
unidades para dimensionamento relativo
Problemas comuns com seleções nativas #
Como com todos os tipos de campo de formulário, <select>
varia entre os navegadores em sua aparência inicial.
Da esquerda para a direita, aqui está a aparência inicial de <select>
no Firefox, Chrome e Safari:
As diferenças incluem o tamanho da caixa, o tamanho da fonte, a altura da linha e o mais notável é a diferença no estilo do indicador suspenso.
Nosso o objetivo é criar a mesma aparência inicial nesses navegadores, incluindo várias seleções e estados desabilitados.
Observação: a lista suspensa ainda não pode ser estilizada, então, assim que
<select>
for aberto, ele ainda pegará os estilos do navegador individual para a listaoption
. Isso está certo – podemos lidar com isso para manter a acessibilidade livre de um select nativo!
HTML básico #
Nós ” Vou focar em um único <select>
para começar.
O rótulo não faz parte de nosso exercício de estilo, mas está incluído como um requisito geral, principalmente com o for
atributo tendo o valor de id
no <select>
.
Para realizar nossos estilos personalizados, envolvemos a seleção nativa em um div extra com a classe de select
para simplificar neste tutorial.
Redefinir e remover estilos herdados #
Como está incluído em todos os meus tutoriais como uma prática recomendada moderna, adicionamos a seguinte redefinição primeiro:
Depois disso, podemos começar a regra para o select
nativo e aplicar o seguinte para manter sua aparência:
Embora a maioria deles seja provavelmente familiar, o estranho é . Esta é uma propriedade raramente usada e você notará que não é bem onde gostaríamos de suporte, mas o que ela está fornecendo principalmente para nós neste caso é a remoção da seta suspensa do navegador nativo.
Observação: O CodePen é configurado para usar autoprefixer, que adicionará as versões pré-fixadas necessárias da propriedade
appearance
. Pode ser necessário configurar isso especificamente para o seu projeto ou adicioná-los manualmente. Meu HTML / Sass Jumpstart inclui autoprefixer como parte da compilação de produção.
A boa notícia é que podemos adicionar mais uma regra para obter a remoção da seta para versões anteriores do IE, se necessário:
Esta dica encontrada no excelente artigo do Filament Group que mostra um método alternativo para criar estilos selecionados.
A última parte é remover o outline
padrão. Não se preocupe – nós ” adicionarei uma substituição mais tarde para :focus
estado!
E aqui está um gif do nosso progresso. Você pode ver que agora não há nenhuma indicação visual de que este é um select
antes de clicar nele:
Estilos de caixa de seleção personalizados #
Primeiro, vamos configurar algumas variáveis CSS. Isso permitirá que nossa seleção seja recolorida de maneira flexível, de modo a representar um estado de erro.
Nota de acessibilidade: Como um elemento da interface do usuário, a borda selecionada deve ter um contraste 3: 1 ou maior em relação à cor da superfície circundante.
Agora é hora de criar os estilos de seleção personalizados que aplicaremos ao nosso envoltório div.select
:
Primeiro, configuramos algumas restrições de largura. Os valores min-width
e max-width
são principalmente para esta demonstração e você pode optar por descartá-los ou alterá-los para seu caso de uso.
Em seguida, aplicamos algumas propriedades do modelo de caixa, incluindo border
, border-radius
e padding
. Observe o uso da unidade em
que manterá essas propriedades proporcionais ao conjunto font-size
.
Nos estilos de redefinição, definimos várias propriedades para inherit
, então aqui nós as definimos, incluindo font-size
, cursor
e line-height
.
Finalmente, fornecemos propriedades de fundo, incluindo um gradiente para o menor pedaço de dimensão. Se você remover as propriedades de fundo, a seleção ficará transparente e pegará o fundo da página. Isso pode ser desejável, no entanto, fique atento e teste os efeitos no contraste.
E aqui está nosso progresso:
Personalizado Selecione a seta suspensa #
Para nossa seta suspensa, usaremos uma das propriedades CSS modernas mais interessantes: clip-path
.
Os caminhos de recorte nos permitem fazer todos os tipos de formas “recortando” as formas quadradas e retangulares que recebemos como padrão da maioria dos elementos. Eu me diverti usando clip-path
no meu recente redesenho do site de portfólio.
Antes de clip-path
ter um suporte melhor, métodos alternativos incluídos:
-
background-image
– normalmente um png, um pouco mais moderno seria um SVG - um SVG embutido como um elemento adicional
- o truque da borda para criar um triângulo
SVG pode parecer a solução ideal, no entanto, quando usado como um background-image
, ele perde a capacidade de agir como um ícone no sentido de não ser capaz de t o alterar suas propriedades, como a cor de preenchimento, sem redefini-la totalmente. Isso significa que não podemos usar nossa variável personalizada CSS.
Colocar um SVG embutido resolve o fill
problema de cor, no entanto, significa incluir mais um elemento sempre que um <select>
é definido.
Com clip-path
, obtemos um gráfico “gráfico” de seta nítido e escalonável que parece um SVG, mas com os benefícios de poder usar nossa variável personalizada e estar contida no estilo em comparação com a marcação HTML.
Para criar a seta, vamos defini-la como ::after
pseudo-elemento.
A sintaxe clip-path
é um pouco estranha, e como é realmente não é o foco deste artigo, eu recomendo os seguintes recursos:
- Colby Fayock explica a sintaxe com um exemplo neste vídeo egghead
- Clippy é uma ferramenta online que permite você deve selecionar uma forma e ajustar os pontos enquanto gera dinamicamente o
clip-path
CSS
Se você seguir ao longo do caminho, você deve ter notado que a seta não está aparecendo apesar de definir width
e height
. Quando inspecionado, descobriu-se que o ::after
não está realmente tendo permissão para sua largura.
Vamos resolver isso atualizando nosso .select
para usar o layout de grade CSS.
Isso permite que a seta apareça essencialmente estendendo-a para um valor de exibição semelhante a “bloquear”.
Neste estágio, podemos verificar que realmente criamos um triângulo.
Para corrigir o alinhamento, usaremos meu hack de grade CSS favorito (velho para você, caso tenha lido alguns artigos por aqui!).
Solução CSS antiga: position: absolute
Nova solução CSS: um único grid-template-areas
para conter todos eles
Primeiro, definiremos nossa área e, em seguida, definiremos que select
e ::after
o usam. O nome tem como escopo o elemento para o qual foi criado, e nós o manteremos fácil chamando-o de “select”:
O que nos dá uma sobreposição de a seta acima da seleção nativa devido ao contexto de empilhamento via ordem de origem:
Agora podemos usar as propriedades da grade para finalizar o alinhamento de cada elemento:
Ta-da!
: focus State #
Ah, sim – lembra como removemos o outline
? Precisamos resolver o :focus
estado de descartar isso.
Há uma próxima propriedade que poderíamos usar chamada :focus-within
, mas ainda é melhor incluir um polyfill para ele neste tempo.
Para este tutorial, vamos usar um método alternativo que atinge o mesmo resultado, apenas um pouco mais pesado.
Infelizmente, isso significa que precisamos adicionar mais um elemento em o DOM.
Após o elemento de seleção nativo, como o último filho em .select
, adicione:
Por que depois? Como esta é uma solução CSS pura, colocá-la após a seleção nativa significa que podemos alterá-la quando select
for focalizado pelo uso do seletor irmão adjacente – +
.
Isso nos permite criar a seguinte regra:
Você pode estar se perguntando por que voltamos a position: absolute
depois de aprender o hack grid-area
anterior.
O motivo é evitar o recálculo de ajustes com base no preenchimento. Se você tentar por conta própria, “verá que mesmo definindo width
e height
para 100% ainda faz com que se encaixe no preenchimento .
O trabalho position: absolute
faz melhor é combinar o tamanho de um elemento. Estamos puxando um pixel extra em cada direção para garantir que ele se sobreponha à borda propriedade.
Mas, precisamos fazer mais uma adição a .select
para garantir que seja “relativo à nossa seleção por – bem, position: relative
.
E aqui está nossa seleção personalizada, como visto no Chrome:
Multiple Select #
As seleções vêm em um segundo tipo, que permite ao usuário selecionar mais de uma opção. Da perspectiva do HTML, isso significa simplesmente adicionar o atributo multiple
, mas também adicionaremos uma classe para ajudar a criar ajustes de estilo chamada select--multiple
:
E olhando para ele, podemos ver que “herdou a maioria de nossos estilos favoravelmente, exceto que não precisamos da seta nesta visualização.
Esta é uma solução rápida para ajustar nosso seletor que define a seta. Usamos :not()
para excluir nossa classe recém-definida:
Temos alguns pequenos ajustes para fazer para a seleção múltipla, o primeiro é remover o preenchimento que foi adicionado anteriormente para abrir espaço para a seta:
Por padrão, as opções com um valor longo irão estourar a área visível e serão cortadas, mas descobri que os navegadores principais permitem que a quebra seja substituída se você desejar:
Opcionalmente, podemos definir um height
na seleção para trazer um comportamento um pouco mais confiável entre navegadores. Testando isso, aprendi que o Chrome e o Firefox mostrarão uma opção parcial, mas o Safari ocultará completamente uma opção que não pode ser totalmente visualizada.
A altura deve ser definida diretamente no seletor nativo . Dados nossos outros estilos, o valor 6rem
será capaz de mostrar 3 opções:
Neste ponto, devido ao suporte do navegador atual, fizemos todos os ajustes possíveis.
O estado
:selected
dooptions
é bastante personalizável no Chrome, um pouco no Firefox, e não no Safari. Veja a demonstração do CodePen para uma seção que pode ser descomentada para visualizar isso.
: Estilos desativados #
Embora eu recomende simplesmente não mostrando os controles desabilitados, devemos preparar os estilos para aquele estado apenas para cobrir nossas bases.
Para enfatizar o estado desabilitado, queremos aplicar um fundo cinza. Mas, uma vez que definimos estilos de fundo em .select
e não existe um seletor “ta :parent
, precisamos criar uma última classe para lidar com este estado:
Aqui, atualizamos o cursor como uma dica extra de que não é possível interagir com o campo e atualizamos os valores de fundo que definimos anteriormente ser branco para agora ser mais cinza para o estado desativado.
Isso resulta nas seguintes aparências:
Demo #
Você pode testá-lo por si mesmo, mas aqui está uma prévia da solução completa (a partir da esquerda) Firefox, Chrome e Safari:
Por Stephanie Eckles (@ 5t3ph)