Diseño similar a una revista para la Web con regiones y exclusiones de CSS

Christian Cantrell
Christian Cantrell

Introducción

La Web es una plataforma extremadamente potente para el texto, un área en la que Adobe tiene mucha experiencia y conocimientos. Cuando Adobe buscaba formas de ayudar a que la Web avanzara, mejorar aún más las capacidades de texto de la Web parecía un punto de partida obvio para nosotros. La Web suele suponer una orientación vertical de una sola columna para el texto. Aunque es posible hacer que el texto fluya alrededor de los gráficos y hasta darle formato en varias columnas con CSS, sigue siendo muy difícil lograr un diseño similar al de una revista en la Web. Con las regiones de CSS y las exclusiones de CSS, Adobe encabeza el esfuerzo para llevar el poder de la autoedición a los navegadores modernos. Por ejemplo, en la siguiente captura de pantalla, se usan las exclusiones de CSS para que el texto fluya a lo largo del contorno de la montaña:

Ejemplo de exclusiones de CSS en acción
Ejemplo de exclusiones de CSS en acción

El documento de la siguiente captura de pantalla también usa exclusiones de CSS para permitir que el texto se ajuste a las formas de las imágenes, así como regiones de CSS para dar formato al texto en columnas y alrededor de una cita destacada:

Ejemplo de regiones de CSS en acción
Ejemplo de regiones de CSS en acción

Regiones de CSS

Antes de entrar en los detalles de las regiones de CSS, me gustaría explicar cómo se pueden habilitar las regiones en Google Chrome. Una vez que hayas habilitado las regiones de CSS, puedes probar algunas de las muestras a las que se hace referencia en este artículo y crear las tuyas.

Cómo habilitar las regiones de CSS en Google Chrome

A partir de la versión 20 de Chrome (versión 20.0.1132.57, para ser exactos), las regiones de CSS se habilitan a través de la interfaz chrome://flags. Para habilitar las regiones de CSS, sigue estos pasos:

  1. Abre una nueva pestaña o ventana en Chrome.
  2. Escribe chrome://flags en la barra de ubicación.
  3. Usa Buscar en la página (control/command + f) y busca la sección "experimental Web Platform features".
  4. Haz clic en el vínculo Habilitar.
  5. Haz clic en el botón Relaunch Now que se encuentra en la parte inferior.

Para obtener más información sobre las funciones experimentales de Chrome, consulta mi entrada de blog sobre Todo sobre las funciones experimentales de Chrome.

Una vez que hayas reiniciado el navegador, podrás comenzar a experimentar con las regiones de CSS.

Descripción general de las regiones de CSS

Las regiones de CSS permiten que un bloque de texto con lenguaje de marcado semántico fluya automáticamente en "cuadros" (actualmente, elementos). En el siguiente diagrama, se muestra la separación del texto (el flujo) y los cuadros (las regiones en las que fluye el texto):

El contenido fluye hacia regiones definidas
El contenido fluye hacia regiones definidas

Veamos un caso de uso real de las regiones de CSS. Además de ser desarrollador en Adobe, también soy escritor de ciencia ficción. Suelo publicar mi trabajo en línea con una licencia Creative Commons y, para que funcione en la mayor cantidad posible de dispositivos y navegadores, suelo usar un formato muy simple similar a este:

Ejemplo de Human Legacy Project sin diseño
Ejemplo de proyecto heredado de Human sin diseño

Con las regiones de CSS, pude crear una experiencia que es más interesante visualmente y mucho más funcional, ya que es más fácil de navegar y más cómoda de leer:

Human Legacy Project con la región
Proyecto de legado humano con regiones.

Para fines de demostración, agregué la capacidad de revelar regiones de CSS en este prototipo. En la siguiente captura de pantalla, se muestra cómo se organizan las regiones para que den la impresión de ser columnas que se ajustan alrededor de un gráfico y una cita destacada en el centro:

Proyecto Human Legacy en el que se muestran las regiones
Proyecto Human Legacy que muestra las regiones

Puedes experimentar con este prototipo (y ver el código fuente) aquí. Usa las teclas de flecha para navegar y presiona la tecla Esc para revelar las regiones. Los prototipos anteriores también están disponibles aquí.

Crea un flujo con nombre

El CSS necesario para que un bloque de texto fluya por las regiones es muy sencillo. El siguiente fragmento asigna un flujo con nombre llamado "article" a un div con el ID "content" y asigna ese mismo flujo con nombre "article" a cualquier elemento con la clase "region". El resultado es que el texto contenido dentro del elemento "content" fluirá automáticamente a través de cualquier elemento con la clase "region".

<!DOCTYPE html>
<html>
<head>
    <style>
    #content {
        { % mixin flow-into: article; % }
    }

    .region {
        { % mixin flow-from: article; % }
        box-sizing: border-box;
        position: absolute;
        width: 200px;
        height: 200px;
        padding: 10px;
    }

    #box-a {
        border: 1px solid red;
        top: 10px;
        left: 10px;
    }

    #box-b {
        border: 1px solid green;
        top: 210px;
        left: 210px;
    }

    #box-c {
        border: 1px solid blue;
        top: 410px;
        left: 410px;
    }
    </style>
</head>
<body>
    <div id="box-a" class="region"></div>
    <div id="box-b" class="region"></div>
    <div id="box-c" class="region"></div>
    <div id="content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eleifend dapibus felis, a consectetur nisl aliquam at. Aliquam quam augue, molestie a scelerisque nec, accumsan non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin cursus euismod nisi, a egestas sem rhoncus eget. Mauris non tortor arcu. Pellentesque in odio at leo volutpat consequat....
    </div>
</body>
</html>

El resultado se ve de la siguiente manera:

Resultado del código anterior
Resultado del código anterior

Ten en cuenta que el texto dentro del div "content" no tiene conocimiento de su presentación. En otras palabras, puede permanecer completamente intacto desde el punto de vista semántico, incluso cuando fluye por varias regiones. Además, como las regiones son solo elementos, se posicionan y se dimensionan con CSS como cualquier otro elemento y, por lo tanto, son perfectamente compatibles con los principios del diseño responsivo. Designar elementos como parte de un flujo con nombre simplemente significa que el texto especificado fluye automáticamente a través de ellos.

El modelo de objetos de CSS

El modelo de objetos de CSS, o CSSOM, define las APIs de JavaScript para trabajar con CSS. A continuación, se muestra una lista de las APIs nuevas relacionadas con las regiones de CSS:

  • document.webkitGetNamedFlows(): Es una función que devuelve la colección de flujos con nombre disponibles en el documento.
  • document.webkitGetNamedFlows().namedItem("article"): Es una función que devuelve una referencia a un flujo con nombre específico. El argumento corresponde al nombre especificado como el valor de las propiedades CSS flow-into y from-from. Para obtener una referencia al flujo con nombre especificado en el fragmento de código anterior, debes pasar la cadena "article".
  • WebKitNamedFlow: Es una representación de objeto de un floe con nombre que tiene las siguientes propiedades y funciones:
    • firstEmptyRegionIndex: Es un valor entero que apunta al índice de la primera región vacía asociada al flujo con nombre. Consulta getRegions() a continuación para obtener información sobre cómo obtener la colección de regiones.
    • name: Es un valor de cadena con el nombre del flujo.
    • overset: Es una propiedad booleana que puede ser:
      • false cuando el contenido del flujo con nombre se ajusta a las regiones asociadas
      • true cuando el contenido no cabe y se requieren más regiones para contener todo el contenido.
    • getContent(): Es una función que devuelve una colección con referencias a los nodos que fluyen hacia el flujo con nombre.
    • getRegions(): Es una función que devuelve una colección con referencias a regiones que contienen el contenido del flujo con nombre.
    • getRegionsByContentNode(node): Es una función que devuelve una referencia a la región que contiene el nodo especificado. Esto es especialmente útil para encontrar regiones que contienen elementos como anclas con nombre.
  • webkitregionoversetchange. Este evento se activa en un WebkitNamedFlow cada vez que el diseño del contenido asociado cambia por cualquier motivo (se agrega o quita contenido, cambia el tamaño de la fuente, cambia la forma de la región, etc.) y hace que cambie la propiedad webkitRegionOverset de una región. Este evento es útil para detectar cambios generales en el diseño. Es un indicador de que ocurrió algo importante y es posible que el diseño requiera atención, por ejemplo, se necesitan más regiones, algunas regiones podrían estar vacías, etcétera.
  • webkitregionfragmentchange. No se implementó en el momento de esta edición. Este evento se activa en un WebkitNamedFlow cada vez que el diseño del contenido asociado cambia por cualquier motivo, de forma similar a webkitregionoversetchange, pero independientemente de cualquier cambio en las propiedades de webkitRegionOverset. Este evento es útil para escuchar cambios de diseño detallados que no necesariamente afectan todo el diseño del flujo con nombre, por ejemplo: el contenido se mueve de una región a otra, pero el contenido general aún se ajusta a todas las regiones.
  • Element.webkitRegionOverset: Los elementos se convierten en regiones cuando tienen asignada la propiedad de CSS flow-from. Estos elementos tienen una propiedad webkitRegionOverset que, si forman parte de un flujo con nombre, indica si el contenido de un flujo se desborda de la región. Los valores posibles de webkitRegionOverset son los siguientes:
    • "overflow" si hay más contenido del que puede contener la región
    • "fit" si el contenido se detiene antes del final de la región
    • "empty" si el contenido no llegó a la región

Uno de los usos principales del CSSOM es escuchar eventos webkitregionoversetchange y agregar o quitar regiones de forma dinámica para dar cabida a distintas cantidades de texto. Por ejemplo, si la cantidad de texto al que se le dará formato es impredecible (tal vez generada por el usuario), si se cambia el tamaño de la ventana del navegador o si cambia el tamaño de la fuente, puede ser necesario agregar o quitar regiones para adaptarse al cambio en el flujo. Además, si quieres organizar tu contenido en páginas, necesitarás un mecanismo para modificar de forma dinámica el DOM y tus regiones.

En el siguiente fragmento de código de JavaScript, se muestra el uso del CSSOM para agregar regiones de forma dinámica según sea necesario. Ten en cuenta que, para simplificar, no se quitan regiones ni se definen el tamaño y las posiciones de las regiones; solo se usa con fines de demostración.

var flow = document.webkitGetNamedFlows().namedItem("article")
flow.addEventListener("webkitregionoversetchange", onLayoutUpdate);

function onLayoutUpdate(event) {
    var flow = event.target;
    
    // The content does not fit
    if (flow.overset === true) {
    addRegion();
    } else {
    regionLayoutComplete();
    }
}

function addRegion() {
    var region = document.createElement("div");
    region.style = "flow-from: article";
    document.body.appendChild(region);
}

function regionLayoutComplete() {
    // Finish up your layout.
}

Hay más demostraciones disponibles en la página de muestras de regiones de CSS.

Plantillas de páginas de CSS

Aprovechar el CSSOM es probablemente la forma más potente y flexible de implementar cosas como la paginación y el diseño responsivo, pero Adobe ha estado trabajando con herramientas de texto y autoedición el tiempo suficiente como para saber que los diseñadores y desarrolladores también van a querer una forma más fácil de obtener capacidades de paginación relativamente genéricas. Por lo tanto, estamos trabajando en una propuesta llamada Plantillas de página CSS que permite definir el comportamiento de paginación de forma completamente declarativa.

Veamos un caso de uso común de las plantillas de páginas de CSS. En el siguiente fragmento de código, se muestra el uso de CSS para crear dos flujos con nombre: "article-flow" y "timeline-flow". Además, define un tercer selector llamado "combined-articles" dentro del cual se contendrán los dos flujos. La simple inclusión de la propiedad overflow-style dentro del selector "combined-articles" indica que el contenido se debe paginar automáticamente a lo largo del eje X o de forma horizontal:

<style>
    #article {
    { % mixin flow-into: article-flow; % }
    }

    #timeline {
    { % mixin flow-into: timeline-flow; % }
    }

    #combined-articles {
    overflow-style: paged-x;
    }
</style>

Ahora que se definieron los flujos y se especificó el comportamiento de desbordamiento deseado, podemos crear la plantilla de página:

@template {
    @slot left {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }

    @slot time {
    width: 25%;
    float: left;
    { % mixin flow-from: timeline-flow; % }
    }

    @slot right {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }
}

Las plantillas de página se definen con la nueva sintaxis "at". En el fragmento de código anterior, definimos tres ranuras, cada una correspondiente a una columna. El texto de "article-flow" fluirá por las columnas de la izquierda y la derecha, y el texto de "timeline-flow" completará la columna del medio. El resultado podría ser similar al siguiente:

Ejemplo de plantillas de páginas
Ejemplo de plantillas de páginas

Observa que el texto del artículo (el texto de las columnas izquierda y derecha) está en inglés, y la línea de tiempo del centro está en alemán. Además, el documento se pagina de forma horizontal sin necesidad de ningún código JavaScript. Todo se hizo de forma completamente declarativa en CSS.

Las plantillas de página CSS siguen siendo una propuesta, pero tenemos un prototipo que usa un "shim" de JavaScript (también conocido como polyfill) para que puedas experimentar con ellas ahora.

Para obtener más información sobre las regiones de CSS en general, consulta la página de regiones de CSS en html.adobe.com.

Exclusiones de CSS

Para lograr un diseño similar al de una revista, no basta con poder distribuir el texto por las regiones. Un elemento fundamental de la autoedición de alta calidad y visualmente interesante es la capacidad de hacer que el texto fluya alrededor o dentro de gráficos y formas irregulares. Las exclusiones de CSS llevan este nivel de calidad de producción a la Web.

La siguiente captura de pantalla es de un prototipo de exclusiones de CSS y muestra texto que fluye de forma dinámica alrededor de una ruta de acceso que coincide con el contorno de una formación rocosa grande:

Ejemplo de exclusiones de CSS en acción
Ejemplo de exclusiones de CSS en acción

En la siguiente captura de pantalla, se ilustra lo contrario: el texto fluye dentro de polígonos con formas irregulares:

Texto que fluye en polígonos de forma irregular
Texto que fluye en polígonos de forma irregular

El primer paso para poder ajustar el texto alrededor o dentro de formas arbitrarias es desarrollar y optimizar los algoritmos necesarios. Actualmente, Adobe está trabajando en implementaciones que se aportarán directamente a WebKit. Una vez que se optimicen estos algoritmos, se convertirán en las bases sobre las que se creará el resto de las exclusiones de CSS.

Para obtener más información sobre las exclusiones de CSS, consulta la página de exclusiones de CSS en html.adobe.com y, para obtener una vista más detallada del trabajo de Adobe en la tecnología subyacente para las exclusiones de CSS, consulta la entrada de blog de Hans Muller titulada Horizontal Box: Polygon Intersection for CSS Exclusions.

El estado de las regiones y exclusiones de CSS (2012)

La primera vez que hablé públicamente sobre las regiones y exclusiones de CSS fue en el Adobe Developer Pod en Google I/O 2011. En ese momento, mostraba demostraciones en nuestro propio navegador de prototipos personalizado. La recepción fue muy entusiasta, pero hubo una sensación palpable de decepción cuando los espectadores descubrieron que ninguna de las funciones que mostraba estaba disponible en ninguno de los principales navegadores.

Este año (2012), volví a asistir a Google I/O, esta vez como presentador junto con mi compañero de trabajo Vincent Hardy y Alex Danilo de Google (puedes mirar la presentación aquí). Solo un año después, se implementó alrededor del 80% de la especificación de regiones de CSS en WebKit y ya se encuentra en la versión más reciente de Google Chrome (ten en cuenta que, actualmente, las regiones de CSS deben habilitarse a través de chrome://flags). Incluso se agregó compatibilidad preliminar con las regiones de CSS en Chrome para Android:

Regiones en Chrome para Android
Regiones en Chrome para Android

Además, tanto las regiones como las exclusiones de CSS se implementan en la versión preliminar de Internet Explorer 10 y, actualmente, se encuentran en la hoja de ruta de Mozilla para Firefox de 2012. La próxima versión principal de Safari debería admitir la mayor parte de la especificación de regiones de CSS, y las actualizaciones posteriores deberían incluir el resto.

A continuación, se muestra un cronograma detallado del progreso que hemos logrado con las regiones y exclusiones de CSS desde nuestra propuesta inicial al W3C en abril de 2011:

Progreso de la región y la exclusión
Progreso de la región y la exclusión

Conclusión

Adobe tiene una gran experiencia con texto, fuentes y autoedición en general a través de herramientas como InDesign. Si bien la Web ya es una plataforma muy potente para el texto, queremos usar nuestro conocimiento y experiencia para llevar la presentación de texto aún más lejos. Las regiones y exclusiones de CSS permiten que el contenido mantenga su estructura semántica y, al mismo tiempo, que se use un diseño similar al de una revista, lo que, en última instancia, hace que la Web sea mucho más expresiva.