Desafortunadamente, clip-path: path() sigue estando prohibido

Me emocioné mucho cuando escuché por primera vez que clip-path: path()llegaría a Firefox. ¡Imagínese poder codificar fácilmente un cuadro de respiración como el que se muestra a continuación con solo un elemento HTML y muy poco CSS sin necesidad de SVG o una lista enorme de puntos dentro de la función de polígono!

Chris también estaba entusiasmado con la implementación inicial.

Que divertido sería esto:

Decidí probarlo. Ingrese a CodePen, presione divun panel HTML, le di dimensiones en unidades de ventana gráfica para que se escalara bien y agregué un backgroundpara poder verlo. Luego entré a MDN para ver algunos ejemplos de uso… ¡y la nube esponjosa de mi sueño comenzó a fallar!

Tenga en cuenta que clip-path: path()solo funciona en Firefox 63-70 con la layout.css.clip-path-path.enabledbandera configurada trueen about:configy en Firefox 71+ sin necesidad de habilitar ninguna bandera. (Fuente: MDN.)

Estos fueron los ejemplos que encontré:

path('M0 200L0 110A110 90 0 0 1 240 100L 200 340z')path('M.5 1C.5 1 0 .7 0 .3A.25 .25 1 1 1 .5 .3 .25 .25 1 1 1 1 .3C1 .7 .5 1 .5 1Z')

¿Cuales son esas coordenadas? ¡La triste respuesta son los valores de píxeles ! Se utilizan porque la path()función toma una pathcadena SVG como argumento que, al igual que el valor del datributo SVG en un pathelemento, solo contiene un tipo de valor de coordenadas: píxeles sin unidades. En el caso de SVG, estos píxeles se escalan con el viewBoxdel svgelemento, ¡pero no se escalan en absoluto dentro de la path()función CSS!

Esto significa que el elemento siempre se recorta en la misma área fija si tenemos un elemento responsable con un path()valor para la clip-pathpropiedad. Por ejemplo, considere un cuadrado .boxcuya longitud de arista es 35vw. Lo recortamos a un corazón usando la path()función:

clip-path: path('M256 203C150 309 150 309 44 203 15 174 15 126 44 97 73 68 121 68 150 97 179 68 227 68 256 97 285 126 285 174 256 203')

Esta forma de corazón permanece del mismo tamaño mientras que las dimensiones de nuestro .boxelemento real cambian con la ventana gráfica:

Estas son malas noticias en 2020, donde el diseño responsivo es el estándar, no la excepción. Salvo en el extraño caso en el que el elemento que queremos recortar en realidad tiene un tamaño de píxel fijo, ¡la path()función es completamente inútil! Todavía es mejor usar un SVG real hoy en día, o incluso un polygon()valor aproximado para clip-path. En definitiva, path()todavía necesita mejoras, a pesar de haber despegado.

Amelia Bellamy-Royds ha sugerido aquí dos posibilidades:

Opción 1: Permitir calc()valores/unidades dentro de pathlos datos. Esto probablemente se haría al extender pathla sintaxis SVG en general.

Opción 2: Especificar viewBoxen clip-pathla declaración, escalar la ruta para que se ajuste.

Personalmente prefiero la primera opción. La única ventaja que ofrece el segundo sobre el uso de SVG es el hecho de que no tenemos que incluir un SVG real. Dicho esto, incluir un SVG real siempre tendrá un mejor soporte.

La primera opción, sin embargo, podría ser una gran mejora con respecto al uso de SVG: al menos una mejora suficiente para justificar su uso clip-pathen un elemento HTML en lugar de incluir un SVG dentro de él. Consideremos el cuadro de respiración en la parte superior de esta publicación. Usando SVG, tenemos el siguiente marcado:

svg viewBox='-75 -50 150 100'  path//svg

Tenga en cuenta que viewBoxestá configurado de manera que el 0,0punto esté muerto en el medio. Esto significa que tenemos que hacer que las coordenadas de la esquina superior izquierda (es decir, los dos primeros viewBoxvalores) sean iguales a menos la mitad de las viewBoxdimensiones (es decir, los dos últimos viewBoxvalores).

En SCSS, establecemos la longitud del borde ( $l) del cuadro cuadrado inicial como la viewBoxdimensión más pequeña (que es el más pequeño de los dos últimos valores). Este es 100nuestro caso.

Comenzamos el camino desde la esquina superior izquierda de nuestro cuadro cuadrado. Esto significa un comando de movimiento a ( M) hasta este punto, con coordenadas que son ambas iguales a menos la mitad de la longitud del borde.

Luego bajamos a la esquina inferior izquierda. Esto requiere dibujar una línea vertical con una longitud que sea igual a la longitud del borde ( $l) y que descienda, en la dirección positiva del eje y . Entonces, usaremos el vcomando.

A continuación, nos situamos en la esquina inferior derecha. Dibujaremos una línea horizontal con una longitud igual a la longitud del borde ( $l) y va hacia la derecha, en la dirección positiva del eje x . Usaremos el hcomando para que eso suceda.

Ir a la esquina superior derecha significa dibujar otra línea vertical con una longitud igual a la longitud del borde ( $l), por lo que usaremos el vcomando nuevamente, solo que esta vez, la diferencia es el hecho de que vamos en la dirección opuesta a la Eje y , lo que significa que usamos las mismas coordenadas, pero con un signo menos.

Juntándolo todo, tenemos el SCSS que nos permite crear el cuadro cuadrado inicial:

.box {  d: path('M#{-.5*$l},#{-.5*$l} v#{$l} h#{$l} v#{-$l}');  fill: darkorange}

El CSS generado (donde $lse reemplaza por 100) se ve así:

.box {  d: path('M-50,-50 v100 h100 v-100');  fill: darkorange;}

El resultado se puede ver en la demostración interactiva a continuación, donde al pasar el cursor sobre una parte de los datos de la ruta se resalta la parte correspondiente en el SVG resultante y al revés:

Sin embargo, si queremos que los bordes laterales respiren, no podemos utilizar líneas rectas. Reemplacémoslos por qunos cuadráticos de Bézier ( ). El punto final sigue siendo el mismo, que está a un largo de borde hacia abajo a lo largo de la misma línea vertical. Pasamos por 0,#{$l}allí para llegar.

Pero ¿qué pasa con el punto de control que debemos especificar antes de eso? Colocamos el punto verticalmente a medio camino entre los puntos inicial y final, lo que significa que bajamos hasta él la mitad de nuestro recorrido para llegar al punto final.

Y digamos que, en horizontal, lo colocamos un cuarto de longitud de borde hacia un lado en una dirección u otra. Si queremos que las líneas sobresalgan para ensanchar el cuadro o apretarlas para estrecharlo, debemos hacer algo como esto:

d: path('M#{-.5*$l},#{-.5*$l}          q#{-.25*$l},#{.5*$l} 0,#{$l}          h#{$l}          v#{-$l}'); /* swollen box */d: path('M#{-.5*$l},#{-.5*$l}          q#{.25*$l},#{.5*$l} 0,#{$l}          h#{$l}          v#{-$l}'); /* squished box */

Esto se compila con el siguiente CSS:

d: path('M-50,-50          q-25,50 0,100          h100          v-100'); /* swollen box */d: path('M-50,-50          q25,50 0,100          h100          v-100'); /* squished box */

La demostración interactiva a continuación muestra cómo pathfunciona esto. Puede pasar el cursor sobre los componentes de datos de ruta para verlos resaltados en el gráfico SVG. También puedes alternar entre las versiones hinchada y aplastada.

Este es sólo el borde izquierdo. También debemos hacer lo mismo con el borde derecho. La diferencia aquí es que vamos desde la esquina inferior derecha a la esquina superior derecha, que está hacia arriba (en la dirección negativa del eje y ). Colocaremos el punto de control fuera del cuadro para obtener el efecto de buey ancho, lo que también significa colocarlo a la derecha de sus puntos finales (en la dirección positiva del eje x ). Mientras tanto, colocaremos el punto de control adentro para obtener el efecto de cuadro estrecho, lo que significa colocarlo a la izquierda de sus puntos finales (en la dirección negativa del eje x ).

d: path('M#{-.5*$l},#{-.5*$l}          q#{-.25*$l},#{.5*$l} 0,#{$l}          h#{$l}          q#{.25*$l},#{-.5*$l} 0,#{-$l}'); /* swollen box */d: path('M#{-.5*$l},#{-.5*$l}          q#{.25*$l},#{.5*$l} 0,#{$l}          h#{$l}          q#{-.25*$l},#{-.5*$l} 0,#{-$l}'); /* squished box */

El SCSS anterior genera el CSS siguiente:

d: path('M-50,-50          q-25,50 0,100          h100          q25,-50 0,100'); /* swollen box */d: path('M-50,-50          q25,50 0,100          h100          q-25,-50 0,-100'); /* squished box */

Para conseguir el efecto respiratorio, animamos entre el estado hinchado y el estado aplastado:

.box {  d: path('M#{-.5*$l},#{-.5*$l}            q#{-.25*$l},#{.5*$l} 0,#{$l}            h#{$l}            q#{.25*$l},#{-.5*$l} 0,#{-$l}'); /* swollen box */  animation: breathe .5s ease-in-out infinite alternate}@keyframes breathe {  to {    d: path('M#{-.5*$l},#{-.5*$l}              q#{.25*$l},#{.5*$l} 0,#{$l}              h#{$l}              q#{-.25*$l},#{-.5*$l} 0,#{-$l}'); /* squished box */  }}

Dado que lo único que difiere entre los dos estados es el signo de la diferencia horizontal de los puntos de control (el signo del primer número después del qcomando curva cuadrática de Bézier), podemos simplificar las cosas con un mixin:

@mixin pdata($s: 1) {  d: path('M#{-.5*$l},#{-.5*$l}            q#{-.25*$s*$l},#{.5*$l} 0,#{$l}            h#{$l}            q#{.25*$s*$l},#{-.5*$l} 0,#{-$l}')}.box {  @include pdata();  animation: breathe .5s ease-in-out infinite alternate}@keyframes breathe { to { @include pdata(-1) } }

Esto es más o menos lo que estoy haciendo para la demostración real de la caja de respiración, aunque el movimiento es un poco más discreto. Aún así, esto no hace absolutamente nada por el CSS generado: todavía tenemos dos rutas largas, feas y casi idénticas en el código compilado.

Sin embargo, si pudiéramos usar un div, recortado con un clip-path: path()que admitiera todo tipo de valores, incluidos calc()los valores internos, entonces podríamos convertir el signo en una propiedad personalizada --sgn, que luego podríamos animar entre -1y 1con la ayuda de Houdini.

div.box {  width: 40vmin; height: 20vmin;  background: darkorange;  --sgn: 1;  clip-path: path(M 25%,0%                  q calc(var(--sgn)*-25%),50% 0,100%                  h 50%                  q calc(var(--sgn)*25%),-50% 0,-100%);  animation: breathe .5s ease-in-out infinite alternate}@keyframes breathe { to { --sgn: -1 } }

Ser capaz de hacer esto haría una gran diferencia. Nuestro elemento se escalaría muy bien con la ventana gráfica y también lo haría la caja de respiración que recortamos. Y, lo más importante, no necesitaríamos repetir este trazado de recorte para obtener las dos versiones diferentes (la hinchada y la aplastada), porque usar la propiedad personalizada del signo ( --sgn) dentro de un calc()valor sería suficiente. . Sin embargo, tal como está ahora, clip-path: path()es prácticamente inútil.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion