
Comenzó con una reciente demostración de efectos de texto de Pen of Mandy Michael. Soy una criatura muy visual, así que lo primero que noté fue el efecto, no el título (que indica claramente cómo se logró el efecto). Al instante, mi mente se puso en “modos de fusión”, lo que resultó ser incorrecto.
La demostración realmente usa clip-path
. En primer lugar, el texto está duplicado. Tenemos el texto negro a continuación como el contenido de texto real del elemento y el texto blanco arriba como el valor del content
propiedad (tomada de un atributo de datos que se actualiza a través de JS). Estos dos están apilados uno encima del otro (se superponen completamente). Luego, el pseudo-elemento con el texto blanco arriba se recorta a la forma del vestido negro.
Sin embargo, esto significa que tenemos que cambiar la ruta de recorte si cambiamos la imagen y, en este punto, es todo menos fácil descubrir rutas de recorte poligonales con muchos puntos a través de herramientas de desarrollo (razón por la cual tener algo como Clippy de Benett Feely con la edición bidireccional directamente en las herramientas de desarrollo sería inmensamente útil). Así que decidí probar mi idea inicial, los modos de fusión.
Digamos que tenemos un encabezado en un contentEditable
1 recipiente con una imagen en blanco y negro (bueno, escala de grises) background
. La estructura HTML es la siguiente:
<header>
<h2 contentEditable role="textbox" aria-multiline="true">And stay alive</h2>
</header>
Establecemos el background-image
sobre el header
contenedor, le damos el h2
texto blanco y establezca su mix-blend-mode
a difference
o exclusion
. El CSS relevante está a continuación:
header { background: url(black-and-white-image.jpg) }
h2 {
color: white;
mix-blend-mode: difference;
}
Realmente no puedo entender los modos de fusión o normalmente veo una diferencia entre difference
y exclusion
, pero según MDN, son prácticamente iguales, con exclusion
tener menos contraste. Lo que puedo entender en esta situación es que tener texto blanco sobre la imagen nos da un resultado que es la imagen invertida donde el texto se superpone. Para imágenes simples en blanco y negro, el negro en la imagen original se vuelve blanco donde tenemos texto blanco encima y el blanco en la imagen original se vuelve negro donde tenemos texto blanco encima.
El resultado se puede ver en el siguiente Pen:
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
¡Misión cumplida! Tanto el texto como la imagen se pueden cambiar y el efecto se conserva sin necesidad de JavaScript ni de cambios en el CSS.
Pero al instante descubrí que había otra picazón que rascar: ¿qué sucede si la imagen no es solo en blanco y negro? Bueno, ¡intentemos eso! Resulta que el resultado se ve bastante bien:
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Sin embargo, el texto ya no es escala de grises y la configuración filter: grayscale(1)
no cambia nada. ¿Alguno filter
valorar el trabajo? Bueno, intenté drop-shadow()
siguiente para tratar de encontrar una respuesta a esta pregunta. Y la respuesta es que si drop-shadow()
funciona, pero la forma en que funciona: la sombra se mezcla con la header
background2: proporciona una pista sobre por qué grayscale()
no cambió nada: los filtros se aplican antes de la fusión, nuestro texto es blanco y la salida de grayscale()
en este caso es idéntica a su entrada (entrada blanca, salida blanca). Y, dado que nada cambia antes de la mezcla, su resultado es el mismo.
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Probablemente esto no debería haber sido una sorpresa. Me encontré con problemas causados por el orden en que se aplicaban las propiedades antes.
Por ejemplo, filter
también se aplica antes clip-path
, así que si recortamos un elemento a una forma no rectangular y queremos tener una sombra paralela, mala suerte, estableciendo el filter
en el mismo elemento no da el resultado esperado. Esto se debe a que el elemento rectangular obtiene la filter
aplicado, por lo que tenemos una sombra alrededor de su cuadro rectangular y solo después de eso se recorta a la forma especificada a través de clip-path
. Este es siempre el orden en el que se aplican estos dos, independientemente del orden en que los establezca en el CSS.
Diagrama de cómo se aplican los navegadores
filter
y clip-path
cuando se establecen en el mismo elemento.
La forma de resolver el filter
+ clip-path
El problema es configurar el filter
en un elemento padre sin nada visible excepto el hijo recortado. La parte “nada visible” es importante porque, si el padre tiene algún texto o bordes visibles, también obtendrán la sombra paralela, mientras que si tiene un fondo, entonces toda el área del fondo tendrá la sombra.
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Sin embargo, esta solución no funciona para filter
+ mix-blend-mode
problema también. Envolviendo nuestro h2
en una div
y ambientación filter
en ese div
rompe el efecto de fusión.
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Lo que es peor es que parece que no puedo pensar en nada que pueda hacer para solucionar este problema. Puede haber una forma de hacerlo duplicando el texto y usando un luminosity
modo de fusión, pero, como se mencionó antes, realmente no entiendo los modos de fusión y no he podido hacerlo bien.
Pero tal vez podríamos probar un enfoque completamente diferente, uno que no use la mezcla. Todo el juego con los filtros me dio la idea de que podíamos aplicar la imagen al texto, luego aplicar un invert()
filtro, al que podríamos encadenar grayscale()
, contrast()
y más.
Con este método usando background-clip: text
, también tenemos la ventaja de una solución de navegador cruzado, ya que Firefox y Edge ahora también lo han implementado.
La forma en que hacemos esto es la siguiente: nos aseguramos de que header
y el h2
tienen fondos idénticos y que estos fondos se superponen perfectamente. Entonces establecemos color: transparent
sobre el h2
y recortar su fondo para text
. El último paso es establecer filter: invert(1)
sobre el h2
. El CSS3 relevante es el siguiente:
h2 {
background: inherit;
background-clip: text;
color: transparent;
filter: invert(1);
}
El resultado se puede ver en el siguiente Pen:
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Se ve como antes, excepto que está usando un método diferente y ahora podemos encadenar más funciones al filter
propiedad. Por ejemplo, podemos hacer que el texto sea en escala de grises y aumentar su contraste:
filter: invert(1) grayscale(1) contrast(9)
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Ajustando el filter
El valor también es cómo agregamos una sombra de texto. Mientras que en el primer caso (usando mix-blend-mode
) simplemente podemos establecer el text-shadow
propiedad (y la sombra también se mezcla con el fondo), hacerlo en el segundo caso rompe las cosas:
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Afortunadamente, podemos encadenar drop-shadow()
a nuestro filtro.
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
El lápiz a continuación muestra los dos métodos descritos en este artículo. A la izquierda, tenemos el mix-blend-mode
método y a la derecha, tenemos el background-clip
y filter
método (con los componentes de contraste y escala de grises adicionales). El texto es editable y las miniaturas permiten cambiar el background-image
:
Vea el lápiz de thebabydino (@thebabydino) en CodePen.
Entonces, si enfrentamos estos métodos entre sí, ¿cuál es mejor?
Cuando no entre en estética porque es un asunto subjetivo y probablemente difiera de un caso a otro e incluso de un estado de ánimo a otro.
En lo que respecta al soporte básico, el último método obtiene una ventaja ya que es compatible con Edge, mientras que mix-blend-mode
no lo es (pero si lo desea en Edge, vote por él porque sus comentarios sí importan). El ejemplo original de Mandy usa clip-path
, otra característica muy útil, que lamentablemente tampoco funciona en Edge (puedes votarla aquí).
Cuando se trata de seleccionar texto, el mix-blend-mode
El método funciona perfectamente y se ve mejor en todos los navegadores compatibles.
Seleccionar texto al usar el
mix-blend-mode
método
Utilizando el clip-path
método, la selección se ve limpia y el texto sigue siendo legible, pero parecía tropezar en Firefox mientras estaba sobre el texto del pseudo-elemento. Afortunadamente, este problema resultó tener una solución fácil: configurar pointer-events: none
en el pseudo-elemento.
Seleccionar texto en Firefox al usar el
clip-path
método
En cuanto al último método, la selección puede verse desagradable y puede hacer que el texto sea más difícil de leer. Sin mencionar que la sombra paralela termina aplicándose a todo el rectángulo de selección en este caso, no solo al texto real.
Seleccionar texto al usar el
background-clip: text
+ filter
método
Cambiar el texto también se vuelve incómodo en Firefox con el último método, la pantalla se “ensucia” a medida que escribo texto nuevo.
Cambiar el texto en Firefox al usar el
background-clip: text
+ filter
método
El clip-path
El método también tuvo un problema con el cambio de texto en Firefox al principio: intentar comenzar a editar desde el medio del texto del pseudo-elemento no funcionó. Afortunadamente, el establecimiento pointer-events: none
en el pseudo-elemento también corrige esto.
Cambiar el texto en Firefox al usar el
clip-path
método
En lo que respecta a la flexibilidad en términos de cómo podemos alterar el texto, el último método funciona mejor porque encadenar funciones de filtro puede llevarnos un largo camino.
Al final del día, lo que es mejor termina dependiendo del caso de uso particular. ¿Qué navegadores deberían ser compatibles? ¿Cambia la imagen? ¿Cambia el texto? ¿Cómo se debe alterar visualmente el texto?
1 contentEditable
no es accesible en todos los navegadores de forma predeterminada, por lo que debemos proporcionar semántica para solucionarlo.
2 Cuando experimente con modos de fusión, tenga en cuenta los problemas de legibilidad que pueden producir, especialmente en lo que respecta al contraste. WCAG 2.0 establece que, a menos que el texto forme parte de imágenes puramente decorativas, debe pasar un umbral de contraste mínimo. Herramientas como Color ContrastAnalyzer pueden ayudarlo a cumplir con ese requisito.
3 Los prefijos se omiten por brevedad, pero background-clip
todavía necesita el -webkit-
prefijo para los navegadores WebKit (Firefox y Edge lo han implementado sin prefijo, aunque ambos lo admiten con el -webkit-
prefijo también, probablemente porque ya se ha utilizado hasta la muerte solo con ese prefijo) y este prefijo debe agregarse manualmente / a través de un preprocesador mixin, que es algo que normalmente no recomiendo, pero, en este caso particular, prefijo automático a través de Autoprefixer o Prefixfree no ocurre (Prefixfree funciona mediante la detección de funciones, que no detecta propiedades como background-clip
, filter
o clip-path
y este es el problema del Autoprefixer). Como para filter
, ahora se admite sin prefijo en todos los navegadores de escritorio actuales y Autoprefixer puede prefijarlo de todos modos.