soy Kseso y esto EsCSS

La función Css element(): conexión cuántica entre elementos

iamvdo Traducción al español del artículo original de Vincent De Oliveira CSS element() function [ing]. Ilustrado con demos que emulan de forma simple viejos y complejos efectos como plegados y fondos animados.
Todo el crédito, imágenes y demos incluidas, ha de ser otorgado a su auto original (ver pie del artçiculo).

La función Css element(): conexión cuántica entre elementos

✎ 1
COLABORACIÓN AUTOR INVITADO
La función Css element(): estilos cuánticos entre elementos

En Julio escribí sobre tecnicas avanzadas de filtros Css, como backdrop-filter y fillter().

Hoy quiero compartir una novedad Css mucho más impresionante. Pero antes de comenzar, permíteme una advertencia: la propiedad que te voy a mostrar sólo es soportada por FIrefox de momento y ningún otro navegador ha demostrado interés por ella. Quizás esto cambie en un futuro próximo. Realmente lo espero. Así que id y difundid la buena nueva.

Si tienes Firefox instalado quizás quieras abrirlo para ver las demos funcionando en vivo. Si no, he añadido vídeos.

element()

El documento de nivel 4 CSS Image Values and Replaced Content introduce la función Css element(). Esta función fue definida previamente en el mismo documento en su Nivel 3 y así Firefox le dio soporte desde su versión 4 (¡Mayo de 2011!).

Para hacerlo sencillo, esta función renderiza cualquier parte de una web como una imagen en directo. ¡A. Live. Image!. Tal como se muestra un elemento del DOM al ser dibujado por el navegador obtienes una imagen de él. Y cada cambio que haya en el elemento se reflajará en la imagen al mismo tiempo, incluso la selección de texto.

Cuando descubrí esta propiedad allá en 2011 no me lo podía creer. ¿Cu.an genial es eso? ¿Cómo puede ser esto posible?

Bueno, funciona y la sintaxis es muy sencilla. sólo referencia al elemento del que quieres tener la imagen en vivo usando su atributo id. Por ejemplo, tengamos un texto y una imagen en div#css-sourde. La imagen en vivo de este elemento puede ser usada como fondo (background) en div#css-result.

<div id="css-source"> <p>Lorem ipsum</p> <img src="" alt="" /> </div> <div id="css-result"></div> #css-result { background: element(#css-source); background-size: 50% 50%; }

Como element() cea una imagen, puedes usas cualquier propiedad Css que conozcas para controlarla, como background-repeat, background-size, étc.

Aquí tienes una demo en vivo sobre lo que estoy diciendo:

See the Pen LVKVON by Kseso (@Kseso) on CodePen.


Vista en vivo en Firefox

Ten presente que cualquier parte de un sitio web puede ser referenciado, incluso todo el sitio si así lo necesitas. No obstante, ten cuidado, el elemento que muestra la imagen puede ser hijo del mostrado y aparecer varias veces. Firefox resuelve bien estas referencias circulares.

element() lleva el diseño Css aun nuevo nivel de manera sencilla. Algunas ideas que me vienen a la cabeza (algunas ya las he utilizado en los últimos 4 años):

Ten presente:

Reflections

Todos sabemos que las reflexiones pasaron de moda tiempo ha (¡Hola web 2.0!) pero es un buen punto de inicio para comprender mejor a element(). La siguiente demo está compuesta por una imagen con su figcaption, ambas dentro de un elemento figure. La función element() es utilizada en el fondo del pseudoelemento ::after para tener una vista en vivo de /lt;figure>, girada sobre el eje Y y enmascarada usando una máscara SVG.

Todo el efecto está incluido en una regla @supports por lo de la mejora progresiva.

<figure class="reflection" id="css-element"> <img src="image.jpg" alt=""> <figcaption>San Francisco, CA</figcaption> </figure> @supports (background: element(#css-element)) { .reflection::after { background: element(#css-element); transform: scaleY(-1); mask: url('#mask'); opacity: .3; } }

See the Pen qdzOdr by Kseso (@Kseso) on CodePen.

Vaaale. Ya se que estás aburrido de ver este efecto. Profundicemos.

Efecto 3D de papel doblado

En algunos efectos avanzados, hay veces que hay que lidiar con contenido duplicado, y la opción razonable ahí es javascript.

Es bastante sencillo si el contenido es estático (imágenes, texto, étc) pero se complica con los dinámicos.

Con element() es pan comido.

Por ejemplo, puedes plegar en dos este formulario de accesso a Twitter fácilmente (haz :hover sobre él con Firefox):

See the Pen jPjbBN by Kseso (@Kseso) on CodePen.


Vista en vivo en Firefox

Permíteme que insista, digo, explicarlo:

  • Se crea formulario Html de acceso y se posiciona
  • A continuación se añade una capa de máscara sobre él, con lo que el formulario ya no es visible.
  • Se añaden los dos pseudoelementos (::before y ::after) del formulario sobre la máscara.
  • Cada elemento es posicionado en el mismo punto que el formulario y referenciado usando element()
  • Entonces se aplican las transformaciones, animaciones y filtros Css a los dos pseudos.
  • Además se utiliza pointer-events: none para que los eventos apliquen sobre el formulario oculto. Así es plenamente funcional.
  • Todo lo anterior tiene un final feliz sólo si element() tiene soporte, dentro de @supports

Yendo un poco más allá podemos plegar cualquier cosa contenida en la página, como un mapa interactivo:

See the Pen NqZGmq by Kseso (@Kseso) on CodePen.


Resultado en Firefox

Fondos animados

Un efecto simple también podría ser la creación de fondos animados. Vale, es posible que pienses en un fondo animado con el viejo GIF, pero element() abre nuevas posibilidades, como usar los elementos video, canvas o svg. Combinando video, canvas y contenido duplicado se puede crear este alocado efecto de plegado de más de 30 partes donde se puede dibujar mientras sucede la animación. ¡Muy divertido!:

See the Pen OVeMPJ by Kseso (@Kseso) on CodePen.


Resultado en Firefox

Habrás observado que esta demo también funciona en navegadores basados en Webkit. Es por:

  • Reemplacé el elemento video por un GIF animado y así funciona como fondo Css. El inconveniente es que el tamaño del GIF es muy pesado comparado con el vídeo: ~4MB (GIF) vs ~400KB (MP4) y ~600KB (WEBM). Así que en este caso reduje marcos (frames).
  • He usado -webkit-canvas() que es similar a element(), pero limitado a <canvas>, claro. No es tan mala solución en este caso porque estoy referenciando un canvas. Sin embargo ten cuidado. Esta función además de no estándar es obsoleta.

Falso backdrop-filter

Con element() se hace sencillo crear una solución a backdrop-filter, y también extender el soporte de los navegadores. Lo que tienes que hacer es configurar como fondo de un elemento lo que haya debajo de él. Sencillo, ¿no?

Puedes verlo en una de mis demos de un artículo anterior, ahora incluyendo soporte para Firefox utilizando element()

See the Pen KpjVmm by Kseso (@Kseso) on CodePen.


Y otra más con contenido dinámico:

See the Pen iOS 7 background blur with CSS by Kseso (@Kseso) on CodePen.


El código se explica por sí sólo:

h1 { … } @supports ( backdrop-filter: blur(1px) ) { h1 { backdrop-filter: grayscale(1) contrast(3) blur(1px); } } @supports (not (backdrop-filter: blur(1px))) and (background: element(#back)) { h1::before { content: ''; position: absolute; z-index: -1; top: 0; left: 0; bottom: 0; right: 0; background: element(#back) fixed; filter: grayscale(1) contrast(3) blur(1px); } }

Usando @supports puedes probar:

  • Si backdrop-filter es soportado, se aplica al <h1>
  • Si backdrop-filter no es soportado pero element() sí, crea un pseudoelemento que será posicionado sobre el título, establecelo para que sea mostrado en directo como fondo del pseudo y aplica el filtro.

Merece la pena señalar, también, que puedes crear un falso backdrop-filter con filtros SVG. Algo como lo siguiente (mira la pestaña 'HTML'):

See the Pen OVeMzN by Kseso (@Kseso) on CodePen.

De esta formas proporcionas mucho mejor soporte, pero también tiene muchos inconvenientes. Este filtro SVG no es dinámico, aunque teóricamente sea posible. De hecho ningún navegador soporta backgroundImage como valor de entrada en los filtros primitivos. IE/Edge soporta la propiedad obsoleta enable-background para acceder al valor de entrada backgroundImage, pero sólo para contenido SVG.

Cómo ocultar los referentes

En muchos efectos he tenido que crear una máscara de capa para ocultar partes de la página. Es porque no se puede display: none un elemento que es utilizado como fondo fondo. En la actualidad, la imagen en directo del elemento como fondo no se mostrará en absoluto.

También intenté envolver al elemento de referencia dentro de un <div> con height:0 y overflow: hidden. De esta forma el elemento está aún presente en la página (y puede ser referenciado como imagen en directo) sin que sea visible, así no es necesaria la máscara de capa.

El problema es que algunos navegadores degradan el rendimiento de elementos ocultos (animaciones CSS, imágenes GIF inanimados, etc.) y esto no es lo que queremos en ese caso específico.

Así que terminé utilizando la técnica de la máscara. ¿Conoces alguna otra solucción?

En resumen

Con suerte te he convencido de lo impresionante que es la propiedad Css element(), escaso soporte e incidencia en la composición de la página aparte. Deberías probarlo y compartir tus increibles demos. Hemos de demostrar interés en él. No hay duda que esto animará a los navegadores a tomarlo en consideración.

iamvdo

La totalidad del artículo, imágenes y demostraciones incluidas, es obra de Vincent De Oliveira (aka @iamvdo).
Fue publicado originalmente en su página iamvdo.me bajo el título CSS element() function el 6 de Agosto de 2015 en inglés.
Yo sólo me he limitado a traducirlo al español. Todo el crédito y reconocimiento ha de ser otorgado a su autor:
Vincent De Oliveira en las redes
Twitter || Google+ || Dribbble || GitHub || También es el autor de pleeease.io