Métodos para contrastar texto con fondos »Wiki Ùtil Programar Plus

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 contentEditable1 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.  Un cuadro que representa un elemento (izquierda) tiene un filtro CSS aplicado para convertirse en un cuadro con una sombra de cuadro (centro) y luego se aplica una ruta de recorte para convertirse en una estrella sin sombra (derecha).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.

El texto editable, hecho para contrastar con la imagen de fondo utilizando el método mix-blend-mode, se muestra seleccionado en su totalidad.  El fondo de la selección se mezcla con la imagen de abajo.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.

GIF animado.  El texto editable, hecho para contrastar con la imagen de fondo utilizando el método de ruta de clip, se selecciona en Firefox.  La selección tropieza donde la copia de este texto, generada a través de un pseudoelemento, se superpone al original.  Establecer eventos de puntero: ninguno en el pseudoelemento soluciona este problema.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.

El texto editable, hecho para contrastar con la imagen de fondo utilizando el método background-clip: text + filter, se muestra seleccionado en su totalidad.  Todo el cuadro de selección tiene aplicado el efecto de filtro, no solo el texto, por lo que el fondo de la selección es en escala de grises y la sombra ahora está en el cuadro de selección, no solo en el texto en sí.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.

GIF animado.  El texto editable, hecho para contrastar con la imagen de fondo usando el método background-clip: text + filter, se edita en Firefox.  A medida que escribe, el texto se recorta y se distorsiona, superponiéndose a sí mismo.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.

GIF animado.  El texto editable, hecho para contrastar con la imagen de fondo utilizando el método de ruta de clip, se edita en Firefox.  El cursor no se puede colocar para comenzar a editar desde la parte donde la copia de este texto, generada a través de un pseudo-elemento, se superpone al original.  Establecer eventos de puntero: ninguno en el pseudoelemento soluciona este problema.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.

(Visited 5 times, 1 visits today)