Dominando los Selectores Hermanos Generales: Elementos de Formulario Personalizados.
() translation by (you can also view the original English article)
Uno de los selectores CSS más poderosos y poco utilizados es el combinador de hermanos: ~
. En estos tutoriales voy a mostrar diferentes formas de usar ~
para crear componentes que no solo son visualmente atractivos, sino que también funcionales y útiles. Este tutorial va a cubrir elementos de formulario; radio, checkbox, e inputs regulares.
Vamos a aprender un monto: los selectores CSS modernos, la propiedad will-change
, propiedades stroke
de SVG, estados de los inputs, y ¡mucho mas!.
Antes de Empezar...
Un rápido descargo de responsabilidad: Estos efectos CSS pueden o no funcionar en navegadores antiguos - los he probado en la últimas versiones de Chrome, Firefox, y Safari.
Voy a usar Haml (un compilador HTML) y Sass (un pre procesador CSS) para !acelerar¡ el proceso de codificado. Los demos van a usar Haml mientras que cualquier código entre lineas va a usar HTML normal.
También estaré usando el increíble AutoPrefixer en lugar de los prefijos del navegador. Si usas CodePen, asegurate de ir a la configuración de tu pen, da clic en CSS, y selecciona AutoPrefixer.



Botón de Radio
Vamos a empezar con uno de los elementos de formulario mas básicos: el botón de radio. Existen dos estados visuales (seleccionado y no seleccionado) también dos entre estados (encima y clic/activo-clic es similar e apariencia a seleccionado)
Versión SVG
El primer paso es crear nuestro HTML. Necesitaras un contenedor exterior principal y un contenedor interno con dos hijos: un div
conteniendo el botón y elementos visuales y un label
para el botón. Me gusta usar un fieldset
para el contenedor exterior. Asegúrate de agregar un ID para el botón que concuerde con el atributo for
en la etiqueta.
1 |
<fieldset>
|
2 |
<div class="container"> |
3 |
<div class="svg"> |
4 |
<input id="radio-svg" type="radio" name="option"/> |
5 |
<div></div>
|
6 |
<svg viewBox="0 0 24 24"> |
7 |
<circle cx="12" cy="12" r="8"></circle> |
8 |
<circle cx="12" cy="12" r="8"></circle> |
9 |
</svg>
|
10 |
</div>
|
11 |
<label for="radio-svg">SVG</label> |
12 |
</div>
|
13 |
</fieldset>
|
El siguiente paso es ocultar el botón predeterminado, agregamos algo de estilo visual básico, y ocultamos los elementos extra que solamente se van a mostrar cuando el botón de radio sea seleccionado. La idea es hacer el botón invisible, pero posicionarlo sobre los elementos visuales, de forma que dando clic en el botón de radio parezca que dan clic en la opción visual del botón. Podemos hacer esto estableciendo position:relative
a .svg
y position: absolute
para el botón, luego ocultar el botón.
Nota: puedes dar formato a eso de la forma en que quieras, yo he elegido un circulo básico de estilo minimalista que imita el botón de radio predeterminado, excepto que es plano.
Vamos a establecer algunas variables de color usando Sass; un par de colores grises y un azul brillante para el radio seleccionado. También vamos a establecer una variable $p para nuestra unidad predeterminada - 12px es un buen numero porque es divisible por un amplio rango de números(1, 2, 3, 4, 6).
Puse la variables principales en el directamente, pero el estilo adicional puede ser encontrado aquí o dando clic en la pagina de CodePen, da clic en Settings en la esquina superior derecha, y da clic en la pestaña CSS para ver hojas de estilo adicionales.
Hemos creado el primer circulo uno gris claro y el segundo es el azul brillante, y luego ocultamos el segundo estableciendo transform: scale (0)
. Luego, vamos a animar el circulo para que entre del fondo, así que es importante establecer la escala ahora.
Después configuramos todo eso, necesitamos decidir el estilo visual para cada estado. Para este ejemplo, He decidido que para encima el circulo gris claro se va a transformar en azul claro; en clic, el circulo se escala y el fondo gris se convierte en blanco, entonces permanece así par el estado de seleccionado. La única forma de quitar el estado seleccionado de un radio es dando clic en otro radio, en este case el azul y blanco deberían simplemente desvanecerse.
Primero vamos a establecer los colores, luego vamos a animar después de todo los estados tienen color. Esto es donde la tilde ~
se vuelve útil. Este selector general de hermanos (el combinador de hermano) va a seleccionar el segundo elemento siempre que este precedido por el primer elemento en algún lugar, y compartan un padre común. Usamos input:hover ~ div
para seleccionar el elemento visual cuando se encuentra encima del botón.
Prueba dando clic en el primer radio, luego en el segundo- deberías ser capaz de ver los estados encima y activo/seleccionado claramente.
El paso final es configurar las animaciones para cada estado. La clave para animar todos estos diferentes estados es establecer las transiciones de no seleccionado de forma predeterminada y establecer las transiciones de seleccionado cuando damos clic en el botón. Estoy usando una nueva propiedad de CSS llamada will-change
para permitir al navegador saber que propiedades va a estar animando.
Versión en HTML
La configuración es similar:
1 |
<fieldset>
|
2 |
<div class="container"> |
3 |
<div class="svg"> |
4 |
<input id="radio-html" type="radio" name="option"/> |
5 |
<div></div>
|
6 |
<div></div>
|
7 |
<div></div>
|
8 |
</div>
|
9 |
<label for="radio-html">HTML</label> |
10 |
</div>
|
11 |
</fieldset>
|
El CSS es casi el mismo, excepto que tiene algo mas de estilos para los dos elementos div
, que han reemplazado a los círculos SVG. En este caso, usamos nth-of-type(n)
para seleccionar los diferentes elementos div así que no tenemos que darles una clase en el HTML.
Con la versión en SVG, hay mas marcado pero menos estilizado; con la versión HTML, es de la forma contraria. El resultado se ve idéntico, prueba el que se ajuste a tus preferencias de código.
Casillas de verificación
El siguiente elemento de formulario que vamos a personalizar es la casilla de verificación. Sus estados son similares a los del botón de radio: dos estados visuales principales (seleccionado y no seleccionado) y dos estados intermedios (encima y clic/activo).
Versión SVG
La configuración se parece a la del radio, pero usa lineas para crear el cheque en lugar de circulos.
1 |
<fieldset>
|
2 |
<div class="container"> |
3 |
<div class="svg"> |
4 |
<input id="checkbox-svg" type="checkbox"> |
5 |
<div></div>
|
6 |
<div></div>
|
7 |
<svg viewBox="0 0 24 24"> |
8 |
<g>
|
9 |
<line x1="4.5" x2="9.24" y1="12.5" y2="17.24"></line> |
10 |
<line x1="9.24" x2="19.76" y1="17.24" y2="6.73"></line> |
11 |
</g>
|
12 |
<g>
|
13 |
<line x1="4.5" x2="9.24" y1="12.5" y2="17.24"></line> |
14 |
<line x1="9.24" x2="19.76" y1="17.24" y2="6.73"></line> |
15 |
</g>
|
16 |
</svg>
|
17 |
</div>
|
18 |
<label for="checkbox-svg">SVG</label> |
19 |
</div>
|
20 |
</fieldset>
|
Las lineas en el primer grupo tienen un gris claro y no son animadas; las lineas en el segundo grupo va a aparecer animadas cuando le den clic a la casilla.
También hay un elemento div
adicional; vamos a usar este para crear un efecto de clic donde el azul brillante se expanda en el fondo. Para hacer que este efecto funcione, el div necesita ser un círculo azul con un un ancho y alto mucho mas grandes que la casilla real, y el contenedor exterior debe tener overflow: hidden;
al ponerlo así los bordes del círculo no se muestran. El div redondo debe tener establecido transform: scale (0)
, similar al radio.



De nuevo, da formato a esto de acuerdo a tus preferencias. Yo decidí redondear los bordes del cheque así como todas las esquinas.
El siguiente paso es preparar las animaciones. Los efectos son similares al radio, excepto que en lugar de un círculo expandiéndose, el cheque se dibuja dentro de el mismo. Para esta animación, vamos a necesitar utilizar stroke-dashoffset
en las lineas del SVG.
Para poder animar stroke-dashoffset
, necesitamos el largo de cada linea. Yo cree una herramienta en CodePen para calcular los largos, pero si usas el cheque que yo ya cree, la linea corta tiene 6.708
de largo y la linea mas larga tiene 14.873
de largo. Vamos a usar este valor para establecer ambos stroke-dashoffset
y stroke-dasharray
. Esto es solo lo necesario para el primer cheque (el segundo juego de lineas muestra de forma predeterminada el estado de no seleccionado).
Cuando se da clic sobre la casilla, establecemos el stroke-dashoffset
a 0
, el cual (con una transformación) se verá como si se "dibujara" la linea. También necesitamos incluir el otro cambio de estado del radio personalizado, incluido el cambio de fondo cuando se esta encima y el circulo que cambia de tamaño al dar clic.
El ultimo paso es agregar todas las transiciones, De nuevo vamos a establecer la transición de no seleccionado como predeterminado y establecer la transición de seleccionado en clic
Versión HTML
Puedes obtener el mismo efecto con algunos elementos div en vez de usar un SVG; el marcado es más simple, pero no tan claramente delineado. El primer div vacío es el círculo azul que se está expandiendo, el segundo es la marca de verificación por defecto y el tercero es la marca de verificación que se anima cuando damos click.
1 |
<fieldset>
|
2 |
<div class="container"> |
3 |
<div class="line"> |
4 |
<input id="checkbox-html" type="checkbox"> |
5 |
<div></div>
|
6 |
<div></div>
|
7 |
<div></div>
|
8 |
</div>
|
9 |
<label for="checkbox-html">HTML</label> |
10 |
</div>
|
11 |
</fieldset>
|
Vamos a usar :before
y :after
como cada parte de la casilla de verificación, que simplifica el marcado, de otra manera necesitaríamos cuatro elementos vacíos o más para crear las dos casillas. Tenemos que posicionar las lineas manualmente y rotarlas en su lugar, pero puedes usar una sola transformación para rotarlas y dibujarlas.
Versión Símbolo
Puedes también usar una casilla de verificación en vez de rotar los elementos div. No es casi lo mismo como las otras dos visualmente, pero funciona de igual manera.
1 |
<fieldset>
|
2 |
<div class="container"> |
3 |
<div class="symbol"> |
4 |
<input id="checkbox-sym" type="checkbox"> |
5 |
<div></div>
|
6 |
<div>✓</div> |
7 |
<div>✓</div> |
8 |
</div>
|
9 |
<label for="checkbox-sym">Symbol</label> |
10 |
</div>
|
11 |
</fieldset>
|
Nota: Solo necesitas el símbolo HTML en los últimos dos elementos del div, pero en la demostración de abajo, he incluído tres divs para que pueda incluirlo en lazo repetido.
Ya que no podemos dibujar el símbolo, la versión blanca de desvanece al click. Chequea las tres versiones de abajo.
Inputs Regulares
La última parte de este tutorial el texto de input regular. He tomado inspiración de los inputs de linea de Google's Material. Estos inputs tienen estados diferentes: default, active/focus (cuando el parpadeo del cursor es visible), y un flotador sutil.
La preparación es incluso más mínimo que los estilos de input anteriores. Tenemos un fieldset, el input, un label, y un elemento div para el borde.
1 |
<fieldset>
|
2 |
<input id="example" type="text"> |
3 |
<label for="example">Label</label> |
4 |
<div></div>
|
5 |
</fieldset>
|
El siguiente paso es darle estilo al input. No ocultaremos el input esta vez ya que necesitaremos mostrar el valor. También crearemos una pestaña que se mueve hacia arriba y abajo cuando enfocamos el input. Para hacer que esto funcione, necesitaremos posicionar la pestaña exactamente arriba del input. El borde div tendrá un pseudo elemento :after
que se dibuja encima del borde cuando al input se le da click; pondremos un scale (0)
en el pseudo elemento para prepararla para la animación.
Si tratas de dar click en la demostración de arriba y comienzas a digitar, notarás que el texto se escribe encima de la pestaña. Animaremos la pestaña para que se reduzca al dar click. Puedes usar transformaciones enteramente para prevenir repintado, en vez de usar font-size
como lo hice, pero encontré que usarlo al igual como translateY
me da mucho una animación precisa. También borraremos la escala del div :after
para hacer el dibujo animado.
Ahora si tratas de dar click en el demo de arriba y comienzas a escribir de nuevo, la pestaña se encoje y se mueve hacia arriba, pero si dejas el texto escrito y das click afuera, la pestaña se mueve hacia abajo de nuevo, obstruyendo lo que se ha escrito. Podríamos usar JavaScript para prevenir este comportamiento, pero podemos usar un estado CSS llamado :valid
.
Podemos añadir required
como un atributo vacío a nuestro input en HTML o añadir :required => true
a nuestro input en Haml. Luego añadimos :valid
a las propiedades de :focus
en nuestro Sass/CSS. Esto añade un estado visual adicional a nuestro input, y ya que es un texto simple, el estado válido es cuando hay texto puesto.
Nota: usando una clase diferente de input como en el correo provocará que este comportamiento se rompa, ya que el input de correo electrónico tiene requerimientos de validación diferentes.
Inspiración
Si quieres crear tu propio input usando estas técnicas, pero necesitas inspiración visual, checa los kits UI disponibles en la suscripción de Envato Elements.



Conclusión
Hay docenas de diferentes maneras de utilizar los selectores de hermanos generales que son visuales, funcionales o ambos. Proveen una manera poderosa de personalizar los componentes sin tener que usar más que CSS y HTML. Hemos cubierto tres diferentes clases de elementos de forma en este tutorial; en el siguiente, vamos a explorar los menus y la navegación. Siéntete libre de dejar un comentario abajo si tienes alguna pregunta o comentario.