1. Web Design
  2. HTML/CSS
  3. HTML Templates

Implementando el patrón de etiquetas flotantes en un formulario

Utilizando el diseño de la interacción de un formulario móvil de Matt Smith como guía, crearemos una sorprendente interacción en un formulario web, el cual es hermoso y accesible mediante HTML, CSS y JavaScript.
Scroll to top

Spanish (Español) translation by Steven (you can also view the original English article)

Utilizando el diseño de la interacción de un formulario móvil de Matt Smith como guía, crearemos una sorprendente interacción en un formulario web, el cual es hermoso y accesible mediante HTML, CSS y JavaScript.


Visión general

El diseño de formularios y la interacción en la web pueden ser un tema delicado. Una multiplicidad de problemas de accesibilidad en los formularios y mejores prácticas pueden hacer que el diseño de una interacción atractiva en los formularios sea muy difícil, en contraposición al diseño de formularios en plataformas nativas.

Matt Smith creó recientemente una interacción de forma convincente que publicó en Dribbble:

Take a look at the original Dribbble shot on floatlabel.comTake a look at the original Dribbble shot on floatlabel.comTake a look at the original Dribbble shot on floatlabel.com
Echa un vistazo a la toma del dribbble original en floatlabel.com

Aunque está diseñada para una aplicación nativa de iOS, esta interacción en el formulario se puede recrear para la web utilizando HTML, CSS y Javascript, al mismo tiempo que satisface las preocupaciones de accesibilidad del formulario.

El concepto de etiqueta flotante ha despertado bastante atención, lo que ha llevado a debates y experimentos en toda la web.

En lugar de utilizar los mismos campos de formulario en el diseño de Matt, crearemos un formulario de contacto simple que puedes utilizar en tu propio sitio web. ¡Así que vamos a sumergirnos!


Anatomía del formulario

Primero, observemos y registremos las interacciones de formularios que Matt ha creado. Esto nos permitirá predeterminar cómo se debe marcar nuestro formulario. También nos dará una buena comprensión de cómo diseñar el formulario y crear sus interacciones con JavaScript.

Estructura del formulario

El formulario tiene los siguientes elementos que podemos traducir a HTML:

  • Elementos de tipo <label>
  • Elementos de tipo <input>
  • Elemento de tipo <textarea>
  • Atributos de marcador de posición - placeholder
form-elementsform-elementsform-elements

Interacciones de los elementos del formulario

Al observar las interacciones que Matt ha creado, podemos formular reglas para la interacción de los elementos del formulario que crearemos. Estas reglas serán útiles para crear nuestro marcado, reglas de estilo e interacciones de JavaScript.

  • al cargar la página:
    • Elementos de tipo <label>
      • Oculto, enfatizado con un color de resaltado.
    • Elementos <input> & <textarea>:
      • Mostrar el texto del marcador de posición del elemento.
  • cuando se enfoque:
    • Elementos de tipo <label>
      • Si el campo de entrada correspondiente de la etiqueta está vacío, ocultar la etiqueta. De lo contrario, restar importancia al color de la etiqueta.
    • Elementos <input> & <textarea>:
      • Si el campo está vacío, mostrar el texto del marcador de posición del elemento. De lo contrario, mostrar el texto introducido por el usuario.
  • cuando se presione una tecla:
    • Elementos de tipo <label>
      • Si el campo de entrada correspondiente de la etiqueta está vacío, ocultar la etiqueta. De lo contrario, mostrar la etiqueta.
    • Elementos <input> & <textarea>:
      • Si el campo está vacío, mostrar el texto del marcador de posición. De lo contrario, mostrar el texto introducido por el usuario.
  • en el desenfoque:
    • Elementos de tipo <label>
      • Si el campo de entrada correspondiente está vacío, ocultar la etiqueta. De lo contrario, restar importancia al color.
    • Elementos <input> & <textarea>:
      • Si el campo está vacío, mostrar el texto del marcador de posición. De lo contrario, mostrar el texto introducido por el usuario.

Ahora que hemos determinado los elementos HTML del formulario junto con sus reglas de interacción, podemos comenzar a crearlo.


HTML básico

Comencemos por obtener un código de inicio básico.

1
<!doctype html>
2
<html lang="en">
3
<head>
4
    <meta charset="utf-8">
5
    <title>Contact Me</title>
6
7
    <!-- Viewport tag to make things responsive -->
8
    <meta name="viewport" content="width=device-width, initial-scale=1">
9
    
10
    <!-- Link to the stylesheet we will create -->
11
    <link rel="stylesheet" href="styles.css">
12
13
    <!-- HTML5 shiv for older browsers -->
14
    <!--[if lt IE 9]>

15
        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>

16
    <![endif]-->
17
</head>
18
<body>
19
20
    <!-- Form Markup Will Go Here -->
21
22
    <!-- Google's hosted version of jQuery -->
23
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
24
    
25
    <!-- Link to the javascript file we will create -->
26
    <script src="scripts.js"></script>
27
</body>
28
</html>

Creando el marcado del formulario

Ahora vamos a crear el marcado para nuestro formulario:

1
<section class="container">
2
    <h1 class="title">Contact Me</h1>
3
    <form id="form" class="form" action="#" method="get">
4
        <ul>
5
            <li>
6
                <label for="name">Your Name:</label>
7
                <input type="text" placeholder="Your Name" id="name" name="name" tabindex="1"/>
8
            </li>
9
            <li>
10
                <label for="email">Your Email:</label>
11
                <input type="email" placeholder="Your Email" id="email" name="email" tabindex="2"/>
12
            </li>
13
            <li>
14
                <label for="message">Message:</label>
15
                <textarea placeholder="Message…" id="message" name="message" tabindex="3"></textarea>
16
            </li>
17
        </ul>
18
        <input type="submit" value="Send Message" id="submit"/>
19
    </form>
20
</section>

Aquí configuramos un contenedor de formulario con un encabezado de "Contáctame" y los elementos de formulario correspondientes estructurados dentro de los elementos de lista. Ten en cuenta que también asignamos el tipo de campo de correo electrónico mediante type="email". Esto proporciona teclados virtuales contextuales para dispositivos que los admiten, así como una validación simple compatible con el navegador para aquellos navegadores que admiten tipos de entrada HTML5. Para aquellos que no lo hacen, se convierte en un simple campo de texto.

Lo que tenemos ahora son los conceptos básicos de un formulario que funcionará en cualquier lugar y está estructurado adecuadamente para una accesibilidad simple.

basic-formbasic-formbasic-form

Nota: No cubriremos el envío de formularios del lado del servidor en este tutorial, así que no dudes en cambiar el método de envío del formulario según sea necesario.


Creando los estilos básicos de la página

Ya tenemos un formulario de trabajo en HTML. Ahora vamos a dar nuestro primer paso en la mejora progresiva: aplicar estilos CSS. Vamos a crear los estilos para que nuestro formulario sea más atractivo visualmente y, al mismo tiempo, recordemos mantener el formulario funcional y accesible.

Vamos a crear un estilo básico para la página y el contenedor de formularios. En el <head> de nuestro documento hemos creado un enlace a un archivo llamado styles.css, por lo que crearemos ese archivo ahora y lo guardaremos en la raíz de nuestro proyecto.

Comenzamos importando los estilos del restablecimiento CSS de Eric Meyer a nuestro propio archivo. Puedes tomar esos estilos aquí y copiarlos en tu propia hoja de estilo.

A continuación, vamos a crear algunos estilos generales para la página:

1
/* General

2
==================================== */
3
*, *:before, *:after {
4
    -moz-box-sizing: border-box; 
5
    -webkit-box-sizing: border-box; 
6
    box-sizing: border-box;
7
}
8
9
body {
10
    background: #eaedf1;
11
}
12
13
body, input, textarea {
14
    font: 1em/1.5 Arial, Helvetica, sans-serif;
15
}
16
17
.container {
18
    max-width: 25em;
19
    margin: 2em auto;
20
    width: 95%;
21
    
22
}
23
24
.title {
25
    font-size: 1.5em; 
26
    padding: .5em 0;
27
    text-align: center; 
28
    background: #323a45;
29
    color: white;
30
    border-radius: 5px 5px 0 0;
31
}

Notarás que usamos el enfoque sugerido por Paul Irish para el modelo de caja al modelar formularios: box-sizing: border-box;.

Ahora tenemos algo mejor, pero esto va a necesitar más trabajo.

basic-form-stylesbasic-form-stylesbasic-form-styles

Creando los estilos de los elementos del formulario

Vamos a aplicar algunos estilos a nuestros elementos de formulario. Esto hará que nuestro formulario se parezca más al de Matt.

En primer lugar, aplicaremos estilo a los elementos de la lista que contienen nuestros elementos de formulario.

1
/* Form

2
==================================== */
3
.form ul {
4
    background: white;
5
    margin-bottom: 1em;
6
}
7
8
.form li {
9
    border: 1px solid #ccc; 
10
    border-bottom: 0;
11
    margin-bottom: 0px; 
12
    position: relative; 
13
}
14
15
.form li:first-child {
16
    border-top: 0;
17
}
18
19
.form li:last-child {
20
    border-bottom: 1px solid #ccc;
21
}

Ahora tenemos todos nuestros elementos del formulario visualmente contenidos. Deberías tener algo como esto:

basic-form-list-stylesbasic-form-list-stylesbasic-form-list-styles

Creando los estilos de los elemento del formulario

Sigamos diseñando los elementos de nuestro formulario para que coincidan con el diseño de Matt y, al mismo tiempo, tengamos en cuenta las limitaciones de accesibilidad de la web.

Diseña los campos de entrada como elementos grandes a nivel de bloque en el formulario:

1
label, input, textarea {
2
    display: block; 
3
    border: 0;
4
}
5
6
input, textarea { 
7
    width: 100%; 
8
    height: 100%; 
9
    padding: 2.25em 1em 1em; 
10
    outline: 0;
11
}
12
13
textarea {
14
    height: 16em;
15
    resize: none; 
16
}

Deberías tener algo como esto:

form-input-stylesform-input-stylesform-input-styles

A continuación, agreguemos los estilos a los elementos de formulario <label> para que se estén situados aproximadamente a un tercio del camino desde la parte superior de cada bloque de entrada.

1
label {
2
    font-size: .8125em; /* 13/16 */ 
3
    position: absolute; 
4
    top: 1.23em;
5
    left: 1.23em;
6
    color: #f1773b;
7
    opacity: 1;
8
}

Nota: ¿Notaste la regla opacity? Usaremos esa propiedad (junto con la propiedad top) para animar el elemento <label> más adelante mediante JavaScript.

Deberías tener algo que empiece a parecerse mucho al diseño del formulario de Matt.

form-label-stylesform-label-stylesform-label-styles

A continuación, necesitamos diseñar nuestro botón de envío de formulario.

1
input[type="submit"] {
2
    background: #f1773b;
3
    margin-bottom: 1em;
4
    color: white;
5
    border-radius: 3px;
6
    padding: .75em;
7
    -webkit-appearance: none; /* remove default browser <button> styling */
8
    -webkit-transition: .333s ease -webkit-transform;
9
    transition: .333s ease transform;
10
}
11
input[type="submit"]:hover {
12
    -webkit-transform: scale(1.025);
13
    transform: scale(1.025);
14
    cursor: pointer;
15
}
16
input[type="submit"]:active {
17
    -webkit-transform: scale(.975);
18
    transform: scale(.975);
19
}

Observa que usamos el selector de atributos para apuntar solo al botón de envío. Hemos añadido algunos estilos básicos junto con una interacción simple en los estados :hover y :active (los navegadores más antiguos que no admiten transformaciones CSS simplemente no tendrán una interacción elegante, pero el formulario todavía funciona). Ahora deberías tener algo como esto:

form-submit-stylesform-submit-stylesform-submit-styles

Nuestro formulario ha sido diseñado de una manera similar al diseño de Matt, pero también adaptado para apaciguar las preocupaciones de accesibilidad de la web. Observa cómo, sin JavaScript, el formulario aún es accesible y los campos del formulario se muestran en todo momento. Para los usuarios con navegadores más antiguos que no admiten el atributo marcador de posición, aún podrán ver los campos del formulario y determinar qué información se les requiere.

Además, el <input> y los elementos <textarea></textarea> cubren todo el bloque del campo del formulario, por lo que el área de destino para cada entrada es bastante grande y accesible.

Por ejemplo, así es como se vería el formulario en este punto en Internet Explorer 8:

form-ieform-ieform-ie

Usando JavaScript para un formulario progresivamente mejorado

Ahora deberíamos empezar a pensar en cómo implementar la interacción que Matt creó usando JavaScript. Lo lograremos en gran medida agregando y eliminando clases CSS.

Notarás justo antes del cierre de la etiqueta <body> que ponemos un enlace a nuestro archivo JavaScript personalizado llamado scripts.js. Podemos crear ese archivo ahora y decirle al navegador que ejecute el código cuando el DOM esté listo:

1
$(document).ready(function(){
2
    // Our code here

3
});

Comprobando la compatibilidad con marcadores de posición

En caso de que no lo hayas notado, esta interacción depende en gran medida de la compatibilidad del marcador de posición. El atributo marcador de posición es ampliamente compatible con los navegadores modernos. Dado que nuestra interacción de formulario depende tanto de la compatibilidad con marcadores de posición, primero probaremos si el explorador admite texto en el marcador de posición. Si lo hace, implementaremos la interacción del formulario. Si no lo hace (IE8 & IE9) simplemente proporcionaremos la forma básica sin interacción JavaScript. ¡Mejora progresiva para la victoria!

En primer lugar, vamos a usar $.support() de jQuery para ver si el navegador admite texto en el marcador de posición. Esto establecerá $.support.placeholder en 'true' o 'false', dependiendo de la compatibilidad del explorador con el texto del marcador de posición.

1
// Test for placeholder support

2
$.support.placeholder = (function(){
3
    var i = document.createElement('input');
4
    return 'placeholder' in i;
5
})();

Si se admite el texto de marcador de posición, podemos ocultar los elementos <label> al cargar la página. Como se mencionó anteriormente, ocultar las etiquetas con JavaScript después de que se cargue la página garantiza que los navegadores con JavaScript desactivado (y aquellos sin soporte de marcador de posición) aún puedan usar el formulario.

1
// Hide labels by default if placeholders are supported

2
if($.support.placeholder) {
3
    $('.form li').each(function(){
4
        $(this).addClass('js-hide-label');
5
    });  
6
7
    // Code for adding/removing classes here

8
}

Observa que hemos agregado una clase a cada elemento de lista denominado js-hide-label. Esto se debe a que, según las reglas de interacciones al principio del tutorial, la apariencia predeterminada del formulario tiene ocultas las etiquetas de campo del formulario. La clase js-hide-label se aplicará a los elementos padres como <li> cuando el elemento descendiente <input> no tiene el contenido del usuario.

Para ayudar en la comprensión y el mantenimiento del código, estamos agregando un prefijo a las clases que agregamos o eliminamos con JavaScript mediante 'js-'. Agreguemos esa clase a nuestra hoja de estilo y usémosla para ocultar todos los elementos label descendientes de la vista. ¿Recuerdas cómo íbamos a usar la regla opacity? Aquí es donde lo usamos para ocultar los elementos <label>:

1
.js-hide-label label {
2
    opacity: 0; 
3
    top: 1.5em
4
}

Nota: La propiedad opacity es compatible con todos los navegadores modernos. IE8 no lo reconocerá, pero está bien porque IE8 tampoco admite atributos de marcador de posición, por lo que en realidad no estamos ejecutando JavaScript para aplicar la clase en IE8. ¡Esto un gana-gana!

Nota sobre las transiciones

Si observas de cerca, el diseño de interacción de Matt muestra que las etiquetas de los campos de formulario no solo aparecen y desaparecen, sino que lo hacen con un pequeño movimiento hacia arriba y hacia abajo. Debido a que los elementos de nuestra etiqueta están posicionados de manera absoluta, cuando agregamos una clase que cambia su posición superior (o izquierda, derecha o abajo), el navegador puede hacer la transición de ese efecto. Todo lo que tenemos que hacer es agregar una propiedad de transición a la propia etiqueta.

Volvamos a nuestro elemento label en el CSS y agreguemos una propiedad de transición para las propiedades top y opacity:

1
label {
2
    -webkit-transition: .333s ease top, .333s ease opacity;
3
    transition: .333s ease top, .333s ease opacity;
4
}

Esto permite que las etiquetas no solo aparezcan y desaparezcan suavemente, sino que se muevan hacia arriba y hacia abajo cuando se vuelven completamente opacas o transparentes, así:

form-hiding-labelform-hiding-labelform-hiding-label

Ahora deberías tener algo como esto cuando cargues la página (en un navegador moderno, por supuesto).

form-hidden-labelsform-hidden-labelsform-hidden-labels

Eliminando el color de resaltado

Como se mencionó anteriormente, estamos agregando y eliminando clases de los elementos <li> y dirigiéndonos a cualquier elemento hijo que necesite el estilo. En este punto (al cargar la página) hemos agregado una clase js-hide-label que oculta todas las etiquetas en el formulario. Ahora necesitamos una clase más para eliminar el color de resaltado de los elementos <label>:

1
.js-unhighlight-label label {
2
    color: #999 
3
}

Agreando detectores de eventos

Ahora tenemos un formulario que se mejora progresivamente y está listo para alguna interacción de JavaScript (en los navegadores modernos) cuando el usuario comienza a interactuar con el formulario.

Dentro del marcador de posición if que escribimos anteriormente, comencemos a agregar y eliminar nuestras clases js- en el momento adecuado. Primero, seleccionaremos nuestros elementos de formulario y agregaremos un detector de eventos en los eventos blur, focus, y keyup (usamos keyup en lugar de keydown o keypress ya que esos eventos se activarán prematuramente):

1
$('.form li').find('input, textarea').on('keyup blur focus', function(e){
2
    
3
    // Cache our selectors

4
    var $this = $(this),
5
        $parent = $this.parent();
6
7
    // Add or remove classes

8
    if (e.type == 'keyup') {
9
        // keyup code here                    

10
    } 
11
    else if (e.type == 'blur') {
12
        // blur code here

13
    } 
14
    else if (e.type == 'focus') {
15
        // focus code here

16
    }
17
});

He aquí una breve explicación de lo que estamos haciendo:

  • Seleccionamos todos los elementos de la lista que forman parte de nuestro formulario mediante $('.form li'). Entonces, dentro de esa selección, encontramos todos los elementos <input> y <textarea> mediante .find('input, textarea'). Esto asegura que la última entrada en nuestro marcado (el botón de enviar) no esté incluida en nuestra selección.
  • Almacenamos en caché los selectores que planeamos usar. Esta es una buena práctica de rendimiento. Además, prefijar el nombre de la variable con '$' nos permite saber que esa variable específica es un objeto jQuery.
  • Combinamos los eventos blur, focus, y keyup y simplemente comprobamos el tipo de evento usando e.type para determinar qué clases agregaremos o eliminaremos en momentos específicos.

Programando el evento keyup

De acuerdo con las reglas de interacción que establecimos al principio que corresponden al diseño de Matt, cuando un usuario comienza a escribir texto (no cuando se centran en el campo) queremos mostrar la etiqueta.

Por lo tanto, utilizando el evento keyup, cada vez que el usuario introduce un carácter podemos comprobar si el campo de entrada está en blanco (este código va dentro de if(e.type == 'keyup')):

1
if( $this.val() == '' ) {
2
    $parent.addClass('js-hide-label'); 
3
} else {
4
    $parent.removeClass('js-hide-label');   
5
}

Observa que nuestra lógica funciona así:

  • Si el valor de entrada está en blanco, se oculta la etiqueta agregando la clase 'js-hide-label'.
  • De lo contrario (si el valor de entrada no está en blanco), se muestra la etiqueta quitando la clase 'js-hide-label'.

Ahora deberías tener algo que funcione así al introducir o eliminar texto en un campo de entrada:

form-hiding-labelform-hiding-labelform-hiding-label

Programando el evento blur

Ahora, de acuerdo con nuestras reglas de interacción (de nuevo), sabemos que cuando un usuario mueve el foco de un campo de entrada al siguiente (evento de desenfoque o efecto blur), debemos restar importancia al color del elemento <label> dependiendo de si el usuario realmente ha introducido algo en el campo.

Dentro de else if (e.type == 'blur'), agregaremos el siguiente código:

1
if( $this.val() == '' ) {
2
    $parent.addClass('js-hide-label');
3
} 
4
else {
5
    $parent.removeClass('js-hide-label').addClass('js-unhighlight-label');
6
}

Observa que nuestra lógica funciona así:

  • Si el valor de la entrada estaba en blanco cuando el usuario quitó el foco, se oculta la etiqueta aplicando la clase js-hide-label.
  • De lo contrario (si el valor de la entrada no estaba en blanco cuando el usuario ha quitado el foco) se muestra la etiqueta quitando la clase js-hide-label y se le resta importancia al color de la etiqueta agregando la clase 'js-unhighlight-label'.

Ahora deberías tener algo que le reste importancia al color de la etiqueta cuando eliminas el foco, algo como esto:

form-blurform-blurform-blur

Programando el evento focus

Por último, necesitamos agregar un poco de lógica para cuando un usuario se centra en una entrada. Siguiendo nuestras reglas de interacción, vamos a usar el siguiente JavaScript dentro de la sección else if (e.type == 'focus'):

1
if( $this.val() !== '' ) {
2
    $parent.removeClass('js-unhighlight-label');
3
}

Nuestra lógica funciona así:

  • Si el valor de la entrada no está en blanco, se quita la clase 'js-unhighlight-label' del elemento padre.

Ahora, cuando un usuario se centra en un campo del formulario, si no está vacío, la etiqueta se enfatizará con el color de resaltado de la siguiente manera:

form-focusform-focusform-focus

Puntos adicionales

Hay mucho más que podríamos hacer en este formulario, incluida la adición de la validación del lado del cliente y del servidor. También podríamos crear algunas clases más para aplicar estilo a los valores de campo cuando son válidos o inválidos. Por ejemplo, podríamos agregar estilos a una clase 'js-error' que iría en el elemento padre <li> cuando el valor de la entrada no es válido de la siguiente manera:

1
.js-error {
2
    border-color: #f13b3b !important; /* override all cases */
3
}
4
.js-error + li {
5
    border-top-color: #f13b3b;
6
}
7
.js-error label {
8
    color: #f13b3b;
9
}

Estos tipos de estilos de validación podrían hacer que nuestro formulario se vea algo más parecido a esto:

bonus-form-errorbonus-form-errorbonus-form-error

Sin embargo, este tutorial estaba destinado a mostrar cómo podíamos crear un formulario accesible y mejorarlo progresivamente imitando el diseño de Matt. Y, tengo que decir, creo que lo hemos hecho bastante bien.

¡Siéntete libre de copiar, modificar o mejorar este formulario de cualquier manera que lo consideres adecuado en tus propios proyectos!


Enlaces útiles