Cómo comenzar a usar las formas CSS

Cómo unir contenido alrededor de rutas personalizadas

Durante mucho tiempo, los diseñadores web se vieron obligados a crear dentro de las limitaciones del rectángulo. La mayor parte del contenido de la Web sigue atrapado en cuadros simples porque la mayoría de las iniciativas creativas en diseños no rectangulares terminan en frustración. Eso está a punto de cambiar con la introducción de las formas CSS, disponibles a partir de Chrome 37. Las formas de CSS permiten a los diseñadores web unir el contenido alrededor de trazados personalizados, como círculos, elipses y polígonos, lo que permite liberarse de las restricciones del rectángulo.

Las formas se pueden definir de forma manual o inferir a partir de imágenes.

Veamos un ejemplo muy sencillo.

Tal vez hayas sido tan ingenuo como yo cuando flotaste una imagen con partes transparentes esperando que el contenido se uniera y llenara los espacios, solo para decepcionarte con la forma rectangular que persiste alrededor del elemento. Las formas de CSS se pueden usar para resolver este problema.

Extrae una forma de una imagen
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>

<style>
.element{
  shape-outside: url(image.png);
  shape-image-threshold: 0.5;
  float: left;
}
</style>

La declaración CSS shape-outside: url(image.png) le indica al navegador que extraiga una forma de la imagen.

La propiedad shape-image-threshold define el nivel mínimo de opacidad de los píxeles que se usarán para crear la forma. Su valor debe estar entre 0.0 (completamente transparente) y 1.0 (completamente opaco). Por lo tanto, shape-image-threshold: 0.5 significa que solo se usarán píxeles con una opacidad del 50% o superior para crear la forma.

La propiedad float es clave aquí. Si bien la propiedad shape-outside define la forma del área alrededor de la cual se unirá el contenido, sin el número de punto flotante, no verás los efectos de la forma.

Los elementos tienen un área flotante en el lado opuesto de su valor float. Por ejemplo, si un elemento con una imagen de taza de café se coloca a la izquierda, el área flotante se creará a la derecha de la taza. Si bien puedes diseñar una imagen con espacios en ambos lados, el contenido solo se unirá a la forma del lado opuesto designado por la propiedad de flotación, a la izquierda o a la derecha, nunca a ambos.

En el futuro, será posible usar shape-outside en elementos que no estén flotando con la introducción de Exclusiones de CSS.

Crea formas de forma manual

Además de extraer formas de las imágenes, también puedes codificarlas de forma manual. Puedes elegir entre algunos valores funcionales para crear formas: circle(), ellipse(), inset() y polygon(). Cada función de forma acepta un conjunto de coordenadas y se vincula con un cuadro de referencia que establece el sistema de coordenadas. En un momento, hablaremos más sobre los cuadros de referencia.

La función circle()

Ilustración del valor de la forma circle()

La notación completa para un valor de forma de círculo es circle(r at cx cy), en la que r es el radio del círculo, mientras que cx y cy son las coordenadas del centro del círculo en el eje X y el eje Y. Las coordenadas del centro del círculo son opcionales. Si los omites, se usará el centro del elemento (la intersección de sus diagonales) como predeterminado.

.element{
  shape-outside: circle(50%);
  width: 300px;
  height: 300px;
  float: left;
}

En el ejemplo anterior, el contenido se unirá alrededor del exterior de una ruta circular. El único argumento 50% especifica el radio del círculo, que, en este caso específico, equivale a la mitad del ancho o la altura del elemento. Si cambias las dimensiones del elemento, se verá afectado el radio de la forma circular. Este es un ejemplo básico de cómo las formas CSS pueden ser responsivas.

Antes de continuar, ten en cuenta que es importante recordar que las formas de CSS solo influyen en la forma del área flotante alrededor de un elemento. Si el elemento tiene un fondo, la forma no lo recortará. Para lograr ese efecto, debes usar propiedades de máscaras de CSS, ya sea clip-path o mask-image. La propiedad clip-path resulta muy útil porque sigue la misma notación que las formas de CSS, por lo que puedes volver a usar los valores.

Ilustración de la forma &quot;circle()`&quot; + clip-path

En las ilustraciones de este documento, se usa el recorte para destacar la forma y ayudarte a comprender los efectos.

Regresa a la forma de círculo.

Cuando se usan porcentajes para el radio del círculo, el valor se calcula con una fórmula un poco más compleja: sqrt(width^2 + height^2) / sqrt(2). Es útil comprender esto porque te ayudará a imaginar cómo será la forma del círculo resultante si las dimensiones del elemento no son iguales.

Todos los tipos de unidades de CSS se pueden usar en las coordenadas de la función de forma: px, em, rem, vw, vh, etcétera. Puedes elegir la que sea lo suficientemente flexible o rígida para tus necesidades.

Para ajustar la posición del círculo, establece valores explícitos para las coordenadas de su centro.

.element{
  shape-outside: circle(50% at 0 0);
}

Esto posiciona el centro del círculo en el origen del sistema de coordenadas. ¿Qué es el sistema de coordenadas? Aquí es donde presentamos los cuadros de referencia.

Cuadros de referencia para formas de CSS

El cuadro de referencia es un cuadro virtual alrededor del elemento que establece el sistema de coordenadas que se usa para dibujar y posicionar la forma. El origen del sistema de coordenadas se encuentra en la esquina superior izquierda, con el eje X apuntando hacia la derecha y el eje Y hacia abajo.

Sistema de coordenadas para formas de CSS

Recuerda que shape-outside altera la forma del área flotante alrededor de la cual se unirá el contenido. El área flotante se extiende hasta los bordes exteriores del cuadro definido por la propiedad margin. Esto se denomina margin-box y es el cuadro de referencia predeterminado para una forma si no se menciona ninguna de forma explícita.

Las siguientes dos declaraciones de CSS tienen resultados idénticos:

.element{
  shape-outside: circle(50% at 0 0);
  /* identical to: */
  shape-outside: circle(50% at 0 0) margin-box;
}

Aún no configuramos un margen en el elemento. En este punto, es seguro suponer que el origen del sistema de coordenadas y el centro del círculo están en la esquina superior izquierda del área de contenido del elemento. Esto cambia cuando estableces un margen:

.element{
  shape-outside: circle(50% at 0 0) margin-box;
  margin: 100px;
}

El origen del sistema de coordenadas ahora se encuentra fuera del área de contenido del elemento (100 px hacia arriba y 100 px hacia la izquierda), al igual que el centro del círculo. El valor calculado del radio del círculo también aumenta para dar cuenta del aumento de la superficie del sistema de coordenadas establecido por el cuadro de referencia margin-box.

Sistema de coordenadas de margen de cuadro con y sin margen
Existen algunas opciones de cuadros de referencia para elegir: "margin-box", "border-box", "padding-box" y "content-box". Sus nombres implican sus límites. Anteriormente, explicamos el "margin-box". El "border-box" está limitado por los bordes exteriores del elemento, el "padding-box" está limitado por el padding del elemento, mientras que el "content-box" es idéntico a la superficie real que usa el contenido dentro de un elemento.
Ilustración de todas las casillas de referencia

Solo se puede usar un cuadro de referencia a la vez con una declaración shape-outside. Cada cuadro de referencia influirá en la forma de una manera diferente y, a veces, sutil. Hay otro artículo que profundiza en el tema y te ayuda a comprender los cuadros de referencia para las formas de CSS.

La función ellipse()

Ilustración del valor de la forma ellipse()

Las elipses parecen círculos aplastados. Se definen como ellipse(rx ry at cx cy), donde rx y ry son los radios de la elipse en el eje X y el eje Y, mientras que cx y cy son las coordenadas del centro de la elipse.

.element{
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

Los valores de porcentaje se calcularán a partir de las dimensiones del sistema de coordenadas. No se requieren cálculos complicados. Puedes omitir las coordenadas del centro de la elipse, y se inferirán del centro del sistema de coordenadas.

Los radios en los ejes X e Y también se pueden definir con palabras clave: farthest-side genera un radio igual a la distancia entre el centro de la elipse y el lado del cuadro de referencia más alejado de él, mientras que closest-side significa exactamente lo contrario: usa la distancia más corta entre el centro y un lado.

.element{
  shape-outside: ellipse(closest-side farthest-side at 50% 50%);
  /* identical to: */
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

Esto puede resultar útil cuando las dimensiones del elemento (o el cuadro de referencia) pueden cambiar de forma impredecible, pero deseas que la forma de elipse se adapte.

Las mismas palabras clave farthest-side y closest-side también se pueden usar para el radio en la función de forma circle().

La función polygon()

Ilustración del valor de la forma polygon()

Si los círculos y las elipses son demasiado limitantes, la función de forma de polígono abre un mundo de opciones. El formato es polygon(x1 y1, x2 y2, ...), en el que especificas pares de coordenadas x e y para cada vértice (punto) de un polígono. La cantidad mínima de pares para especificar un polígono es tres, un triángulo.

.element{
  shape-outside: polygon(0 0, 0 300px, 300px 600px);
  width: 300px;
  height: 600px;
}

Los vértices se colocan en el sistema de coordenadas. En el caso de los polígonos responsivos, puedes usar valores porcentuales para algunas o todas las coordenadas.

.element{
  /* polygon responsive to font-size*/
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  width: 20em;
  height: 40em;
}

Hay un parámetro fill-rule opcional, importado desde SVG, que le indica al navegador cómo considerar la “interioridad” de un polígono en caso de rutas que se cruzan o formas cerradas. Joni Trythall explica muy bien cómo funciona la propiedad fill-rule en SVG. Si no se define, el valor predeterminado de fill-rule es nonzero.

.element{
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  /* identical to: */
  shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}

La función inset()

La función de forma inset() te permite crear formas rectangulares alrededor de las cuales unir el contenido. Esto puede parecer contraintuitivo si tenemos en cuenta la premisa inicial de que CSS Shapes crea contenido web gratuito a partir de cuadros simples. Es muy probable. Aún no encuentro un caso de uso para inset() que no se pueda lograr con números de punto flotante y márgenes, o con un polygon(). Sin embargo, inset() proporciona una expresión más legible para las formas rectangulares que polygon().

La notación completa de una función de forma insertada es inset(top right bottom left border-radius). Los primeros cuatro argumentos de posición son compensaciones hacia adentro desde los bordes del elemento. El último argumento es el radio del borde de la forma rectangular. Es opcional, por lo que puedes omitirla. Sigue la notación abreviada border-radius que ya usas en CSS.

.element{
  shape-outside: inset(100px 100px 100px 100px);
  /* yields a rectangular shape which is 100px inset on all sides */
  float: left;
}

Cómo crear formas a partir de cuadros de referencia

Si no especificas una función de forma para la propiedad shape-outside, puedes permitir que el navegador derive una forma del cuadro de referencia del elemento. El cuadro de referencia predeterminado es margin-box. Hasta ahora, no hay nada exótico, así es como funcionan los números de punto flotante. Sin embargo, si aplicas esta técnica, puedes volver a usar la geometría de un elemento. Veamos la propiedad border-radius.

Si lo usas para redondear las esquinas de un elemento flotante, se obtiene el efecto de recorte, pero el área flotante sigue siendo rectangular. Agrega shape-outside: border-box para unir el contorno creado por border-radius.

Extracción de una forma del atributo border-radius de un elemento con el cuadro de referencia de border-box
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

Por supuesto, puedes usar todos los cuadros de referencia de esta manera. Este es otro uso de las formas derivadas: las citas destacadas desplazadas.

Cómo crear una cita destacada desplazada con el cuadro de referencia del cuadro de contenido

Es posible lograr el efecto de cita destacada desplazada solo con las propiedades de margen y flotación. Sin embargo, eso requiere que posiciones el elemento de comillas en el árbol HTML en el punto en el que deseas que se renderice.

A continuación, te mostramos cómo lograr el mismo efecto de cita destacada desplazada con mayor flexibilidad:

.pull-quote{
  shape-outside: content-box;
  margin-top: 200px;
  float: left;
}

Establecemos explícitamente el cuadro de referencia content-box para el sistema de coordenadas de la forma. En este caso, la cantidad de contenido en la cita define la forma alrededor de la cual se unirá el contenido externo. La propiedad margin-top se usa aquí para posicionar (desplazar) la cita, independientemente de su posición en el árbol HTML.

Margen de la forma

Notarás que unir el contenido alrededor de una forma puede hacer que se frote demasiado contra el elemento. Puedes agregar espacio alrededor de la forma con la propiedad shape-margin.

.element{
  shape-outside: circle(40%);
  shape-margin: 1em;
  float: left;
}

El efecto es similar al que obtienes con la propiedad margin normal, pero shape-margin solo afecta el espacio alrededor del valor shape-outside. Agregará espacio alrededor de la forma solo si hay espacio para ello en el sistema de coordenadas. Por eso, en el ejemplo anterior, el radio del círculo se establece en 40%, no en 50%. Si el radio se hubiera establecido en el 50%, el círculo habría ocupado todo el espacio en el sistema de coordenadas, sin dejar espacio para el efecto de shape-margin. Recuerda que, en última instancia, la forma está restringida al margin-box del elemento (el elemento más su margin circundante). Si la forma es más grande y se desborda, se recortará en el margin-box y obtendrás una forma rectangular.

Es importante comprender que shape-margin solo acepta un valor positivo. No tiene una notación larga. ¿Qué es shape-margin-top para un círculo?

Cómo animar formas

Puedes combinar formas de CSS con muchas otras funciones de CSS, como transiciones y animaciones. Sin embargo, debo enfatizar que a los usuarios les resulta muy molesto que el diseño del texto cambie mientras leen. Presta mucha atención a la experiencia si decides animar las formas.

Puedes animar los radios y centros de las formas circle() y ellipse(), siempre que estén definidos en valores que el navegador pueda interpolar. Es posible ir de circle(30%) a circle(50%). Sin embargo, animar entre circle(closest-side) y circle(farthest-side) bloqueará el navegador.

.element{
  shape-outside: circle(30%);
  transition: shape-outside 1s;
  float: left;
}

.element:hover{
  shape-outside: circle(50%);
}
GIF de círculo animado

Se pueden lograr efectos más interesantes cuando se animan formas polygon(), con la nota importante de que el polígono debe tener la misma cantidad de vértices entre los dos estados de animación. El navegador no puede interpolar si agregas o quitas vértices.

Un truco es agregar la cantidad máxima de vértices que necesitas y posicionarlos agrupados en el estado de animación en el que deseas que la forma tenga menos bordes percibidos.

.element{
  /* four vertices (looks like rectangle) */
  shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transition: shape-outside 1s;
}

.element:hover{
  /* four vertices, but second and third overlap (looks like triangle) */
  shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
GIF de triángulo animado

Cómo unir contenido dentro de una forma

Captura de pantalla de la demostración de Alicia en el país de las maravillas con formas de CSS para unir el contenido

El borrador inicial de la especificación de formas de CSS incluía una propiedad shape-inside que te permitía unir el contenido dentro de una forma. Incluso hubo implementaciones en Chrome y Webkit durante un tiempo. Sin embargo, unir contenido posicionado de forma arbitraria dentro de una ruta personalizada requiere mucho más esfuerzo y investigación para abarcar todas las situaciones posibles y evitar errores. Es por eso que la propiedad shape-inside se aplazó al nivel 2 de formas de CSS y se retiraron las implementaciones para ella.

Sin embargo, con un poco de esfuerzo y compromiso, puedes lograr el efecto de unir el contenido dentro de una forma personalizada. El hack consiste en usar dos elementos flotantes con shape-outside, posicionados en lados opuestos de un contenedor. El compromiso es que debes usar uno o dos elementos vacíos que no tienen significado semántico, pero que sirven como puntales para crear la ilusión de una forma en el interior.

<div>
  <div class='left-shape'></div>
  <div class='right-shape'></div>

  Lorem ipsum...
</div>

La posición de los elementos de soporte .left-shape y .right-shape en la parte superior del contenedor es importante porque flotarán hacia la izquierda y la derecha para flanquear el contenido.

.left-shape{
  shape-outside: polygon(0 0, ...);
  float: left;
  width: 50%;
  height: 100%;
}

.right-shape{
  shape-outside: polygon(50% 0, ...);
  float: right;
  width: 50%;
  height: 100%;
}
Ilustración de la solución alternativa para shape-inside para la demo de Alice

Este diseño hace que los dos elementos flotantes ocupen todo el espacio dentro del elemento, pero las propiedades shape-outside reservan espacio para el resto del contenido.

Si el navegador no admite las formas CSS, se producirán efectos feos, ya que se empujará todo el contenido hacia abajo. Por eso, es importante usar la función de forma progresivamente mejorada.

En los ejemplos anteriores de animación de formas, notarás que el texto que se mueve puede ser molesto. No todos los casos de uso garantizan una forma animada. Sin embargo, puedes animar otras propiedades que interactúan con las formas de CSS para agregar efectos donde tenga sentido.

En la demostración de Alicia en el país de las maravillas de las formas de CSS, usamos la posición de desplazamiento para cambiar el margen superior del contenido. El texto se comprime entre dos elementos flotantes. A medida que se mueve hacia abajo, debe volver a diseñarse según el shape-outside de los dos elementos flotantes. Esto da la impresión de que el texto se está yendo por el camino equivocado y agrega a la experiencia de contar historias. ¿Es un contenido gratuito en el límite? Tal vez. Pero se ve bien.

Debido a que el navegador realiza el diseño de texto de forma nativa, el rendimiento es mejor que usar una solución de JavaScript. Sin embargo, cambiar el margen superior durante el desplazamiento activa muchos eventos de reordenamiento y pintura, lo que puede reducir notablemente el rendimiento. Usar con precaución. Sin embargo, usar formas CSS sin animarlas no genera un impacto perceptible en el rendimiento.

Mejora progresiva

Comienza por suponer que el navegador no es compatible con las formas de CSS y, luego, desarrolla esa idea cuando detectes la función. Modernizr es una buena solución para realizar la detección de funciones, y hay una prueba para las formas CSS en la sección 'Non-core detects'.

Algunos navegadores proporcionan detección de funciones en CSS a través de la regla @supports sin necesidad de bibliotecas externas. Google Chrome, que también admite formas de CSS, comprende la regla @supports. Así es como se usa para mejorar de forma progresiva:

.element{
  /* styles for all browsers */
}

@supports (shape-outside: circle(50%)){
  /* styles only for browsers which support CSS Shapes */
  .element{
    shape-outside: circle(50%);
  }
}

Lea Verou escribió más sobre cómo usar la regla @supports de CSS.

Eliminación de ambigüedades de las exclusiones de CSS

Lo que hoy conocemos como formas de CSS solía llamarse exclusiones y formas de CSS en los primeros días de la especificación. El cambio en los nombres puede parecer un matiz, pero en realidad es muy importante. Las exclusiones de CSS, ahora una especificación independiente, permiten unir el contenido alrededor de elementos posicionados de forma arbitraria, sin necesidad de una propiedad de flotación. Imagina unir contenido alrededor de un elemento con posición absoluta. Ese es un caso de uso para las exclusiones de CSS. Las formas de CSS solo definen la ruta alrededor de la cual se unirá el contenido.

Por lo tanto, las formas y las exclusiones no son lo mismo, pero se complementan. Las formas de CSS están disponibles en los navegadores en la actualidad, mientras que las exclusiones de CSS aún no se implementan con la interacción de formas.

Herramientas para trabajar con formas de CSS

Puedes crear rutas de acceso en herramientas clásicas de creación de imágenes, pero, en el momento de escribir este artículo, ninguna de ellas exporta la sintaxis requerida para los valores de CSS Shapes. Incluso si lo hicieran, trabajar de esa manera no sería muy práctico.

Las formas de CSS están diseñadas para usarse en el navegador, donde reaccionan a otros elementos de la página. Es muy útil visualizar los efectos de editar la forma en el contenido que la rodea. Existen algunas herramientas que te ayudarán con este flujo de trabajo:

Brackets: La extensión Editor de formas de CSS para Brackets usa el modo de vista previa en vivo del editor de código para superponer un editor interactivo para editar valores de forma.

Google Chrome: La extensión Editor de formas de CSS para Google Chrome extiende las herramientas para desarrolladores del navegador con controles para crear y editar formas. Coloca un editor interactivo sobre el elemento seleccionado.

El inspector de Google Chrome tiene compatibilidad integrada para destacar formas. Coloca el cursor sobre un elemento con una propiedad shape-outside y se iluminará para ilustrar la forma.

Formas a partir de imágenes: Si prefieres generar imágenes y que el navegador extraiga formas de ellas, Rebecca Hauck escribió un buen instructivo para Photoshop.

Relleno de espacios: Google Chrome es el primer navegador importante en enviar formas CSS. Pronto se admitirá la función en iOS 8 y Safari 8 de Apple. Es posible que otros proveedores de navegadores lo consideren en el futuro. Hasta entonces, hay un polyfill de formas de CSS para proporcionar compatibilidad básica.

Conclusión

En una Web en la que el contenido está atrapado en su mayoría en cuadros simples, las formas CSS proporcionan una forma de crear un diseño expresivo que cierra la brecha de fidelidad entre el diseño web y el impreso. Por supuesto, se puede abusar de las formas y crear distracciones. Sin embargo, cuando se aplican con buen gusto y prudencia, las formas pueden mejorar la presentación del contenido y enfocar la atención del usuario de una manera única.

Te dejo una colección de trabajos de otros diseñadores, en su mayoría impresos, que demuestran usos interesantes para diseños no rectangulares. Espero que esto te inspire a probar las formas de CSS y experimentar con nuevas ideas de diseño.

Muchas gracias a Pearl Chen, Alan Stearns y Zoltan Horvath por revisar este artículo y proporcionar estadísticas valiosas.