Flotación con texto envolviendo formas geométricas

CSS Shape, flotar y envolver texto

La especificación de formas geométricas CSS Shapes Module Level 1 nos permite crear una forma geométrica y flotarla, con lo que el texto envolverá dicha forma. También es posible usar una imagen como forma geométrica, tal que serán sus áreas de transparencia las que delimitarán como el texto envuelve a la imagen. La especificación está en fase CR y aún queda bastante para finalizar la implementación por parte de los navegadores, pero en algunos como Chrome 37 y Opera 24 ya puede usarse. Internet Explorer 10 y Firefox 24 aún no soportan esta especificación pero es posible que lo implementen en poco tiempo.

Flotar una imagen y que el texto la envuelva es algo que debemos revisar para dispositivos de pequeño ancho. En este sitio elimino las flotaciones dentro del texto principal cuando el ancho del dispositivo es inferior a 512px. Por ejemplo, si observa esta página en un móvil de ancho inferior a ese comprobará que la imagen que está por encima de estos párrafos no está flotada, es decir, el texto no la envuelve. En otro caso el espacio que quedaría para albergar el texto sería insuficiente y la mayor parte de las palabras no cabrían, produciendo unos huecos vacíos poco agradables a la vista y con un texto resultante díficil de leer.

Pero esa eliminación de flotaciones no la llevo a cabo en los ejemplos de esta página, aunque hago una consulta de medios para ajustar el tamaño de la fuente a tres rangos de anchos: menor de 360 píxeles, entre 360 y 500 y mayores de 500. Con esto al menos podemos seguir los ejemplos en dispositivos pequeños.

Antes de meterme de lleno con la nueva especificación me pregunto si hay alguna manera de envolver texto con forma geométrica usando sólo CSS2. La respuesta es negativa si intentamos hacerlo de una forma directa. Pero hay un truco que he visto en un plugin JQuery para envolver texto alrededor de una imagen, cuyo código puede analizarse en el ejemplo de uso que expone jQSlickWrap. Tomando esa idea de flotar tantos contenedores como líneas de texto, he elaborado el siguiente ejemplo que sólo usa HTML y CSS2:

Ejemplo: Flotar formas geométricas con CSS2

Lorem ipsum ad his scripta blandit partiendo, eum fastidii accumsan euripidis in, eum liber hendrerit an. Qui ut wisi vocibus suscipiantur, quo dicit ridens inciderint id. Quo mundi lobortis reformidans eu, legimus senserit definiebas an eos. Eu sit tincidunt incorrupte definitionem, vis mutat affert percipit cu, eirmod consectetuer signiferumque eu per. In usu latine equidem dolores. Quo no falli viris intellegam, ut fugit veritus placerat per. Ius id vidit volumus mandamus, vide veritus democritum te nec, ei eos debet libris consulatu. No mei ferri graeco dicunt, ad cum veri accommodare. Sed at malis omnesque delicata, usu et iusto zzril meliore. Dicunt maiorum eloquentiam cum cu, sit summo dolor essent te. Ne quodsi nusquam legendos has, ea dicit voluptua eloquentiam pro, ad sit quas qualisque. Eos vocibus deserunt quaestio ei. Blandit incorrupte quaerendum in quo, nibh impedit id vis, vel no nullam semper audiam. Ei populo graeci consulatu mei, has ea stet modus phaedrum. Inani oblique ne has, duo et veritus detraxit. Tota ludus oratio ea mel, offendit persequeris ei vim. Eos dicat oratio partem ut, id cum ignota senserit intellegat. Sit inani ubique graecis ad, quando graecis liberavisse et cum, dicit option eruditi at duo.

Código de este ejemplo

En el contenedor <div id="shape-old-img"> disponemos de una imagen de fondo de 256×256 px con fondo transparente. Ponemos esta imagen en el background-image que, por defecto, se posicionará en la esquina superior izquierda. Hemos de conseguir que el texto envuelva esa forma triangular por la derecha de la imagen. El contenido HTML está compuesto por un párrafo con el texto y antes hay 13 elementos <div class="div-separa">, cada uno con un estilo inline para fijar el ancho. Estos separadores se flotan a la izquierda, borrando además las flotaciones previas. Fijamos la altura de línea (line-height) del párrafo para que sea igual que el alto de los separadores (20px). El ancho de cada separador hay que determinarlo con algún método para encontrar los valores y conseguir la forma triangular de la imagen.

Si observamos los anchos de los separadores vemos que van desde 128 hasta 248 píxeles, disponiéndose para cubrir una línea recta entre el vértice superior del triángulo, que es el punto (128, 0) hasta el vértice derecho, punto (256, 256). Los separadores tienen una altura de 20px y hemos de cubrir una altura de 256px por lo que necesitamos 256/20 = 12,8 separadores y que redondeamos a 13. Aplicamos incrementos de ancho de 128/12,8 = 10px. También separamos el texto de la imagen dándole un margen derecho de 10px a los separadores.

El párrafo class="p-shape" tiene contorno (outline) en lugar de borde (border), puesto que con ese caso la última línea flotada no lo haría correctamente, aunque no sabría decir el motivo. Esta clase p-shape se usa en otros ejemplos de este tema que no se ven afectados si usamos borde o contorno.

Flotar con shape-outside

La técnica CSS2 para flotar formas geométricas conlleva un exceso de elementos que podemos evitar con la nueva especificación CSS Shapes. Se declaran en este módulo de nivel 1 sólo tres propiedades:

shape-outside
Las formas geométricas se declaran con shape-outside, que junto a shape-margin define la forma geométrica de la envoltura de la flotación.
shape-image-threshold
Define el umbral del canal alfa usado para extraer la forma geométrica usando una imagen. Un valor de 0.5 significa que la forma incluirá todos los píxeles que tengan una opacidad superior al 50%.
shape-margin
Agrega un margen (siempre positivo) a la forma definida por shape-outside.

Antes de continuar comprobaremos en este navegador el nivel de soporte de estas nuevas propiedades:

  • shape-outside: ?
  • shape-image-threshold: ?
  • shape-margin: ?

Si no se soporta una propiedad aparecerá NULL. Si se soporta con prefijo aparecerá el nombre de la propiedad con el prefijo y cuando se soporte sin prefijo repetirá el nombre de la propiedad.

Este nivel 1 del módulo CSS Shapes sólo incluye las formas geométricas relacionadas con las áreas de flotación. En próximos niveles se agregarán nueva utilidades para las formas geométricas, que en cualquier caso se aplicará a elementos de bloque. O elementos en línea forzados a bloque, como sucede con los elementos flotados. Pero en este primer nivel sólo podrá aplicarse a elementos flotados, es decir, los que contengan la propiedad float.

En el siguiente ejemplo reproducimos el anterior usando la nueva propiedad shape-outside con el valor polygon():

Ejemplo: Flotar formas geométricas con shape-outside: polygon()

Triángulo Sierpinski

Código de este ejemplo

Tenemos un elemento <p> con el texto y una imagen que la flotamos a la izquierda. Es este elemento <img> el que recibe la propiedad shape-outside con el valor polygon(50% 0, 100% 100%, 0 100%). Se trata de construir un polígono en el área de la imagen que es de 256×256 píxeles. Se pueden incluir tantas parejas de valores que representan puntos (x, y) del plano, valores que van separados por un espacio y parejas separadas por comas. Si el último punto no coincide con el primero, el navegador cerrará el polígono entre estos dos puntos.

Podemos usar valores absolutos (como píxeles) o bien porcentajes en cuyo caso serán en referencia al ancho de la imagen para la coordenada X y al alto para la coordenada Y. Nuestro polígono está definido por el vértice superior del triángulo con el punto (50%, 0) significando que la coordenada X se encuentra a un 50% del ancho de la imagen y que la coordenada Y estará en 0. Recuerde que el punto (0,0) siempre es el vértice superior izquierdo del contenedor. El siguiente punto del polígono se encuentra en el vértice inferior derecho del triángulo, por lo que le corresponde el punto (100%, 100%) en porcentajes. El tercer punto del triángulo es su vertice inferior izquierdo, punto (0, 100%). El navegador cerrará el polígono uniendo este punto y el primero.

Con esta forma geométrica definida con CSS el navegador envolverá el texto en torno a esa forma. Desde el punto de vista del HTML resulta más simple que el ejemplo anterior. Pero en todo caso conlleva crear el polígono buscando los vértices que definirán la forma geométrica. Podemos evitar esta tarea si usamos el valor url() con la ruta de la imagen. El navegador analizará la imagen y buscará ese polígono exterior que serán las áreas transparentes sobre las que podrá envolver el texto. Veámos esto en el siguiente ejemplo:

Ejemplo: Flotar imagen con shape-outside: url()

Triángulo Sierpinski

Código de este ejemplo

El ejemplo tiene el mismo HTML que el anterior. El CSS sólo cambia en el valor shape-outside: url('Url de la imagen') para la propiedad shape-outside. Es la misma URL que tiene el elemento <img> y ambas cosas son independientes. Podríamos construir una forma a partir de una imagen pero no necesariamente tenemos que incluir esa imagen en el documento. Pero en este ejemplo estamos usando la misma imagen. El navegador la extrae a partir del CSS y construye la forma sobre las áreas transparentes. Esto se define con la propiedad shape-image-threshold que tiene un valor por defecto de 0.0 que no haría falta ponerlo (más abajo explicaré más sobre esto).

En definitiva, podemos envolver texto alrededor de formas geométricas que podemos crear de varias maneras. En los apartados siguientes explicaré con más detalle estas nuevas propiedades.

Propiedad shape-outside para flotar formas geométricas

La propiedad shape-outside se aplica por ahora sólo a elementos flotados y puede tomar los siguientes valores:

  • El valor inicial shape-outside: none no aplica ninguna forma geométrica.
  • Un valor de forma básica (basic-shape) entre los siguientes:
    • Rectángulo: Con shape-outside: inset(TRBL round BR) definimos los cuatro lados de un rectángulo. El argumento TRBL (top right bottom left) sigue el mismo esquema que el utilizado para la propiedad margin, a saber, con 1 valor se aplica a los cuatro lados, con 2 valores el primero se aplica al superior e inferior (top y bottom) y el segundo al derecho e izquierdo (right y left). Con 3 valores el primero y el último se dedican al superior e inferior respectivamente, mientras que el central es para ambos lados derecho e izquierdo. Con 4 valores se dedican en ese orden: superior, derecho, inferior e izquierdo. Podemos ponerle bordes redondeados al rectángulo agregando opcionalmente round BR donde BR es un valor válido para border-radius.
    • Círculo: Con shape-outside: circle(R at X Y) creamos un círculo de radio R con centro en el punto X Y. El radio y el centro son opcionales. Si se omiten usará como radio r el resultado de la fórmula 2r = sqrt(width2 + height2) / sqrt(2) y el centro será el geométrico de ese rectángulo. Los valores en porcentajes toman como base el valor de 2r que se obtiene de la fórmula anterior.
    • Elipse: Con shape-outside: ellipse(RX RY at X Y) creamos una elipse de radios RX y RY centrado en X Y.
    • Polígono: Con shape-outside: polygon(X1 Y1, X2 Y2, ..., Xn Yn) creamos un polígono de n vértices. El perímetro del polígono sigue ese orden cerrándose el último punto con el primero. Necesitamos al menos 3 puntos para que el polígono contenga un área, pues en otro caso resultaría en una área de flotado vacía. Es posible agregar antes de los puntos del polígono una regla de relleno (fill-rule), así que con polygon(FR, X1 Y1, ...) el valor FR determina el interior del polígono. Los valores posibles para esta regla son nonzero que es el valor inicial y evenodd. Los valores fill-rule se exponen en SVG 1.1.
  • Un valor de forma de la caja (shape-box) tal como se explica en la propiedad background-clip para la caja de borde (border-box), caja de relleno (padding-box) y caja de contenido (content-box). Ahora se agrega la caja de margen (margin-box):
    • shape-outside: margin-box
    • shape-outside: border-box
    • shape-outside: padding-box
    • shape-outside: content-box
  • Una imagen incorporada con shape-outside: url("URL de la imagen").

En este ejemplo podrá ver y probar valores de formas básicas para shape-outside:

Ejemplo: Valores basic-shape para shape-outside

Código de este ejemplo

El elemento de color rosado es el que flotamos y recibe la forma geométrica. Se trata de un <span> con dimensiones 256×256 píxeles. He agregado unas reglas graduadas en píxeles para observar las medidas. Con lo dicho antes poco más hay que explicar sobre este ejemplo. Quizás sólo recordar que el valor url() es la ruta a la imagen del Triángulo de Sierpinski, imagen también de 256×256 píxeles que usé en los primeros ejemplos de este tema. El texto envuelve la forma triangular de esa imagen. La propiedad shape-outside abre el archivo de esa imagen única y exclusivamente para obtener la forma geométrica. Si además queremos ponerla en pantalla debemos agregarla en un background-image o en un elemento <img>, tal como comentamos en los primeros ejemplos.

En el siguiente ejemplo puede ver valores de forma de caja para shape-outside:

Ejemplo: Valores shape-box para shape-outside

Código de este ejemplo

En este ejemplo el elemento flotado también es un span con márgenes, rellenos y bordes de 40px, con medidas ancho y alto también de 40px. Recuerde que al flotar este elemento inline se fuerza a block, por lo que podemos darle ancho y alto. Conseguimos darle una forma circular con border-radius: 100px, pues el radio será la suma del borde (color verde) más relleno (color rosado) y la mitad del contenido (color marrón) (40+40+20). Al cambiar los distintos valores para shape-outside vemos como el texto envuelve la forma.

Propiedades shape-image-threshold y shape-margin

La propiedad shape-image-threshold se usa conjuntamente con el valor url() para la propiedad shape-outside. Más arriba decíamos que CSS puede obtener la forma geométrica buscando las áreas transparentes de una imagen. La propiedad shape-image-threshold establece el umbral de transparencia (u opacidad) a partir del cual se crea la forma. Por defecto tiene el valor cero que se corresponde con la máxima transparencia (mínima opacidad).

Por ejemplo, la imagen del Triángulo de Sierpinski que probamos más arriba tiene sólo dos colores, el azul y el fondo transparente. La forma es triangular porque CSS empieza buscando esas zonas desde los bordes exteriores hasta encontrar los primeros píxeles no transparentes en el interior. Y eso le da una forma triangular sobre la que envolverá el texto. Con shape-image-threshold podemos definir el nivel del transparencia a partir del que se define la forma. Vea el siguiente ejemplo:

Ejemplo: Propiedades shape-image-threshold y shape-margin

Imagen con transparencias

Código de este ejemplo

Con un editor de imágenes he construido la imagen alpha.png dibujando ocho cuadrados de 10px de grueso de borde, que van desde el exterior al interior con opacidades desde 0.0 a 0.7 y diferentes colores. En el centro hay un rectángulo de color blanco con máxima opacidad 1.0. Con valor 0.0 el texto envuelve hasta el primer rectángulo. A medida que vamos incrementando shape-image-threshold vemos como la envoltura se acerca al cuadrado central. La otra propiedad sobre la que podemos actuar es shape-margin para agregar un margen a la envoltura de texto.

La imagen está en un elemento <img> y también tiene otra imagen de fondo con el cuadriculado (transp.png) para observar el efecto de las zonas transparentes. He modificado el tamaño de fuente y altura de línea (clase line-10) para que coincida con el alto de las zonas de transparencia y observar mejor la envoltura de texto en cada zona.

Flotar al centro

Flotar al centro

Podemos flotar un elemento a la izquierda o derecha, de tal forma que el texto envolverá al elemento flotado. Pero por ahora en CSS no hay nada para flotar al centro. En la imagen adjunta puede ver una captura de pantalla de un texto con una imagen flotada al centro realizado en el editor de texto de Google Drive. Aunque he reducido la captura para aligerarla de peso, lo importante que quería resaltar es que el texto de las líneas donde está la imagen sufre un corte que dificulta la lectura, pues al saltar la imagen para seguir leyendo a la derecha no sabemos muy bien por donde vamos. Flotar al centro de esta forma puede resultar atractivo, pero es poco accesible para la lectura.

En cualquier caso intentaré buscar cómo hacerlo. No sé como ese editor puede conseguirlo, pero si he encontrado algo para hacer una falsa flotación al centro. He visto esta idea en el sitio css-tricks.com realizada con pseudoelementos. Basándome en esa idea vea este ejemplo:

Ejemplo: Flotar al centro con CSS2

Parte izquierda torre Eiffel
La torre Eiffel, inicialmente nombrada torre de 300 metros, es una estructura de hierro pudelado diseñada por Maurice Koechlin y Émile Nouguier y construida por el ingeniero francés Gustave Eiffel y sus colaboradores para la Exposición universal de 1889 en París. Situada en el extremo del Campo de Marte a la orilla del río Sena, este monumento parisino, símbolo de Francia y su capital, es la estructura más alta de la ciudad y el monumento que cobra entrada más visitado del mundo, con 7,1 millones de turistas cada año. Con una altura de 300 metros, prolongada más tarde con una antena a 324 metros, la torre Eiffel fue la estructura más elevada del mundo durante 41 años.
Fue construida en dos años, dos meses y cinco días, y en su momento generó cierta controversia entre los artistas de la época, que la veían como un monstruo de hierro. Inicialmente utilizada para pruebas del ejército con antenas de comunicación, hoy sirve, además de atractivo turístico, como emisora de programas radiofónicos y televisivos. Inicialmente tema de controversia de algunos, la torre Eiffel sirvió como presentación a la Exposición Universal de París de 1889, la cual acogió a más de 236 millones de visitantes desde su inauguración. Su tamaño excepcional y su silueta inmediatamente reconocible hicieron de la torre un emblema de París. (Texto extraido de Wikipedia).

Código de este ejemplo

En primer lugar hay dos elementos <div class="center-col"> con display: inline-block y width: 50% donde ubico la parte superior e inferior del texto a presentar. Esto es una presentación a dos columnas. La imagen de 180×299 píxeles a flotar en el centro la incluyo en un <img id="center-img"> como flotada a la derecha del bloque de texto de la izquierda, pero la desplazo hacia la derecha hasta que se centre entre las dos columnas. Esto lo hago aplicando margin: 0 -90px 0 0.1em, donde -90px hará que la imagen salga la mitad su ancho hacia la derecha de su contenedor. El margen de 0.1em es para separar el texto de la imagen.

En la columna de la derecha inserto un <span id="center-span"> flotado a la izquierda con las mismas dimensiones que la imagen (width: 180px; height: 299px). A este lo desplazo a la izquierda para que también se centre con 0 0.1em 0 -90px. Al final la imagen y este elemento quedarán en el mismo sitio centrados entre las dos columnas.

Para que todo ajuste no puede haber ningún espacio entre los elementos. Además hemos de abrir una separación entre el texto de las dos columnas para que se vea claramente que el texto se divide precisamente en dos columnas. Esto lo hacemos dándole un padding derecho e izquierdo de 1em a la columna izquierda y derecha respectivamente. El texto en dos columnas si que resulta más accesible para la lectura.

El siguiente paso es aplicar lo mismo que vimos en el primer ejemplo para flotar al centro con formas geométricas usando CSS2:

Ejemplo: Flotar al centro formas geométricas con CSS2

Código de este ejemplo

La estructura es la misma que la seguida en el primer ejemplo de este tema. Poner la imagen de fondo en el contenedor exterior en el background-image centrándola con background-position: top center. Dos contenedores de texto se estructuran en columnas como el ejemplo anterior. Luego flotamos separadores a cada lado dándoles un ancho suficiente para ir construyendo la forma de la imagen que nos interese.

Por último podemos conseguir lo mismo usando shape-outside:

Ejemplo: Flotar al centro formas geométricas con shape-outside

Código de este ejemplo

Los contenedores que reciben shape-outside son <div class="shape-sep-right"> en la columna de la izquierda (flota a la derecha) y <div class="shape-sep-left"> en la columna de la derecha (flota a la izquierda). Ambos tienen un ancho de 90px, la mitad que el ancho de la imagen de fondo que ponemos en el contenedor exterior como hicimos también en el ejemplo anterior. Usamos el valor polygon() para shape-outside y construimos la forma poligonal con sólo 7 vértices.


En resumen, una nueva prestación de CSS para crear formas geométricas. Aunque ahora sólo se limita a elementos flotados, es posible que se extienda su aplicación a otras cosas en futuros niveles de esta especificación, por lo que conviene conocerla.