HOWTO · CSS
Escolha de Estilo Dropdown no CSS
Este tutorial apresenta como estilizar o menu suspenso em CSS.
Nesta página
Você pode estilizar um menu suspenso nativo de HTML select alterando sua caixa e substituindo a seta padrão por uma seta desenhada em CSS. O controle continua sendo um select real, portanto os usuários mantêm o comportamento de seleção integrado e a interação pelo teclado. Duas abordagens comuns são remover diretamente a aparência nativa ou ocultar a seta nativa com um contêiner que a recorta.
Estilize um menu suspenso nativo de select mantendo seu comportamento
Um select contém elementos option, e o navegador renderiza o controle conforme as convenções da plataforma e do próprio navegador. O CSS pode alterar a caixa visível, mas a lista aberta e alguns detalhes ainda variam entre navegadores e sistemas operacionais. Mantenha o elemento nativo em vez de recriar um menu suspenso com elementos genéricos quando quiser preservar os comportamentos integrados de formulário e teclado.
Os exemplos usam as mesmas quatro opções. O CSS deixa espaço à direita do controle para uma seta e mostra um contorno de foco visível para quem navega pelo teclado. Ajuste as cores e dimensões para combinarem com sua interface.
Oculte a seta nativa com appearance: none e adicione uma seta personalizada
Defina appearance: none no select para remover a seta nativa do navegador onde houver suporte e, em seguida, desenhe um chevron com dois gradientes CSS. As camadas de background posicionam os dois traços perto da borda direita; o preenchimento à direita mantém o texto das opções afastado deles. As declarações -webkit-appearance e -moz-appearance são formas prefixadas da propriedade, usadas por mecanismos que reconhecem esses prefixos; elas não correspondem a famílias distintas de navegadores WebKit/Blink. A propriedade padrão é a declaração principal, então mantenha os prefixos apenas se os requisitos de compatibilidade dos seus navegadores justificarem isso.
Esta página completa é um exemplo estático para navegador. Salve-a como arquivo HTML e abra-a em um navegador para ver o controle; o pacote não inclui evidências de renderização em navegador que permitam afirmar um resultado visual observado.
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Styled select</title>
<style>
.vehicle-select {
box-sizing: border-box;
width: 220px;
height: 40px;
padding: 0 32px 0 10px;
border: 1px solid #777;
border-radius: 4px;
color: #222;
background-color: #fff;
background-image:
linear-gradient(45deg, transparent 50%, #333 50%),
linear-gradient(135deg, #333 50%, transparent 50%);
background-position:
calc(100% - 14px) 50%,
calc(100% - 9px) 50%;
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
appearance: none;
}
.vehicle-select:focus-visible {
outline: 3px solid #1769aa;
outline-offset: 2px;
}
</style>
</head>
<body>
<label for="vehicle">Choose a vehicle</label>
<select class="vehicle-select" id="vehicle" name="vehicle">
<option>RE Himalayan</option>
<option selected>CRF Rally</option>
<option>GS 310</option>
<option>KTM ADV</option>
</select>
</body>
</html>
Oculte a seta nativa com um contêiner que a recorta
Um contêiner oferece outra forma de ocultar a seta nativa. Defina no select uma largura um pouco maior que a do contêiner e configure overflow do contêiner como hidden; assim, a seta nativa fica fora da área visível. Desenhe uma seta substituta no contêiner usando um pseudo-elemento. Como o select continua dentro dele, suas opções e interação nativa permanecem disponíveis.
Deixe o contêiner largo o bastante para o texto do controle e faça o select apenas um pouco mais largo. Se a diferença for grande demais, a borda direita do controle ou outro conteúdo também poderá ser recortado. O pseudo-elemento usa pointer-events: none para não interceptar os cliques no select.
No exemplo com contêiner, o select ultrapassa o contêiner em 20 pixels. Esta pequena verificação em JavaScript deixa explícita essa relação entre as larguras:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
const wrapperWidth = 200;
const selectWidth = 220;
if (selectWidth <= wrapperWidth) {
process.exitCode = 1;
}
A verificação é concluída com sucesso quando o select é mais largo que o contêiner; caso contrário, ela define um código de saída de falha.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Select with clipped arrow</title>
<style>
.select-wrap {
position: relative;
box-sizing: border-box;
width: 200px;
height: 42px;
overflow: hidden;
border: 1px solid #777;
border-radius: 4px;
background: #fff;
}
.select-wrap select {
box-sizing: border-box;
width: 220px;
height: 40px;
padding: 0 10px;
border: 0;
color: #222;
background: transparent;
font: inherit;
}
.select-wrap::after {
position: absolute;
top: 18px;
right: 12px;
width: 7px;
height: 7px;
border-right: 2px solid #333;
border-bottom: 2px solid #333;
content: "";
pointer-events: none;
transform: rotate(45deg);
}
.select-wrap:focus-within {
outline: 3px solid #1769aa;
outline-offset: 2px;
}
</style>
</head>
<body>
<label for="vehicle">Choose a vehicle</label>
<div class="select-wrap">
<select id="vehicle" name="vehicle">
<option>RE Himalayan</option>
<option selected>CRF Rally</option>
<option>GS 310</option>
<option>KTM ADV</option>
</select>
</div>
</body>
</html>
Escolha uma abordagem e verifique seus limites
Use appearance: none quando quiser que o próprio select determine sua largura e borda e os navegadores de destino oferecerem suporte à estilização necessária. Use um contêiner que recorta a seta quando precisar posicioná-la no próprio contêiner ou quando a estilização direta da aparência não for adequada. Em ambos os casos, teste a página nos navegadores e dispositivos compatíveis com seu projeto: a renderização de elementos select nativos e suas listas abertas não é totalmente uniforme.
Confira se o valor selecionado aparece por inteiro, se a seta personalizada está alinhada e se o foco pelo teclado é fácil de identificar. Na versão com contêiner, compare as larguras do contêiner e do select se a borda ou o texto parecerem cortados. Não remova o indicador de foco apenas para deixar o controle visualmente mais limpo; se personalizá-lo, substitua-o por um estilo igualmente claro. Essas técnicas alteram a apresentação, mas deixam o select nativo responsável pela seleção e pelo comportamento do formulário.