Estilos de seleção personalizados com CSS puro

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 lista option. 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 do options é 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)

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *