Este es el episodio n. ° 20 de una serie que examina las soluciones CSS modernas para los problemas que he estado resolviendo durante los últimos 13 años como desarrollador frontend.
El CSS moderno nos brinda una variedad de propiedades para lograr estilos de selección personalizados que tienen un aspecto casi idéntico apariencia inicial para elementos select
únicos, múltiples y desactivados en los principales navegadores.
Algunas propiedades y técnicas que utilizará nuestra solución:
-
clip-path
para crear la flecha desplegable personalizada - Diseño de cuadrícula CSS para alinear la selección nativa y la flecha
- variables CSS personalizadas para estilo flexible
-
em
unidades para el tamaño relativo
Problemas comunes con las selecciones nativas #
Al igual que con todos los tipos de campos de formulario, <select>
varía según los navegadores en su apariencia inicial.
De izquierda a derecha, aquí está la apariencia inicial de <select>
en Firefox, Chrome y Safari:
Las diferencias incluyen el tamaño del cuadro, el tamaño de la fuente, la altura de la línea y lo más destacado es la diferencia en el estilo del indicador desplegable.
Nuestro El objetivo es crear la misma apariencia inicial en estos navegadores, incluidas las selecciones múltiples y los estados deshabilitados.
Nota: La lista desplegable aún no se puede diseñar, por lo tanto, una vez que se abra
<select>
, seguirá recogiendo los estilos del navegador individual para la listaoption
. Esto está bien, ¡podemos lidiar con eso para retener la accesibilidad gratuita de una selección nativa!
Base HTML #
Nosotros » Nos centraremos en un solo <select>
para comenzar.
La etiqueta no es parte de nuestro ejercicio de estilo, pero se incluye como un requisito general, en particular con el for
atributo que tiene el valor del id
en el <select>
.
Para lograr nuestros estilos personalizados, hemos «envuelto la selección nativa en un div adicional con la clase de select
para simplificar este tutorial.
Restablecer y eliminar estilos heredados #
Como se incluye en todos mis tutoriales como una práctica recomendada moderna, primero agregamos el siguiente restablecimiento:
A continuación, podemos comenzar la regla para el select
nativo y aplicar lo siguiente para que descanse su apariencia:
Si bien la mayoría de ellos son probablemente familiares, lo extraño es . Esta es una propiedad que se usa con poca frecuencia y notará que no está exactamente donde nos gustaría que fuera compatible, pero lo que nos brinda principalmente en este caso es la eliminación de la flecha desplegable del navegador nativo.
Nota: CodePen está configurado para usar autoprefixer que agregará las versiones predeterminadas requeridas de la propiedad
appearance
. Es posible que deba configurar esto específicamente para su proyecto o agregarlos manualmente. Mi HTML / Sass Jumpstart incluye autoprefixer como parte de la compilación de producción.
La buena noticia es que podemos agregar una regla más para eliminar la flecha para las versiones inferiores de IE si lo necesita:
Este consejo se encuentra en el excelente artículo de Filament Group que muestra un método alternativo para crear estilos seleccionados.
La última parte es eliminar el outline
predeterminado. No se preocupe, nosotros Más adelante agregaré un reemplazo para :focus
estado!
Y aquí hay un gif de nuestro progreso. Puede ver que ahora no hay ninguna indicación visual de que se trata de un select
antes de hacer clic en él:
Estilos de cuadro de selección personalizados #
Primero, configuremos algunas variables CSS. Esto permitirá que nuestra selección se vuelva a colorear de manera flexible para representar un estado de error.
Nota de accesibilidad: como elemento de la interfaz de usuario, el borde seleccionado debe tener un contraste de 3: 1 o mayor contra el color de la superficie circundante.
Ahora es el momento de crear los estilos de selección personalizados que aplicaremos a nuestro envoltorio div.select
:
Primero, configuramos algunas restricciones de ancho. Los valores min-width
y max-width
son principalmente para esta demostración, y puede optar por eliminarlo o modificarlo para su caso de uso.
Luego aplicamos algunas propiedades del modelo de caja, incluidas border
, border-radius
y padding
. Tenga en cuenta el uso de la unidad em
que mantendrá estas propiedades proporcionales al conjunto font-size
.
En los estilos de restablecimiento, establecemos varias propiedades en inherit
, por lo que aquí las definimos, incluidas font-size
, cursor
y line-height
.
Por último, le proporcionamos propiedades de fondo, incluido un degradado para el más mínimo dimensión. Si elimina las propiedades del fondo, la selección será transparente y recogerá el fondo de la página. Esto puede ser deseable, sin embargo, tenga en cuenta y pruebe los efectos sobre el contraste.
Y aquí está nuestro progreso:
Personalizado Seleccione la flecha desplegable #
Para nuestra flecha desplegable, usaremos una de las propiedades CSS modernas más interesantes: clip-path
.
Los trazados de recorte nos permiten hacer todo tipo de formas «recortando» las formas cuadradas y rectangulares que recibimos como predeterminadas de la mayoría de los elementos. Me divertí usando clip-path
en mi reciente rediseño del sitio de portafolio.
Antes de que clip-path
tuviera un mejor soporte, los métodos alternativos incluían:
-
background-image
– normalmente un png, un poco más moderno sería un SVG - un SVG en línea como elemento adicional
- el truco de borde para crear un triángulo
SVG puede parecer la solución óptima, sin embargo, cuando se usa como background-image
pierde la capacidad de actuar como un ícono en el sentido de no poder t o alterar sus propiedades como el color de relleno sin redefinirlo por completo. Esto significa que no podemos usar nuestra variable personalizada CSS.
Colocar un SVG en línea resuelve el fill
problema de color, sin embargo, significa incluir un elemento más cada vez que un <select>
está definido.
Con clip-path
, obtenemos un «gráfico» de flecha nítido y escalable que se siente como un SVG pero con los beneficios de poder usar nuestra variable personalizada y estar contenida en el estilo frente al marcado HTML.
Para crear la flecha, la definiremos como un ::after
pseudo-elemento.
La clip-path
sintaxis es un poco extraña, y como no es realmente el enfoque de este artículo, recomiendo los siguientes recursos:
- Colby Fayock explica la sintaxis con un ejemplo en este video de cabeza de huevo
- Clippy es una herramienta en línea que permite para seleccionar una forma y ajustar los puntos mientras genera dinámicamente el
clip-path
CSS
Si sigue con el ala, es posible que haya notado que la flecha no aparece a pesar de definir width
y height
. Cuando se inspeccionó, se encontró que ::after
en realidad no se le permite su ancho.
Resolveremos esto actualizando nuestro .select
para usar el diseño de cuadrícula CSS.
Esto permite que la flecha aparezca esencialmente extendiéndola como un valor de visualización similar a «bloque».
En esta etapa podemos verificar que efectivamente hemos creado un triángulo.
Para corregir la alineación, Usaremos mi truco de cuadrícula CSS favorito (¡el sombrero viejo si ha leído algunos artículos por aquí!).
Solución CSS antigua: position: absolute
Nueva solución CSS: Un solo grid-template-areas
para contenerlos todos
Primero definiremos nuestra área, luego definiremos que el select
y ::after
ambos lo usan. El nombre tiene como alcance el elemento para el que se creó, y lo haremos fácil llamándolo «seleccionar»:
Lo que nos da una superposición de la flecha sobre la selección nativa debido al contexto de apilamiento a través del orden de origen:
Ahora podemos usar las propiedades de la cuadrícula para finalizar la alineación de cada elemento:
¡Ta-da!
: focus State #
Ah, sí, ¿recuerdas cómo eliminamos el outline
? Necesitamos resolver el :focus
estado de eliminar eso.
Hay una propiedad próxima que podríamos usar llamada :focus-within
pero aún es mejor incluir un polyfill para ello en este tiempo.
Para este tutorial, usaremos un método alternativo que logra el mismo resultado, solo que un poco más pesado.
Desafortunadamente, esto significa que necesitamos agregar un elemento más en el DOM.
Después del elemento de selección nativo, como último niño dentro de .select
, agregue:
¿Por qué después? Debido a que esta es una solución CSS pura, colocarla después de la selección nativa significa que podemos alterarla cuando select
se enfoca mediante el uso del selector de hermanos adyacente – +
.
Esto nos permite crear la siguiente regla:
Quizás se pregunte por qué» volvemos a position: absolute
después de aprender el truco anterior grid-area
.
La razón es evitar volver a calcular los ajustes basados en el relleno. Si lo prueba por su cuenta, verá que incluso si configura width
y height
al 100%, se mantiene dentro del relleno. .
El trabajo que position: absolute
hace mejor es hacer coincidir el tamaño de un elemento. Lo tiraremos un píxel adicional en cada dirección para asegurarnos de que se superponga al borde propiedad.
Pero, necesitamos hacer una adición más a .select
para asegurarnos de que «es relativo a nuestra selección por – bueno, position: relative
.
Y aquí» nuestra selección personalizada todos juntos como se ve en Chrome:
Selección múltiple #
Las selecciones vienen en un segundo sabor, que permite al usuario seleccionar más de una opción. Desde la perspectiva HTML, esto simplemente significa agregar el atributo multiple
, pero también agregaremos una clase para ayudar a crear ajustes de estilo llamada select--multiple
:
Y mirándolo, podemos ver que ha heredado la mayoría de nuestros estilos favorablemente, excepto que no necesitamos la flecha en esta vista.
Esta es una solución rápida para ajustar nuestro selector que define la flecha. Usamos :not()
para excluir nuestra clase recién definida:
Tenemos que hacer un par de ajustes menores para la selección múltiple, el primero es eliminar el relleno que se agregó anteriormente para dejar espacio para la flecha:
De forma predeterminada, las opciones con un valor largo desbordarán el área visible y se recortarán, pero descubrí que los navegadores principales permiten anular el ajuste si lo desea:
Opcionalmente, podemos establecer un height
en la selección para traer un comportamiento un poco más confiable entre navegadores. Al probar esto, aprendí que Chrome y Firefox mostrarán una opción parcial, pero Safari ocultará completamente una opción que no puede estar completamente a la vista.
La altura debe configurarse directamente en la selección nativa . Dados nuestros otros estilos, el valor 6rem
podrá mostrar 3 opciones:
En este punto, debido a la compatibilidad del navegador actual, hemos realizado todos los ajustes que hemos podido.
El estado
:selected
deoptions
es bastante personalizable en Chrome, algo en Firefox y nada en Safari. Consulte la demostración de CodePen para ver una sección que se puede descomentar para obtener una vista previa de esto.
: estilos deshabilitados #
simplemente sin mostrar controles deshabilitados, deberíamos preparar los estilos para ese estado solo para cubrir nuestras bases.
Para enfatizar el estado deshabilitado, queremos aplicar un fondo gris. Pero como «hemos configurado estilos de fondo en .select
y no hay un selector» ta :parent
, necesitamos crear una última clase para manejar este estado:
Aquí hemos actualizado el cursor como una pista adicional de que no se puede interactuar con el campo, y hemos actualizado los valores de fondo que establecimos previamente ser blanco para ahora ser más gris para el estado deshabilitado.
Esto da como resultado las siguientes apariencias:
Demo #
Puede probarlo usted mismo, pero aquí hay una vista previa de la solución completa (desde la izquierda) en Firefox, Chrome y Safari:
Por Stephanie Eckles (@ 5t3ph)