Modos de fusión domesticados: “diferencia” y “exclusión”

Hasta 2020, los modos de fusión eran una característica que no había usado mucho porque rara vez tenía idea del resultado que podía producir sin probarlos primero. Y adoptar el enfoque de “pruébalo y mira qué pasa” parecía dejarme siempre horrorizado por el vómito visual que había logrado crear en la pantalla.
El problema surgió por no saber muy bien cómo funcionan en la parte trasera. Casi todos los artículos que ha visto sobre el tema se basan en ejemplos, comparaciones con Photoshop o descripciones artísticas detalladas. Los ejemplos me parecen geniales, pero cuando no tienes idea de cómo funcionan las cosas en el fondo, adapta una demostración atractiva a algo que implemente una idea diferente que tienes en la cabeza se convierte en una aventura que requiere mucho tiempo, es frustrante y, en última instancia, inútil. Entonces las comparaciones de Photoshop son prácticamente inútiles para alguien que tiene experiencia técnica. Y las descripciones artísticas detalladas me parecen lenguaje de pingüinos.
Así que se me iluminó cuando encontré la especificación y descubrí que también incluye fórmulas matemáticas según las cuales funcionan los modos de fusión. Esto significó que finalmente pude entender cómo funcionan estas cosas en la parte trasera y dónde pueden ser realmente útiles. Y ahora que lo sé mejor, compartiré este conocimiento en una serie de artículos.
Hoy, nos centraremos en cómo funciona la mezcla en general, luego veremos más de cerca dos modos de mezcla algo similar difference
y exclusion
, finalmente, llegaremos al meollo de este artículo donde analizaremos algunos casos de uso interesantes como los que aparecen a continuación. .
Analizamos el “cómo” de los modos de fusión.
Mezclar significa combinar dos capas (que se apilan una encima de la otra) y obtener una sola capa. Estas dos capas podrían ser dos hermanas, en cuyo caso la propiedad CSS que utilizamos es mix-blend-mode
. También podrían ser dos background
capas, en cuyo caso la propiedad CSS que utilizamos es background-blend-mode
. Tenga en cuenta que cuando hablo de combinar “hermanos”, esto incluye combinar un elemento con los pseudoelementos o con el contenido del texto o el background
de su padre. Y cuando se trata de background
capas, no background-image
me refiero sólo a las capas: background-color
también es una capa.
Al combinar dos capas, la capa de arriba se llama origen , mientras que la capa de abajo se llama destino . Esto es algo que tomo como está porque estos nombres no tienen mucho sentido, al menos para mí. Esperaría que el destino fuera una salida, pero en cambio ambas son entradas y la capa resultante es la salida.
La forma exacta en que combinamos las dos capas depende del modo de fusión particular utilizado, pero siempre es por píxel. Por ejemplo, la siguiente ilustración utiliza el multiply
modo de fusión para combinar las dos capas, representadas como cuadrículas de píxeles.
Muy bien, pero ¿qué pasa si tenemos más de dos capas? Bueno, en este caso, el proceso de mezcla ocurre en etapas, comenzando desde abajo.
En una primera etapa, la segunda capa desde abajo es nuestro origen y la primera capa desde abajo es nuestro destino. Estas dos capas se mezclan y el resultado se convierte en el destino de la segunda etapa, donde la tercera capa desde abajo es la fuente. Fusionar la tercera capa con el resultado de fusionar las dos primeras nos da el destino para la tercera etapa, donde la cuarta capa desde abajo es la fuente.
Por supuesto, podemos utilizar un modo de fusión diferente en cada etapa. Por ejemplo, podemos usar difference
para mezclar las dos primeras capas desde abajo y luego usar multiply
para mezclar el resultado con la tercera capa desde abajo. Pero esto es algo en lo que profundizaremos un poco más en artículos futuros.
El resultado producido por los dos modos de fusión que analizamos aquí no depende de cuál de las dos capas esté encima. Tenga en cuenta que este no es el caso de todos los modos de fusión posibles, pero sí de los que estamos analizando en este artículo.
También son modos de fusión separables, lo que significa que la operación de fusión se realiza en cada canal por separado. Nuevamente, este no es el caso para todos los modos de fusión posibles, pero sí lo es para difference
y exclusion
.
Más exactamente, el canal rojo resultante sólo depende del canal rojo del origen y del canal rojo del destino; el canal verde resultante sólo depende del canal verde del origen y del canal verde del destino; y finalmente, el canal azul resultante solo depende del canal azul del origen y del canal azul del destino.
R = fB(Rs, Rd)G = fB(Gs, Gd)B = fB(Bs, Bd)
Para un canal genérico, sin especificar si es rojo, verde o azul, tenemos que es función de los dos canales correspondientes en la capa de origen (superior) y en la capa de destino (inferior):
Ch = fB(Chs, Chd)
Algo a tener en cuenta es que los valores RGB se pueden representar en el [0, 255]
intervalo o como porcentajes en el [0%, 100%]
intervalo, y lo que realmente usamos en nuestras fórmulas es el porcentaje expresado como un valor decimal. Por ejemplo, crimson
se puede escribir como cualquiera rgb(220, 20, 60)
o como rgb(86.3%, 7.8%, 23.5%)
: ambos son válidos. Los valores de canal que utilizamos para los cálculos si un píxel es crimson
son los porcentajes expresados como valores decimales, es decir .863
, .078
, .235
.
Si un píxel es black
, los valores de canal que usamos para los cálculos son todos 0
, ya que black
se pueden escribir como rgb(0, 0, 0)
o como rgb(0%, 0%, 0%)
. Si un píxel es white
, los valores de canal que usamos para los cálculos son todos 1
, ya que white
se pueden escribir como rgb(255, 255, 255)
o como rgb(100%, 100%, 100%)
.
Tenga en cuenta que siempre que tengamos transparencia total (un alfa igual a 0
), el resultado es idéntico al de la otra capa.
difference
El nombre de este modo de fusión podría proporcionar una pista sobre lo que hace la función de fusión. El resultado es el valor absoluto de la diferencia entre los valores del canal correspondiente para las dos capas.fB()
Ch = fB(Chs, Chd) = |Chs - Chd|
En primer lugar, esto significa que si los píxeles correspondientes en las dos capas tienen valores RGB idénticos (es decir, para cada uno de los tres canales), entonces el píxel de la capa resultante es porque las diferencias para los tres canales son .Chs = Chd
black
0
Chs = ChdCh = fB(Chs, Chd) = |Chs - Chd| = 0
En segundo lugar, dado que el valor absoluto de la diferencia entre cualquier número positivo 0
deja ese número sin cambios, el píxel de resultado correspondiente tiene el mismo valor RGB que el píxel de la otra capa si el píxel de una capa es black
(todos los canales iguales 0
).
Si el black
píxel está en la capa superior (fuente), reemplazar los valores de su canal 0
en nuestra fórmula nos da:
Ch = fB(0, Chd) = |0 - Chd| = |-Chd| = Chd
Si el black
píxel está en la capa inferior (destino), reemplazar los valores de su canal 0
en nuestra fórmula nos da:
Ch = fB(Chs, 0) = |Chs - 0| = |Chs| = Chs
Finalmente, dado que el valor absoluto de la diferencia entre cualquier número subunitario positivo y 1
nos da el complemento de ese número, resulta que si el píxel de una capa está white
(tiene todos los canales 1
), el píxel resultante correspondiente es el píxel de la otra capa completamente invertido (lo que filter: invert(1)
le haría).
Si el white
píxel está en la capa superior (fuente), reemplazar los valores de su canal 1
en nuestra fórmula nos da:
Ch = fB(1, Chd) = |1 - Chd| = 1 - Chd
Si el white
píxel está en la capa inferior (destino), reemplazar los valores de su canal 1
en nuestra fórmula nos da:
Ch = fB(Chs, 1) = |Chs - 1| = 1 - Chs
Esto se puede ver en acción en el lápiz interactivo a continuación, donde puede alternar entre ver las capas separadas y verlas superpuestas y combinadas. Al pasar el cursor sobre las tres columnas en el caso superpuesto también se revela lo que sucede en cada una.
exclusion
Para el segundo y último modo de combinación que veremos hoy, el resultado es el doble del producto de los valores de los dos canales, restado de su suma:
Ch = fB(Chs, Chd) = Chs + Chd - 2·Chs·Chd
Como ambos valores están en el [0, 1]
intervalo, su producto siempre es como máximo igual al menor de ellos, por lo que el doble del producto siempre es como máximo igual a su suma.
Si consideramos un black
píxel en la capa superior (fuente), y luego lo reemplazamos con en la fórmula anterior, obtenemos el siguiente resultado para los canales del píxel resultante correspondiente:Chs
0
Ch = fB(0, Chd) = 0 + Chd - 2·0·Chd = Chd - 0 = Chd
Si consideramos un black
píxel en la capa inferior (destino), y luego lo reemplazamos con en la fórmula anterior, obtenemos el siguiente resultado para los canales del píxel resultante correspondiente:Chd
0
Ch = fB(Chs, 0) = Chs + 0 - 2·Chs·0 = Chs - 0 = Chs
Entonces, si el píxel de una capa es black
, el resultado correspondiente es idéntico al píxel de la otra capa.
Si consideramos un white
píxel en la capa superior (fuente), y luego lo reemplazamos con en la fórmula anterior, obtenemos el siguiente resultado para los canales del píxel resultante correspondiente:Chs
1
Ch = fB(1, Chd) = 1 + Chd - 2·1·Chd = 1 + Chd - 2·Chd = 1 - Chd
Si consideramos un white
píxel en la capa inferior (destino), y luego lo reemplazamos con en la fórmula anterior, obtenemos el siguiente resultado para los canales del píxel resultante correspondiente:Chd
1
Ch = fB(Chs, 1) = Chs + 1 - 2·Chs·1 = Chs + 1 - 2·Chs = 1 - Chs
Entonces, si el píxel de una capa es white
, el resultado correspondiente es idéntico al píxel de la otra capa invertido.
Todo esto se muestra en la siguiente demostración interactiva:
Tenga en cuenta que siempre que al menos una de las capas solo tenga black
píxeles white
y produzca exactamente el mismo resultado.difference
exclusion
Ahora, pasemos al "qué" de los modos de fusión.
Aquí viene la parte interesante: ¡los ejemplos!
Efecto de cambio de estado del texto
Digamos que tenemos un párrafo con un enlace:
pHello, a href='#'World/a!/div
Comenzamos configurando algunos estilos básicos para colocar nuestro texto en el medio de la pantalla, aumentarlo font-size
, establecer un background
y body
un color
tanto en el párrafo como en el enlace.
body { display: grid; place-content: center; height: 100vh; background: #222; color: #ddd; font-size: clamp(1.25em, 15vw, 7em);}a { color: gold; }
No parece mucho hasta ahora, ¡pero pronto cambiaremos eso!
El siguiente paso es crear un pseudoelemento absolutamente posicionado que cubra todo el enlace y que esté background
configurado en currentColor
.
a { position: relative; color: gold; ::after { position: absolute; top: 0; bottom: 0; right: 0; left: 0; background: currentColor; content: ''; }}
Parece que lo anterior hemos estropeado las cosas... pero, ¿realmente lo hemos hecho? Lo que tenemos aquí es un gold
rectángulo encima del gold
texto. Y si ha prestado atención a cómo funcionan los dos modos de combinación discutidos anteriormente, entonces probablemente ya haya adivinado lo que sigue: combinamos los dos nodos hermanos dentro del enlace (el rectángulo del pseudoelemento y el contenido del texto) usando difference
y puesto que son ambos gold
, resulta que lo que tienen en común –el texto– se convierte en black
.
p { isolation: isolate; }a { /* same as before */ ::after { /* same as before */ mix-blend-mode: difference; }}
Tenga en cuenta que tenemos que isolate
el párrafo para evitar que se mezcle con el cuerpo background
. Si bien esto es solo un problema en Firefox (y dado que tenemos una background
pantalla muy oscura body
, no se nota demasiado) y está bien en Chrome, tenga en cuenta que, según las especificaciones, lo que hace Firefox es realmente correcto. Es Chrome el que se comporta con errores aquí, por lo que deberíamos tener la isolation
propiedad configurada en caso de que se solucione el error.
Muy bien, pero queremos que esto suceda sólo si el vínculo está enfocado o suspendido. De lo contrario, el pseudoelemento no es visible; digamos que está reducido a nada.
a { /* same as before */ text-decoration: none; ::after { /* same as before */ transform: scale(0); } :focus { outline: none } :focus, :hover { ::after { transform: none; } }}
También eliminamos el subrayado del enlace y el esquema de enfoque. A continuación, ahora puede ver el efecto de diferencia :hover
(el mismo efecto ocurre en :focus
, que es algo que puede probar en la demostración en vivo).
Ahora tenemos nuestro cambio de estado, pero parece difícil, así que agreguemos un transition
!
a { /* same as before */ ::after { /* same as before */ transition: transform .25s; }}
¡Mucho mejor!
Se vería aún mejor si nuestro pseudo creciera no de la nada en el medio, sino de una delgada línea en la parte inferior. Esto significa que debemos establecer el valor transform-origin
en el borde inferior ( 100%
verticalmente y cualquier valor horizontalmente) e inicialmente escalar nuestro pseudo a algo un poco más que nada a lo largo del eje y .
a { /* same as before */ ::after { /* same as before */ transform-origin: 0 100%; transform: scaleY(.05); }}
Otra cosa que me gustaría hacer aquí es reemplazar el font
párrafo por uno más atractivo estéticamente, ¡así que ocupémonos de eso también! Pero ahora tenemos un tipo diferente de problema: el final de la 'd' sobresale del rectángulo en :focus
/ :hover
.
Podemos solucionar esto con una horizontal padding
en nuestro enlace.
a { /* same as before */ padding: 0 .25em;}
En caso de que se pregunte por qué configuramos esto padding
tanto en el lado derecho como en el izquierdo en lugar de simplemente configurar un padding-right
, el motivo se ilustra a continuación. Cuando el texto de nuestro enlace se convierte en "Alien World", el comienzo rizado de la 'A' terminaría fuera de nuestro rectángulo si no tuviéramos un padding-left
.
Esta demostración con un enlace de varias palabras arriba también resalta otro problema cuando reducimos el ancho de la ventana gráfica.
Una solución rápida aquí sería configurar display: inline-block
el enlace. Esta no es una solución perfecta. También se rompe cuando el texto del enlace es más largo que el ancho de la ventana gráfica, pero funciona en este caso particular, así que dejémoslo aquí ahora y volveremos a este problema en un momento.
Consideremos ahora la situación de un tema ligero. Dado que no hay forma de obtener white
el black
texto del enlace :hover
o :focus
fusionando dos capas de resaltado idénticas que no lo son white
, necesitamos un enfoque un poco diferente aquí, uno que no implique el uso solo de modos de fusión.
Lo que hacemos en este caso es primero configurar el background
texto del párrafo normal color
y el texto del enlace color
con los valores que queremos, pero invertidos. Inicialmente estaba haciendo esta inversión manualmente, pero luego me sugirieron usar la invert()
función Sass, que es una idea genial que realmente simplifica las cosas. Luego, después de tener este tema oscuro que es básicamente el tema claro que queremos invertido, obtenemos el resultado deseado invirtiendo todo nuevamente con la ayuda de la invert()
función de filtro CSS.
Pequeña advertencia aquí: no podemos configurar filter: invert(1)
los elementos body
o html
porque esto no se comportará de la manera que esperamos y no obtendremos el resultado deseado. Pero podemos configurar tanto the background
como the filter
en un contenedor alrededor de nuestro párrafo.
section pHello, a href='#'Alien World/a!/p/section
body { /* same as before, without the place-content, background and color declarations, which we move on the section */}section { display: grid; place-content: center; background: invert(#ddd) /* Sass invert(color) function */; color: invert(#222); /* Sass invertcolor) function */; filter: invert(1); /* CSS filter invert(number|percentage) function */}a { /* same as before */ color: invert(purple); /* Sass invert(color) function */}
Aquí hay un ejemplo de una barra de navegación que emplea este efecto (y muchos otros trucos inteligentes, pero están fuera del alcance de este artículo). Seleccione una opción diferente para verlo en acción:
Algo más con lo que debemos tener cuidado es lo siguiente: todos los descendientes nuestros section
se invierten cuando usamos esta técnica. Y probablemente esto no sea lo que queremos en el caso de img
los elementos; ciertamente no espero ver las imágenes en una publicación de blog invertidas cuando cambio del tema oscuro al claro. En consecuencia, deberíamos revertir la filter
inversión en cada img
descendiente de nuestro section
.
section { /* same as before */ , img { filter: invert(1); }}
En conjunto, la siguiente demostración muestra los casos de tema oscuro y claro con imágenes:
Ahora volvamos al tema del texto del enlace envolvente y veamos si no tenemos mejores opciones que crear elementos a inline-block
.
Bueno, ¡lo hacemos! Podemos combinar dos background
capas en lugar de combinar el contenido del texto y un pseudo. Una capa se recorta en text
, mientras que la otra se recorta en border-box
y su tamaño vertical se anima entre 5%
los casos iniciales y 100%
en los casos enfocados y suspendidos.
a { /* same as before */ -webkit-text-fill-color: transparent; -moz-text-fill-color: transparent; --full: linear-gradient(currentColor, currentColor); background: var(--full), var(--full) 0 100%/1% var(--sy, 5%) repeat-x; -webkit-background-clip: text, border-box; background-clip: text, border-box; background-blend-mode: difference; transition: background-size .25s; :focus, :hover { --sy: 100%; }}
Tenga en cuenta que ya ni siquiera tenemos un pseudoelemento, por lo que tomamos parte del CSS, lo movimos en el enlace y lo modificamos para adaptarlo a esta nueva técnica. Hemos pasado de usar mix-blend-mode
a usar background-blend-mode
; ahora estamos en la transición background-size
de transform
y, en los estados :focus
y :hover
; y ahora no estamos cambiando el transform
, sino una propiedad personalizada que representa el componente vertical del background-size
.
Mucho mejor, aunque tampoco es una solución perfecta.
El primer problema es uno que seguramente habrás notado si revisaste el enlace de demostración en vivo del título en Firefox: no funciona en absoluto. Esto se debe a un error de Firefox que aparentemente informé en 2018, luego lo olvidé por completo hasta que comencé a jugar con los modos de fusión y lo presioné nuevamente.
El segundo problema se nota en la grabación. Los enlaces parecen algo descoloridos. Esto se debe a que, por alguna razón, Chrome combina elementos en línea como enlaces (tenga en cuenta que esto no sucederá con elementos de bloque como divs) con los background
de su ancestro más cercano ( section
en este caso) si estos elementos en línea se han background-blend-mode
configurado en cualquier otro valor que no sea normal
.
Aún más extraño, configurar isolation: isolate
el enlace o su párrafo principal no evita que esto suceda. Todavía tenía la sensación persistente de que debía tener algo que ver con el contexto, así que decidí seguir lanzando posibles trucos y esperar que algo termine funcionando. Bueno, no tuve que dedicarle mucho tiempo. Establecer opacity
un 1
valor subunitario (pero aún lo suficientemente cercano como para que no se note que no es completamente opaco) soluciona el problema.
a { /* same as before */ opacity: .999; /* hack to fix blending issue ¯_(ツ)_/¯ */}
El problema final es otro que se nota en la grabación. Si observas la 'r' al final de “Amur”, podrás notar que su extremo derecho está recortado porque cae fuera del rectángulo de fondo. Esto es particularmente notable si lo comparas con la 'r' de "leopardo".
No tenía grandes esperanzas de solucionar este problema, pero de todos modos lancé la pregunta a Twitter. ¡Y qué sabes, se puede arreglar! ¡Usarlo box-decoration-break
en combinación con lo que padding
ya hemos configurado puede ayudarnos a lograr el efecto deseado!
a { /* same as before */ box-decoration-break: clone;}
Tenga en cuenta que box-decoration-break
todavía se necesita el -webkit-
prefijo para todos los navegadores WebKit, pero a diferencia del caso de propiedades como background-clip
donde está al menos un valor text
, las herramientas de prefijo automático pueden solucionar el problema sin problemas. Es por eso que no he incluido la versión con prefijo en el código anterior.
Otra sugerencia que recibí fue agregar un negativo margin
para compensar el padding
. Estoy yendo y viniendo sobre esto; no puedo decidir si me gusta más el resultado con o sin él. En cualquier caso, es una opción digna de mención.
$p: .25em;a { /* same as before */ margin: 0 (-$p); /* we put it within parenthesis so Sass doesn't try to perform subtraction */ padding: 0 $p;}
Aún así, tengo que admitir que animar sólo la parte background-position
o la parte background-size
de un degradado es un poco aburrido. Pero gracias a Houdini, ahora podemos ser creativos y animar cualquier componente de un gradiente que deseemos, aunque esto solo es compatible con Chromium por el momento. Por ejemplo, el radio de un radial-gradient()
me gusta a continuación o el progreso de un conic-gradient()
.
Invertir solo un área de un elemento (o un background
)
Este es el tipo de efecto que a menudo veo logrado al usar la duplicación de elementos: las dos copias se colocan en capas una encima de la otra, donde una de ellas tiene una inversión filter
y clip-path
se usa en la superior para mostrar ambas capas. Otra ruta es colocar un segundo elemento en capas con un alfa lo suficientemente bajo como para que ni siquiera puedas notar que está ahí y un backdrop-filter
.
Ambos enfoques hacen el trabajo si queremos invertir una parte del elemento completo con todo su contenido y descendientes, pero no pueden ayudarnos cuando queremos invertir solo una parte de background
ambos filter
y backdrop-filter
afectar elementos completos, no solo sus antecedentes. Y aunque la nueva filter()
función (ya compatible con Safari) tiene efecto únicamente en background
las capas, afecta a toda el área del fondo, no sólo a una parte.
Aquí es donde entra en juego la fusión. La técnica es bastante sencilla: tenemos una background
capa, parte de la cual queremos invertir y una o más capas de degradado que nos dan un white
área donde queremos invertir la otra capa y transparencia (o black
) en caso contrario. . Luego mezclamos usando uno de los dos modos de mezcla discutidos hoy. A los efectos de la inversión, prefiero exclusion
(es un carácter más corto que difference
).
He aquí un primer ejemplo. Tenemos un elemento cuadrado que tiene dos capas background
. Las dos capas son una imagen de un gato y un degradado con una transición brusca entre white
y transparent
.
div { background: linear-gradient(45deg, white 50%, transparent 0), url(cat.jpg) 50%/ cover;}
Esto nos da el siguiente resultado. También establecimos dimensiones, a border-radius
, sombras y embellecimos el texto en el proceso, pero todo eso no es realmente importante en este contexto:
A continuación, sólo necesitamos una declaración CSS más para invertir la mitad inferior izquierda:
div { /* same as before */ background-blend-mode: exclusion; /* or difference, but it's 1 char longer */}
Observe cómo el texto no se ve afectado por la inversión; solo se aplica al background
.
Probablemente conozcas los controles deslizantes interactivos de imágenes de antes y después. Es posible que incluso hayas visto algo así aquí mismo en CSS-Tricks. Lo he visto en Compressor.io, que uso a menudo para comprimir imágenes, ¡incluidas las que se usan en estos artículos!
Nuestro objetivo es crear algo así utilizando un único elemento HTML, menos de 100 bytes de JavaScript, ¡y ni siquiera mucho CSS!
Nuestro elemento va a ser un rango input
. No configuramos sus atributos min
o max
, por lo que de forma predeterminada son 0
y 100
, respectivamente. Tampoco configuramos el atributo de valor, por lo que el valor predeterminado es 50
, que también es el valor que le damos a una propiedad personalizada, --k
establecida en su style
atributo.
input type='range' style='--k: 50'/
En CSS, comenzamos con un reinicio básico, luego creamos input
un block
elemento que ocupa toda la altura de la ventana gráfica. También le damos dimensiones y fondos ficticios a su pista y pulgar para que podamos comenzar a ver cosas en la pantalla de inmediato.
$thumb-w: 5em;@mixin track() { border: none; width: 100%; height: 100%; background: url(flowers.jpg) 50%/ cover;}@mixin thumb() { border: none; width: $thumb-w; height: 100%; background: purple;}* { margin: 0; padding: 0;}[type='range'] { , ::-webkit-slider-thumb, ::-webkit-slider-runnable-track { -webkit-appearance: none; } display: block; width: 100vw; height: 100vh; ::-webkit-slider-runnable-track { @include track; } ::-moz-range-track { @include track; } ::-webkit-slider-thumb { @include thumb; } ::-moz-range-thumb { @include thumb; }}
El siguiente paso es agregar otra background
capa en la pista, una linear-gradient
donde la línea de separación entre transparent
y white
dependa del input
valor del rango actual, --k
y luego fusionar las dos.
@mixin track() { /* same as before */ background: url(flowers.jpg) 50%/ cover, linear-gradient(90deg, transparent var(--p), white 0); background-blend-mode: exclusion;}[type='range'] { /* same as before */ --p: calc(var(--k) * 1%);}
Tenga en cuenta que el orden de las dos background
capas de la pista no importa ya que ambas exclusion
son difference
conmutativas.
Está empezando a parecerse a algo, pero arrastrar el pulgar no hace nada para mover la línea de separación. Esto sucede porque el valor actual --k
(del cual depende la posición de la línea de separación del gradiente --p
) no se actualiza automáticamente. Arreglemos eso con un poquito de JavaScript que obtiene el valor del control deslizante cada vez que cambia y luego se establece --k
en este valor.
addEventListener('input', e = { let _t = e.target; _t.style.setProperty('--k', +_t.value)})
¡Ahora todo parece estar funcionando bien!
¿Pero lo es realmente? Digamos que hacemos algo un poco más sofisticado para el pulgar background
:
$thumb-r: .5*$thumb-w;$thumb-l: 2px;@mixin thumb() { /* same as before */ --list: #fff 0% 60deg, transparent 0%; background: conic-gradient(from 60deg, var(--list)) 0/ 37.5% /* left arrow */, conic-gradient(from 240deg, var(--list)) 100%/ 37.5% /* right arrow */, radial-gradient(circle, transparent calc(#{$thumb-r} - #{$thumb-l} - 1px) /* inside circle */, #fff calc(#{$thumb-r} - #{$thumb-l}) calc(#{$thumb-r} - 1px) /* circle line */, transparent $thumb-r /* outside circle */), linear-gradient( #fff calc(50% - #{$thumb-r} + .5*#{$thumb-l}) /* top line */, transparent 0 calc(50% + #{$thumb-r} - .5*#{$thumb-l}) /* gap behind circle */, #fff 0 /* bottom line */) 50% 0/ #{$thumb-l}; background-repeat: no-repeat;}
Deja un comentario