BloomIT Digital Academy

Formularios de alto impacto

Publicado el 17/02/2019 por Germán Rodríguez
Tips

Foto de cover

En el diseño de las interfaces de usuario, el manejo de formularios puede ser el más complejo en su manipulación.
Los controles de formulario no nacieron para ser decorados con CSS, y tratar de salir del aspecto por defecto es una tarea que involucra, principalmente, la originalidad de combinar HTML, CSS y Javascript para -técnicamente- desarrollar nuestros propios controles de formulario (aprovechando o mejorando los existentes).

Entonces, en esta entrada, vamos a ver algunos trucos muy breves del manejo de formularios que son fundamentales para cualquier desarrollador web.

El select y todos los botones calculan distinto su tamaño final.

El box-sizing se encarga de determinar si al ancho del elemento se le sumará el padding y border (content-box) o si se descontarán del tamaño especificado en su ancho (border-box).
Como aparentemente el estándar de HTML lo escribieron dos personas que nunca hablaron entre ellas, los controles de tipo select y los botones (input o button), usan un algoritmo distinto al de los demás elementos.

De esta manera, suponiendo que a todos les damos las mismas propiedades CSS (mismo ancho, mismo padding y mismo borde), veremos que no miden lo mismo.

Los controles de formulario miden distinto tamaño

Este es el estilo aplicado a los cuatro elementos.

input, 
select, 
textarea{ border: 2px solid silver; padding: 10px; width: 380px; }

Por lo cual, deberíamos nivelar todos estos controles bajo un mismo box-sizing (por ejemplo el border-box), para que se vean del mismo tamaño.

El aspecto monoespaciado del textarea

Es muy discutible, en primera instancia, por qué si existen inputs de distintos tipos según lo que esperamos recibir (email, password, number, date, color, etc.), el control para texto multilínea dependa de una etiqueta textarea y no de un input (que su traducción literal es "ingresar un dato") de tipo multilínea.
Además, el textarea es una etiqueta que tiene un par de cierre, en lugar de cerrarse a sí misma, como sucede con los demás controles para el ingreso de texto libre.
Cuál habrá sido la lógica de ofrecer una etiqueta que abre y cierra, si en ningún caso se espera recibir una etiqueta hija (de hecho escribir cualquier elemento del HTML adentro de un textarea, se omite su renderizado y se comporta como texto plano), es todo un misterio.

Si escribimos este código:

<textarea name="area-texto">
	<h1>Soy un título</h1>
</textarea>

Tendremos esta respuesta:

El textarea no acepta elementos hijo

Y combinado a este comportamiento, el textarea es el único que no tiene value para indicar el texto con el que deberá autocompletarse -por ejemplo, si se tratase de un formulario de edición-, ese texto se define entre la apertura y cierre de la etiqueta.
Pero se debe tener mucho cuidado, porque el contenido se comporta como la etiqueta pre, donde los espacios, enter y tabulaciones, serán respetados en la muestra del contenido.
En consecuencia, escribir el contenido del formulario dejando un enter y tabulando -como buen programador- generaría espacios adicionales a la hora de enviar ese contenido a una base de datos, como también podemos observar en la imagen anterior, donde antes del encabezado tenemos un espacio abismal, producto del enter y tabulación adentro del textarea.

Ah, y no puedo omitir que estamos obligados a definir una familia tipográfica, porque por defecto se aplica una fuente monoespaciada.

Los radio y checkbox no son muy CSS-Friendly

Uno de los principales problemas con el manejo de los input de tipo checkbox y radio, es que el navegador se encarga de definir cómo se verán.
Es muy difícil (casi imposible) salirse del formato por defecto que tienen estos componentes para poder implementar un aspecto personalizado que vaya de la mano con el estilo de la página web.

Fancy checkbox y radio solo con CSS

Si queremos lograr un diseño como el anterior, debemos diseñar los controles con alguna herramienta como Photoshop o Illustrator y exportar las imágenes de los diferentes estados (seleccionado y no seleccionado) para luego aplicarlas como imagen de fondo de algún elemento que esté a continuación del control de selección, como podría ser en este ejemplo una etiqueta label.

<div>
	<input type="radio" name="radio_group" value="opcion 1" id="radio1" />
	<label for="radio1">Opcion 1</label>
</div>
<div>
	<input type="radio" name="radio_group" value="opcion 2" id="radio2" />
	<label for="radio2">Opcion 2</label>
</div>
<div>
	<input type="radio" name="radio_group" value="opcion 3" id="radio3" />
	<label for="radio3">Opcion 3</label>
</div>
<div>
	<input type="radio" name="radio_group" value="opcion 4" id="radio4" />
	<label for="radio4">Opcion 4</label>
</div>
<div>
	<input type="radio" name="radio_group" value="opcion 5" id="radio5" />
	<label for="radio5">Opcion 5</label>
</div>

Dado que CSS reconoce que los controles de tipo radio y checkbox tienen un estado :checked, solo cambiamos la imagen de fondo del label cuando el control está tildado, y dado que el label está vinculado al input por medio del atributo for, podemos esconder el input que, al tocar su label asociado, estaremos interactuando con el campo de formulario.

div{ 
	margin-bottom: 4px; 
}

/* 
	A los label que son hermanos de un radio, 
	le damos una imagen de fondo y un efecto 
	gris como "apagado"
*/
div [type=radio] + label{
	font-family: 'Trebuchet Ms';
	color: #F51D1E; 		
	display: inline-block;	
	background: url( 'http://ejemplos.bitdigitalacademy.com/cb/check_no.png' ) left center no-repeat;
	padding-left: 24px;
	filter: grayscale(1);
}

/*
	Si el radio tiene el estado :checked 
	cambiamos la imagen de fondo y quitamos 
	el efecto grisado
*/
div [type=radio]:checked + label{
	background-image: url( 'http://ejemplos.bitdigitalacademy.com/cb/check_si.png' );
	filter: grayscale( 0 );
}

/* como la imagen de fondo hace el efecto, el radio lo ocultamos */
div [type=radio]{
	display: none;
}

Esta técnica la hemos explicado con más detalle teórico en nuestro BitChannel, puedes ver el video en este enlace: YouTube - Fancy Checkbox.

El placeholder no reemplaza al label

Son muchos los casos en los cuales se quiere prescindir del texto que indica lo que se está esperando en un campo, y se le delega esta responsabilidad al atributo placeholder que -para quienes no conozcan el mismo- se encarga de mostrar un texto temporal, que será eliminado desde el momento que el control tenga algún contenido (aunque el mismo sea un espacio).

La limitación del placeholder, está en los casos en que el control muestre algún contenido previo (como puede suceder en el caso de los formularios de edición), donde perderemos la referencia de lo que está mostrando cada elemento del formulario y tendremos que apelar a la lógica deductiva tras analizar el texto mostrado, o eliminar el contenido del mismo para que se restablezca el placeholder que indicaba lo que ese control estaba esperando.

Para buscar un punto intermedio, Google popularizó los placeholder dinámicos que -al recibir el foco del usuario- se desplazan hacia arriba unos píxeles dejando libre el área de escritura sin perder la información de lo que estamos completando.

Efecto focus del placeholder en GMAIL

Lógicamente, esto no se hace por medio del atributo placeholder, sino con un label (o span, o la etiqueta a gusto del programador) ubicada con un position sobre el control de formulario y desplazada con una sutil transición al hacer foco sobre el elemento.

La estructura del HTML es bastante simple, solo el control de formulario y su respectivo span (o label) que indique lo que estamos esperando, ambas etiquetas contenidas en un elemento padre que emulará al campo a completar.

<div class="fake_placeholder">
	<label>
		<span>Tu usuario</span>
		<input type="text" name="usuario" autocomplete="off" />
	</label>
</div>

<div class="fake_placeholder">
	<label>
		<span>Tu clave</span>
		<input type="password" name="clave" autocomplete="off" />
	</label>
</div>

En este caso, uso la etiqueta div como separador de los campos de formulario que el usuario completará, el label va a generar el borde gris -dándo la sensación que se trata del input que el usuario completará- y el span será el falso placeholder animado.

Luego, en CSS superpondremos los span por encima de los input. Para no cometer errores afectando los elementos equivocados, le asigné a cada div que contiene nuestro custom control, una clase que filtrará cuáles elementos serán afectados por este efecto.
Para lograrlo, los span tienen asignada una transición que durará un cuarto de segundo en cambiar las propiedades que varíen entre el estado de reposo del campo y su interacción por parte del usuario.

/* Le quitamos el formato a los controles */
input, select, textarea, span{ 
	border: none; 
	background: white;
	box-sizing: border-box;
	font-family: Verdana;
	font-size: 12px;
	line-height: 12px;
	outline: none; 
	padding: 0;
	resize: none; 
	width: 300px;
}

.fake_placeholder{ 
	margin-bottom: 10px; 
}

/* el label emula el aspecto del input */
.fake_placeholder label{
	border: 2px solid silver;
	display: inline-block;
	padding: 10px;
	position: relative;
}

.fake_placeholder span{
	color: silver;
	display: inline-block;
	left: 2px;
	padding: 5px;
	position: absolute;
	transition: 0.25s;
	top: 9px;
	width: auto;
}

.fake_placeholder span.reubicar{
	color: blue;
	font-size: 10px;
	top: -12px;
}

Dado que el span se va a ubicar por sobre el control de formulario, el label tendrá una posición relativa para que sea el contexto top, bottom, left o right del span que se ubicará por una posición absoluta.
La clase reubicar, creada especialmente para los span, será la encargada de posicionar el label por encima del control de formulario, de reducir el tamaño tipográfico y cambiar el color del mismo.

Y finalmente, la interacción que hace el movimiento de los label, no puede ser con CSS, ya que necesitamos saber si el input tiene o no contenido (porque, de tenerlo, no volveremos a superponer el label); en este caso será Javascript el encargado de poner el label en el top si estamos escribiendo en el control o si nos fuimos del campo habiendo escrito algo, y volverá a superponerlo si nos fuimos sin haber escrito nada o habiendo borrado el texto anterior.

const inputs = document.querySelectorAll( '.fake_placeholder input' );

inputs.forEach( input => {
	//cuando entramos en el input 
	input.onfocus = ( ) => {
		//al elemento anterior (el span) le agregamos la clase que la reubica en top
		input.previousElementSibling.classList.add( 'reubicar' );
	}
	
	//cuando salimos del input
	input.onblur = ( ) => {
		//si no hay texto, le quitamos la clase reubicar, 
		//para que se superponga con el input
		if( input.value.trim( ).length == 0 )
		input.previousElementSibling.classList.remove( 'reubicar' );
	}
} );

Este mismo ejemplo lo puedes ver en YouTube, donde hemos publicado el video Youtube - Placeholder animados, explicando en detalle el paso a paso de esta técnica.

Como podemos ver, entonces, sin importar el diseño que queramos implementar, siempre habrá una solución simple (incluso sin vernos en la obligación de implementar Framework alguno) para llegar a formatear los formularios de la manera en que planificamos nuestros diseños originales.
¿Lo importante? Aprender a aprovechar todas las herramientas que los lenguajes de FrontEnd nos ofrecen para lograr el objetivo propuesto.