Capítulo 4 Qué es Modernizr

Modernizr es una librería JavaScript que nos permite conocer la compatibilidad del navegador con tecnologías HTML5 y CSS3, lo que nos permitirá desarrollar sitios web que se adapten a las capacidades cada navegador.

Este framework es un paquete de detección de las capacidades de un navegador relativas a HTML5 y CSS3, esto es, una librería JavaScript que nos informará cuáles de las funcionalidades de estas tecnologías están disponibles en el navegador del usuario, para utilizarlas, o no, en cada caso.

Sabiendo que nuestro navegador soporta ciertas capacidades de CSS3 o de HTML5, podremos utilizarlas con libertad. De modo contrario, si sabemos que un navegador no es compatible con determinada funcionalidad, podremos implementar variantes que sí soporte y así crear sitios web que se adaptan perfectamente al cliente web de cada visitante.

Existen dos herramientas principales en Modernizr que se pueden utilizar para detectar las funcionalidades que están presentes en un navegador. Una la podemos utilizar a través de JavaScript y otra directamente sobre código CSS. En resumen, con Modernizr podemos detectar las funcionalidades disponibles de CSS3 y HTML5.

4.1 Añadir Modernizr a una página

El primer paso consistirá en descargar el archivo con el código fuente de Modernizr. Se trata de un archivo con código JavaScript que podemos encontrar en dos variantes:

  • Development: contiene el código fuente completo, sin comprimir y con comentarios. Debemos utilizar esta variante únicamente en desarrollo o cuando queremos acceder a su código, para comprenderlo o ampliarlo.
  • Production: es recomendable (o más bien obligatorio) utilizar esta variante cuando pasamos a un entornos de producción. Al descargarnos Modernizr, tenemos la posibilidad de generar una librería únicamente con las funcionalidades que queremos detectar, lo que nos permitirá ahorrarnos una importante cantidad de KB innecesarios.

Una vez que hemos descargado nuestra librería, debemos incluirla en el código HTML de la página, de la misma manera que incluimos scripts JavaScript.

<script src="/js/lib/vendor/modernizr-custom.min.js"></script>

Según podemos leer en la documentación de Modernizr, se aconseja colocar el script dentro del HEAD, porque debe cargarse antes del BODY de la página, debido a un componente que quizás utilicemos, para permitir HTML5 en Internet Explorer, llamado HTML5 Shiv. Además, se recomienda colocarlo después de los estilos CSS para evitar un comportamiento poco deseable llamado FOUC, por el cual puede mostrarse, por un pequeño espacio de tiempo, la página sin los estilos CSS aplicados.

A partir de este momento tendremos disponibles nuestros scripts de detección de funcionalidades así como una serie de clases CSS que nos ayudarán a aplicar estilos solo cuando los navegadores los soporten.

4.2 Objeto Modernizr

Cuando tenemos Modernizr cargado en nuestra página, se crea automáticamente un objeto JavaScript que tiene una serie de propiedades que nos indican si están o no disponibles cada una de las funcionalidades presentes en CSS3 y HTML5. Las mencionadas propiedades contienen simplemente valores booleanos (true o false) que podemos consultar para saber si están o no disponibles las funcionalidades que deseamos utilizar.

El uso es tan sencillo como se indica a continuación:

if (Modernizr.boxshadow) {
   // Podemos aplicar sombras!
} else {
   // La propiedad box-shadow no está disponible
}

Aquí estamos consultando la propiedad boxshadow del objeto Modernizr. Esta propiedad nos indica si el navegador es compatible con el atributo box-shadow de CSS3, que sirve para crear cajas de contenido con sombreado.

Ahora veamos otro ejemplo similar que detectaría si está disponible el elemento canvas del HTML5.

if (Modernizr.canvas) {
   // Podemos utilizar canvas!
} else {
   // El elemento canvas no está disponible
}

Este es un simple ejemplo que comprueba si están disponibles ciertas propiedades y funcionalidades de CSS3 y HTML5. Lógicamente, tendremos que desarrollar las funcionalidades que correspondan en cada caso. El listado completo de propiedades del objeto para la detección de funcionalidades HTML5 y CSS3 se puede encontrar en la propia documentación de Modernizr.

4.3 Clases CSS en Modernizr

Cuando tenemos Modernizr cargado en nuestra página, éste crea automáticamente una serie de clases que asigna al elemento html del documento. Cada una de estas clases hace referencia a las características que soporta el navegador, permitiendo desde CSS adaptar la interfaz según las funcionalidades. Un ejemplo de las clases que crea en un navegador de escritorio moderno:

<html lang="en" class=" js flexbox canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">
<head>
    ...
    <script src="/js/lib/vendor/modernizr-custom.min.js"></script>
</head>
<body>
    <div class="elemento"></div>
</body>
</html>

Todo el proceso es automático y la creación de cada una de esas clases se realizará únicamente en caso de que el navegador sea compatible con cada una de las características de CSS3 y HTML5.

La manera de utilizar estas clases es muy sencilla. Pensemos en que queremos aplicar sombra a un elemento con CSS3 en los navegadores que lo permitan y emular ese sombreado por medio de estilos CSS clásicos en los navegadores que no soporten el atributo box-shadow. Lo único que tenemos que hacer es aplicar los estilos clásicos al elemento que deseemos:

.elemento{
   border-left: 1px solid #ccc;
   border-top: 1px solid #ccc;
   border-bottom: 1px solid #666;
   border-right: 1px solid #666;
}

Posteriormente, si nuestro navegador es compatible con el atributo box-shadow de CSS3, Modernizr habrá incluido la clase "boxshadow" en el elemento html. Nosotros podemos utilizar dicha clase CSS para aplicar estilos que sabemos que solo acabarán afectando a los navegadores que soporten el atributo box-shadow.

.boxshadow .elemento{
   border: 1px solid #ccc;
   box-shadow: #999 3px 3px 3px;
}

Como se puede ver, hemos sobrescrito la regla CSS para el borde y además hemos aplicado la propiedad box-shadow. El efecto conseguido es que los navegadores modernos, que son capaces de procesar el atributo box-shadow, mostrarán una sombra CSS3 y los no compatibles con esta propiedad al menos mostrarán unos estilos para los que sí son compatibles.

Ejercicio 3

Ver enunciado

4.4 El método load()

El método Modernizr.load() es una sencilla manera para cargar librerías sólo cuando los usuarios las necesitan, es decir, cuando una funcionalidad en concreto está (o no) disponible. Es una buena manera de ahorrar ancho de banda y mejorar un poco más el rendimiento de la aplicación.

Por ejemplo, pensemos en que estamos desarrollando una aplicación basada en el API de geolocalización de HTML5. Con Modernizr podemos saber si el navegador ofrece soporte a ese API, mediante la propiedad Modernizr.geolocation. Si deseamos cargar unos recursos u otros dependiendo de la disponibilidad de esta funcionalidad, el método Modernizr.load() nos podrá ahorrar algo de código fuente y de paso acelerar nuestra página en algunas ocasiones. Con éste método podemos indicar a los navegadores que no soporten ese API que carguen el polyfill correspondiente, de modo que se pueda utilizar esa característica de HTML5 en ellos también.

La sintaxis de Modernizr.load() es bastante sencilla de comprender. Un ejemplo sencillo:

Modernizr.load({
  test: Modernizr.geolocation,
  yep : 'geo.js',
  nope: 'geo-polyfill.js'
});

En este ejemplo, se decide que script se debe cargar, en función de si la geolocalización esta soportada por el navegador o no. De esta manera, nos ahorramos el tener que descargar código que el navegador no soporta y por lo tanto, no necesita.

Modernizr.load() es simple y eficaz, pero podemos utilizarlo de manera más compleja, como se muestra en el siguiente ejemplo:

// Give Modernizr.load a string, an object, or an array of strings and objects
Modernizr.load([
  // Presentational polyfills
  {
    // Logical list of things we would normally need
    test : Modernizr.fontface && Modernizr.canvas && Modernizr.cssgradients,
    // Modernizr.load loads css and javascript by default
    nope : ['presentational-polyfill.js', 'presentational.css']
  },
  // Functional polyfills
  {
    // This just has to be truthy
    test : Modernizr.websockets && window.JSON,
    // socket-io.js and json2.js
    nope : 'functional-polyfills.js',
    // You can also give arrays of resources to load.
    both : [ 'app.js', 'extra.js' ],
    complete : function () {
      // Run this after everything in this group has downloaded
      // and executed, as well everything in all previous groups
      myApp.init();
    }
  },
  // Run your analytics after you've already kicked off all the rest
  // of your app.
  'post-analytics.js'
]);

Ejercicio 4

Ver enunciado