Detección nativa de características CSS a través de la regla @supports
Chris David Mills. 21 de noviembre de 2012. Artículo original en inglés
Introducción
Mientras sigue habiendo navegadores de diferentes grados de soporte a los estándares para navegar por la web (desde navegadores modernos decentes a antiguas tartanas como IE6), nos sentimos bastante cómodos con la idea de enviar código diferente a diferentes navegadores para proporcionar experiencias de usuario diferentes pero siempre aceptables. Esto se hace de formas diversas, pero en general se basa bien en la detección del navegador, algo bastante propenso a errores, o en la deteccin de características, que resulta más inteligente y robusta.
La detección de características normalmente se hace escribiendo tu propio JavaScript para comprobar si una propiedad fundamental, método, etc de la función que estás detectando existe o puede ser utilizada, o mediante el uso de una biblioteca ya existente de detección de caractersticas, como el excelente Modernizr. Modernizr ofrece pruebas de características y mecanismos para aplicar selectivamente CSS y JavaScript basándose en los resultados de dichas pruebas, para toda una serie de características diferentes de HTML5 y CSS3.
Esto es realmente útil, pero mucha gente se pregunta si veremos mecanismos nativos para hacer estas pruebas de funciones. La buena noticia es que ya estamos empezando a hacerlo. En este artículo se analiza la regla CSS @supports
, parte del Módulo de Reglas Condicionales de CSS3 Nivel 3, que proporciona un mecanismo perfecto para aplicar selectivamente CSS basándose en el soporte de características. Aquí veremos la sintaxis básica, junto con un ejemplo de aplicación.
Nota
@supports
actualmente funciona en Opera 12.10 y Firefox Aurora, y los navegadores que no admiten @supports sencillamente pasan por alto completamente el código dentro de esos bloques. Esto significa que ya tiene algunas aplicaciones útiles, pero que si no se ajusta a tu situación, puedes seguir usando Modernizr.
Sintaxis de @supports
@supports
toma la forma de un bloque que realiza una prueba y luego ejecuta reglas CSS normales dentro del bloque en función de si la prueba devuelve un valor de verdadero o falso. En este caso, la prueba es siempre una o más declaraciones de CSS, y el navegador devuelve el valor 'true' si es compatible con la declaración o declaraciones indicada. Por ejemplo:
@supports (display:flex) {
section { display: flex }
...
}
Las reglas dentro de este bloque se aplicar si el navegador soporta display: flex
.
@supports
tambin proporciona una palabra clave not
para la aplicación de estilos cuando las caractersticas no están soportadas. Podrás dar algún estilo alternativo específico para los navegadores que no admitan display: flex
de la siguiente manera:
@supports not (display: flex) {
// dar layout de forma alternativa
// tal vez con floats
}
@supports
también da palabras clave or
y and
, para la aplicación de estilos sólo si el navegador pasa dos o más pruebas especficas de apoyo, o si el navegador pasa alguna de entre un número de pruebas de soporte diferentes.<(/p>
Por ejemplo, Flexbox sólo funciona sin prefijos en Opera (Mobile y Next) y en la 'preview' de IE10. Para comprobar si el navegador es compatible con cualquiera de las versiones con prefijo o la versión sin prefijo, podría hacerse lo siguiente:
@supports (display: -webkit-flex) or
(display: -moz-flex) or
(display: flex) {
section {
display: -webkit-flex;
display: -moz-flex;
display: flex;
...
}
}
Para ver un ejemplo de and
, es posible que queramos aplicar un diseño de varias columnas y las reglas asociadas únicamente cuando haya soporte para la versión sin prefijo de las propiedades column-width
y column-span
, puesto que los navegadores que soportan multi-col
con prefijos actualmente no son compatibles con column-span
, lo que limita su utilidad:
@supports (column-width: 20rem) and (column-span: all) {
div { column-width: 20rem }
div h2 { column-span: all }
div h2 + p { margin-top: 0; }
...
}
La última cosa a tener en cuenta sobre la sintaxis de @supports
es que no se permite mezclar and
, or
y not
sin el uso de una capa de paréntesis para dejar clara la prioridad. Así, por ejemplo, podrías querer aplicar una animación con una transformación 3D a un elemento sólo si el navegador soporta tanto la animación 3D como la transformación:
@supports ((-webkit-animation-name: my-animation) and (-webkit-transform: rotate3D(1,2,4,90deg))) or
((-moz-animation-name: my-animation) and (-moz-transform: rotate3D(1,2,4,90deg))) or
((-ms-animation-name: my-animation) and (-ms-transform: rotate3D(1,2,4,90deg))) or
((-o-animation-name: my-animation) and (-o-transform: rotate3D(1,2,4,90deg))) or
((animation-name: my-animation) and (transform: rotate3D(1,2,4,90deg))) {
// añadir aquí la animación
}
Un ejemplo de @supports
Para demostrar el uso real de @supports
, reescribir un ejemplo que escrib por primera vez para mi libro (Practical CSS3: develop and design) — un ejemplo simple de tarjeta con rotación 3D que utiliza Modernizr para proporcionar una experiencia alternativa a los navegadores que no soportan transformaciones 3D (como Opera, en el momento de la escritura: lo tenemos en preparación) o transformaciones 2D (sencillamente aplico un montón de padding por la izquierda en la parte delantera de la tarjeta cuando pasamos por encima para mostrar el reverso). Puedes ver el ejemplo de la tarjeta Modernizr en funcionamiento, y ver la diferencia entre la experiencia de los diferentes niveles de soporte en las figuras 1 a 3.
Figura 1: En los navegadores con soporte para transformaciones 3D la tarjeta gira con una bonita animación.
Figura 2: En los navegadores que no soportan transformaciones 3D pero que sí soportan transformaciones 2D, el anverso de la tarjeta se mueve con una bonita animación para revelar la parte posterior.
Figura 3: En los navegadores que no soportan transformaciones 3D ni 2D, la parte delantera de la tarjeta sencillamente se mueve para mostrar la parte de atrás sin animación.
En mi ejemplo con Modernizr trabajo de adelante hacia atrás, proporcionando el código de reserva para los navegadores que no soportan transformaciones 3D, a continuación proporcionando una experiencia realmente básico para los navegadores que tampoco admitan transformaciones 2D. En el ejemplo con @supports
trabajo al revés, con un enfoque más en la línea de la mejora progresiva: en primer lugar proporcionamos una experiencia realmente básica para mostrar ambos lados de la tarjeta de visita que funciona en casi todos los navegadores:
/* || Para los navegadores que no soportan transformaciones 2D ni 3D */
#wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
margin-left: -350px;
}
Los navegadores más antiguos sólo llegarán hasta aquí, y luego harán caso omiso de todo lo que hay dentro de la regla @supports
.
A continuación tenemos un conjunto de reglas para los navegadores que soportan transformaciones 2D:
/* || Para navegadores con soporte para transformaciones 2D */
@supports (-webkit-transform: rotate(-30deg)) or
(-moz-transform: rotate(-30deg)) or
(-ms-transform: rotate(-30deg)) or
(-o-transform: rotate(-30deg)) or
(transform: rotate(-30deg)) {
#inner-wrapper #front {
-webkit-transition: 0.8s all ease-in;
-moz-transition: 0.8s all ease-in;
-ms-transition: 0.8s all ease-in;
-o-transition: 0.8s all ease-in;
transition: 0.8s all ease-in;
}
#wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
margin-left: 0;
-webkit-transform: rotate(-30deg) translate(-50%,-100%);
-moz-transform: rotate(-30deg) translate(-50%,-100%);
-ms-transform: rotate(-30deg) translate(-50%,-100%);
-o-transform: rotate(-30deg) translate(-50%,-100%);
transform: rotate(-30deg) translate(-50%,-100%);
}
}
Y, finalmente, un conjunto de reglas para navegadores con soporte para transformaciones 3D:
/* || Para navegadores con soporte para transformaciones 3D */
@supports (-webkit-transform: rotateX(0deg)) or
(-moz-transform: rotateX(0deg)) or
(-ms-transform: rotateX(0deg)) or
(-o-transform: rotateX(0deg)) or
(transform: rotateX(0deg)) {
#front, #back {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
-o-backface-visibility: hidden;
backface-visibility: hidden;
}
#front {
-webkit-transform: rotateX(0deg);
-moz-transform: rotateX(0deg);
-ms-transform: rotateX(0deg);
-o-transform: rotateX(0deg);
transform: rotateX(0deg);
}
#back {
-webkit-transform: rotateX(180deg);
-moz-transform: rotateX(180deg);
-ms-transform: rotateX(180deg);
-o-transform: rotateX(180deg);
transform: rotateX(180deg);
}
#wrapper:hover #inner-wrapper, #wrapper:focus #inner-wrapper {
-webkit-transform: rotateX(180deg);
-moz-transform: rotateX(180deg);
-ms-transform: rotateX(180deg);
-o-transform: rotateX(180deg);
transform: rotateX(180deg);
}
#wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
-webkit-transform: none;
-moz-transform: none;
-ms-transform: none;
-o-transform: none;
transform: none;
}
}
Ejemplo de funcionamiento en vivo
window.supportsCSS();
Opera 12.10 es actualmente el único navegador con soporte para la correspondiente API JavaScript de @supports
, que permite ejecutar código de forma condicional dependiendo de si el navegador soporta o no una determinada característica CSS. Por ejemplo, aqu está mi ejemplo inicial simple reescrito en JavaScript:
var flexy = window.supportsCSS('display:flex');
if(flexy) {
alert('¡Soporto Flexbox!');
}
Nota
En la especificación veréis que la sintaxis aparece como CSS.supports, no window.supportsCSS. Esto se debe a que implementamos una versión un poco más antigua de la especificacin, además de que nos preocupaban las implicaciones para la compatibilidad de un objeto llamado CSS en el espacio de nombres global. Lo que finalmente se establezca está aún por verse.
Resumen
Y así llega a su fin nuestro estudio de @supports
. Esta característica es muy interesante, ya que puedes ser muy preciso con la detección de características y entrega de CSS a implementar. Un problema es, por supuesto, el hecho de que los navegadores antiguos a los que se quiere dar estilos alternativos no soportan @supports
, pero aún así resulta útil hoy en día. En cualquier caso, esperamos que la la característica se vuelva más útil en el futuro.