La función Css element(): conexión cuántica entre elementos 20.8.15
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
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.
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):
- Si tienes que manejar efectos avanzados con contenido duplicado.
- miniaturas "vivas" en galerías con next/prev.
- Zoom en directo en una imagen de un producto en un sitio de e-commerce.
- Fondos animados usando animaciones Css, referenciando un vídeo, canvas o SVG.
- Pseudos
backdrop-filter
ofilter()
- Marcas de agua con múltiples fondos como la idea de Lea Verou.
- Cualquier otra que puedas imaginar :)
Ten presente:
- En Firefox es necesario, por ahora, prefijo:
-moz-element()
- Su impacto en el rendimiento (repaint y reflow) al usarse múltiples referencias. No tanto como los filtros Css, pero con todo has de tenerlo en consideración.
- CanIUse tiene una página sobre su soporte.
- Issue Chromium
- Issue WebKit
- Sin noticias en IE Platform Status
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.
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.
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.
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 aelement()
, 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 peroelement()
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.
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
No le voy a compartir demos al amigo Vincent De Oliveira como solicita, pero ya que trajiste de nuevo aquí la propiedad element() aprovecho a republicar un enlace al pen que hice en la época que pedían en varios sitios una forma de hacer que una parte de imagen sprite se repitiera como fondo mosaico. (Algo que no está previsto en los backgrounds.)
ResponderEliminarParallax scroll puro Css...
Habiendo metido tanto invento raro en Chrome, no entiendo por qué Google no le incorpora esta propiedad de una buena vez.