
Esquinas recortadas en 2018

Cuando vi el artículo de Chris sobre cajas con muescas, recordé que hace un tiempo recibí un desafío para usar CSS en un diseño como el siguiente en varios navegadores:
Se parece bastante al concepto de cajas con muescas, excepto que las esquinas ahora están recortadas y solo tenemos que preocuparnos de una esquina por caja. Entonces, veamos cómo podemos hacerlo, cómo podemos expandir la técnica a múltiples rincones, qué problemas encontramos y cómo podemos solucionarlos con o sin comprometer el soporte del navegador.
La idea inicial: box-shadow!
Comenzamos con un elemento de caja:
pseudoelemento cuadrado cuya longitud de borde es igual al diámetro (o el doble del radio $r
) de la pala en la esquina. También le damos a este pseudoelemento un color rojizo box-shadow
y una ficción background
(que eliminaremos más adelante) solo para que podamos verlo mejor:
*/ :before { position: absolute; padding: $r; box-shadow: 0 0 7px #b53; background: #95a; content: '' }}
Y esto es lo que tenemos hasta ahora:
Bueno, no parece demasiado emocionante… ¡todavía! Así que sigamos adelante y hagamos de este cuadrado un disco configurándolo border-radius: 50%
y dándole un negativo margin
igual a su radio $r
, de modo que su punto central coincida con el (0,0)
punto (esquina superior izquierda) de su cuadro principal. También configuramos overflow: hidden
el cuadro principal, de modo que se corte todo lo que esté fuera de este pseudoelemento .box
.
*/ :before { /* same styles as before */ margin: -$r; border-radius: 50% }}
Ahora estamos empezando a ver la forma que buscábamos:
Pero todavía no es exactamente lo que queremos. Para llegar allí, utilizamos el cuarto valor de longitud de la box-shadow
propiedad: el radio de extensión . Si necesitas un repaso sobre cómo box-shadow
funciona con estos cuatro valores, puedes consultar la demostración interactiva a continuación:
Quizás ya hayas adivinado lo que hacemos a continuación. Eliminamos la ficticio background
, ponemos a cero los primeros tres box-shadow
valores (los desplazamientos x e y y la radio de desenfoque) y usamos un número bastante grande para el último (el radio de extensión):
*/ border-radius: 1em; :before { /* same styles as before */ box-shadow: 0 0 0 300px rgba(#95a, .75); }}
Por supuesto, tal como Chris señaló en el artículo sobre cajas con muescas, podemos hacer que el radio de la muesca sea una variable CSS y luego modificarla fácilmente desde JavaScript. Luego, todo se actualiza correctamente, incluso con contenido de texto en nuestra caja:
*/ padding: var(--r); :before { /* same styles as before */ margin: calc(-1*var(--r)); padding: inherit;}
Tenga en cuenta que cuando también tenemos contenido de texto, debemos establecer un negativo z-index
en el ::before
pseudoelemento y colocarlo explícitamente en la esquina, ya que ahora también tenemos un padding
para .box
compensar la primicia.
*/ :before { /* same styles as before */ z-index: -1; top: 0; left: 0}
Aplicando esta técnica
Ahora, avancemos un poco más y veamos cómo podemos aplicar este concepto para reproducir el diseño que mostré al principio. En este caso particular, los puntos centrales de los pseudo-discos de los elementos no coinciden con las esquinas de las cajas, sino que están afuera, en el medio del espacio entre las cajas.
La estructura utilizada es bastante sencilla, solo un header
elemento seguido de cuatro article
elementos que generé en un bucle Pug:
{ /* set generic offsets */ top: calc((1 + var(--j))*50% - var(--r) + var(--j)*#{$m}); left: calc((1 + var(--i))*50% - var(--r) + var(--i)*#{$m}); }}@media (min-width: 2*($min-w + 2*$m)) { article { /* change vertical multiplier for first two (on 1st row of 2x2 grid) */ :nth-of-type(-n + 2) { --j: 1 } /* change horizontal multiplier for odd ones (on 1st column) */ :nth-of-type(odd) { --i: 1 }}
Tenga en cuenta que solo tenemos recortes de disco visibles en el section
elemento para los dos primeros article
elementos y solo en el h3
para los dos últimos. Por lo tanto, para los dos primeros article
elementos, el radio en el pseudoelemento --r
del encabezado es , mientras que para los dos últimos, este radio es para el pseudoelemento de la sección :::before
0
0
::before
{ --r: 0 ; } } }}
De manera similar, agregamos paddings diferenciados a los hijos de los article
elementos:
*/ /* any CSS background we wish */ mask: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0);}
Tenga en cuenta que los navegadores WebKit aún necesitan el -webkit-
prefijo para las mask
propiedades.
Luego agregamos los círculos en las otras esquinas:
*/ /* any CSS background we wish */ mask: $grad-list}
Eso es increíblemente repetitivo, ya sea mucho escribir o mucho copiar y pegar, así que veamos qué podemos hacer al respecto.
En primer lugar, utilizamos una variable CSS para la lista de exclusión. Esto elimina la repetición en el CSS generado.
*/ /* any CSS background we wish */ --stop-list: #000 var(--r, 50px), transparent 0; mask: $grad-list;}
Pero todavía no es mucho mejor, así que generemos las esquinas dentro de un bucle:
*/ /* any CSS background we wish */ --stop-list: #000 var(--r, 50px), transparent 0; mask: $grad-list;}
Mucho mejor en cuanto al código porque ahora no tenemos que escribir nada varias veces y correr el riesgo de no actualizarlo en todas partes más adelante. Pero el resultado hasta ahora no es el que buscábamos:
Aquí estamos cortando todo excepto las esquinas, que es lo opuesto a lo que queremos.
Una cosa que podemos hacer es invertir los degradados, hacer los círculos de las esquinas transparent
y el resto black
con:
*/ /* any CSS background we wish */ --stop-list: transparent var(--r, 50px), #000 0; mask: $grad-list; mask-size: 50% 50%; mask-repeat: no-repeat;}
Tenga en cuenta que los navegadores WebKit aún necesitan el -webkit-
prefijo para mask
las propiedades.
Pero el gran problema aquí es... el problema con la división y el redondeo en general: nuestros cuatro cuartos juntos no siempre logran formar un todo nuevamente, por lo que terminamos con espacios entre ellos.
Bueno, no es como si no pudiéramos cubrir esos huecos con linear-gradient()
tiras finas o aumentar el , mask-size
digamos 51%
:
¿Pero no existe una forma más elegante?
Bueno, hay una mask-composite
propiedad que puede ayudarnos si la configuramos intersect
al volver a las capas de degradado de tamaño completo.
*/ /* any CSS background we wish */ --stop-list: transparent var(--r, 50px), #000 0; mask: $grad-list; mask-composite: intersect;}
Esto es muy bueno porque es un CSS puro, no una solución SVG, pero la noticia no tan buena es que el soporte está limitado a Firefox 53+.
Sin embargo, al menos tenemos la -webkit-mask-composite
alternativa no estándar (¡tomando valores diferentes!) para los navegadores WebKit. Así que eso es mucho mejor que el apoyo a la última opción que tenemos cuando se trata de curvas cerradas.
La corner-shapeopción
A Lea Verou se le ocurrió esta idea hace unos cinco años e incluso creó una página de vista previa. Lamentablemente, no solo no está implementada todavía en ningún navegador, sino que la especificación no ha avanzado mucho desde entonces. Aún es algo que hay que tener en cuenta para el futuro, ya que ofrece mucha flexibilidad con muy poco código: recrear nuestro efecto solo requeriría lo siguiente:
padding: var(--r);corner-shape: scoop;border-radius: var(--r);
Sin vómitos de marcado, sin largas listas de gradientes, solo este sencillo fragmento de CSS. ¡Eso es… cuando finalmente sea compatible con los navegadores!
Deja una respuesta