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 texto, un área en la que Adobe tiene mucha experiencia y conocimientos. Cuando Adobe buscaba formas de ayudar a que la Web avanzara, por lo tanto, mejorar aún más las capacidades de texto de la Web parecía un punto de partida obvio. La Web generalmente supone una sola columna con orientación vertical para el texto. Si bien es posible hacer que el texto fluya alrededor de los gráficos, e incluso darle formato al texto en varias columnas con CSS, sigue siendo muy difícil lograr un verdadero diseño similar a una revista en la Web. Con las regiones de CSS y las exclusiones de CSS, Adobe encabeza la iniciativa para llevar el poder de la autoedición a los navegadores modernos. Por ejemplo, en la siguiente captura de pantalla, las exclusiones de CSS se están utilizando 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 envuelva formas en las imágenes, así como regiones de CSS para dar formato al texto en columnas y en torno a una cita de extracción:

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

Regiones de CSS

Antes de entrar en detalles sobre las regiones de CSS, me gustaría explicar cómo se pueden habilitar las regiones en Google Chrome. Una vez que tengas habilitadas las regiones de CSS, podrás 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 están habilitadas 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/comando + f) y busca la sección "funciones experimentales de la plataforma web".
  4. Haz clic en el vínculo Habilitar.
  5. Haz clic en el botón Reiniciar ahora que se encuentra en la parte inferior.

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

Una vez que reinicies 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 a "cuadros" (elementos actualmente). En el siguiente diagrama, se muestra la separación de texto (el flujo) y cuadros (las regiones a las que fluye el texto):

El contenido se traslada a regiones definidas
El contenido fluye a 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. Con frecuencia publico mi trabajo en línea bajo una licencia de Creative Commons y para que funcione en la mayor cantidad de dispositivos y navegadores, con frecuencia uso un formato extremadamente simple similar al siguiente:

Ejemplo de proyecto humano heredado sin estilo
Ejemplo de proyecto heredado humano sin estilo

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:

Proyecto humano heredado en el que se muestra la región
Proyecto heredado humano con regiones.

Para fines de demostración, agregué la capacidad de revelar las regiones de CSS en este prototipo. En la siguiente captura de pantalla, se muestra cómo se organizan las regiones de modo que dan la impresión de que son columnas que envuelven un gráfico y una comillas simples en el centro:

Proyecto humano heredado en el que se muestran las regiones
Proyecto heredado humano que muestra regiones

Puedes experimentar con este prototipo (además de 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 lograr que un bloque de texto fluya por las regiones es extremadamente simple. El siguiente fragmento asigna un flujo con nombre llamado "article" a un elemento div con el ID "content" y asigna ese mismo flujo con nombre de "article" a cualquier elemento con la clase "region". Como resultado, el texto contenido dentro del elemento “content” fluirá automáticamente por 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 conoce su presentación. En otras palabras, puede permanecer intacto de manera semántica por completo, incluso mientras fluye por varias regiones. Además, como las regiones son solo elementos, se posicionan y ajustan su tamaño con CSS de la misma forma que 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 a través de ellos automáticamente.

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 nuevas APIs relacionadas con las regiones de CSS:

  • document.webkitGetNamedFlows(): Es una función que muestra la colección de flujos con nombre disponibles en el documento.
  • document.webkitGetNamedFlows().namedItem("article"): Es una función que muestra una referencia a un flujo con nombre específico. El argumento corresponde al nombre especificado como el valor de las propiedades de CSS flow-into y from-from. Para obtener una referencia al flujo nombrado especificado en el fragmento de código anterior, debes pasar la cadena "article".
  • WebKitNamedFlow: Es una representación del objeto de un plano con nombre con las siguientes propiedades y funciones:
    • firstEmptyRegionIndex: Es un valor de número entero que apunta al índice de la primera región vacía asociada con el 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: Una propiedad booleana que tiene las siguientes características:
      • false cuando el contenido del flujo con nombre se ajusta a las regiones asociadas.
      • Se utiliza true cuando el contenido no se ajusta y se requieren más regiones para incluir todo el contenido.
    • getContent(): Es una función que muestra una colección con referencias a los nodos que fluyen al flujo con nombre.
    • getRegions(): Es una función que muestra una colección con referencias a regiones que contienen el contenido del flujo con nombre.
    • getRegionsByContentNode(node): Es una función que muestra 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 una WebkitNamedFlow cada vez que cambia el diseño del contenido asociado por algún motivo (se agrega o quita contenido, cambia el tamaño de la fuente, cambia la forma de la región, etc.) y cambia la propiedad webkitRegionOverset de una región. Este evento es útil para escuchar cambios generales de diseño. Es un indicador de que ocurrió algo importante y es posible que el diseño requiera atención. Por ejemplo: se requieren más regiones, algunas regiones pueden estar vacías, etcétera.
  • webkitregionfragmentchange. No se implementó en el momento de esta edición. Este evento se activa en una WebkitNamedFlow cada vez que cambia el diseño del contenido asociado por algún motivo, similar a webkitregionoversetchange, pero independientemente de cualquier cambio en las propiedades webkitRegionOverset. Este evento es útil para detectar cambios de diseño detallados que no afectan necesariamente todo el diseño del flujo con nombre; por ejemplo, el contenido se traslada de una región a otra, pero el contenido general 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 desborda la región o no. Estos son los posibles valores de webkitRegionOverset:
    • " desbordar" si hay más contenido del que la región puede almacenar
    • "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 adaptarse a diferentes cantidades de texto. Por ejemplo, si la cantidad de texto al que se debe dar formato es impredecible (quizá generada por el usuario), si se cambia el tamaño de la ventana del navegador o si cambia el tamaño de la fuente, es posible que sea 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 dinámicamente el DOM y tus regiones.

En el siguiente fragmento de código JavaScript, se demuestra el uso del CSSOM para agregar regiones de forma dinámica según sea necesario. Ten en cuenta que, por motivos de simplicidad, no se pueden quitar regiones ni definir su tamaño y sus posiciones; solo se usa con fines demostrativos.

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 CSS

Es probable que el uso del CSSOM sea la forma más poderosa y flexible de implementar elementos como la paginación y el diseño responsivo, pero Adobe ha estado trabajando con herramientas de texto y autoedición el tiempo suficiente para saber que los diseñadores y desarrolladores también van a querer una forma más sencilla de obtener capacidades de paginación relativamente genéricas. Por lo tanto, estamos trabajando en una propuesta llamada plantillas de páginas de CSS que permite definir el comportamiento de paginación de forma totalmente declarativa.

Veamos un caso de uso común de las plantillas de páginas CSS. El siguiente fragmento de código muestra el uso de CSS para crear dos flujos denominados: "article-flow" y "timeline-flow". Además, define un tercer selector llamado "combinados-artículos" dentro del cual se encontrarán los dos flujos. La inclusión simple de la propiedad overflow-style dentro del selector de "artículos combinados" indica que el contenido se debería paginar automáticamente en el 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 por sí misma:

@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áginas se definen con la nueva sintaxis "at". En el fragmento de código anterior, definimos tres espacios, cada uno correspondiente a una columna. El texto del "flujo de artículos" fluirá a través de las columnas de la izquierda y de la derecha, y el texto del "flujo de cronograma" se propagará en la columna en el medio. El resultado podría ser similar al siguiente:

Ejemplo de plantillas de página
Ejemplo de plantillas de página

Ten en cuenta 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 vuelve horizontalmente sin necesidad de usar código JavaScript. Todo se hizo de forma totalmente declarativa en CSS.

Las plantillas de páginas de CSS siguen siendo una propuesta; sin embargo, tenemos un prototipo que usa un “corrector de compatibilidad” 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 Regiones de CSS en html.adobe.com.

Exclusiones de CSS

Para lograr un verdadero diseño similar a una revista, no es suficiente poder desplazar 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 de gráficos y formas irregulares o dentro de ellos. 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 un texto que fluye de forma dinámica alrededor de una ruta que coincide con el contorno de una gran formación rocosa:

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

Lo contrario se ilustra en la siguiente captura de pantalla: texto que fluye dentro de polígonos de forma irregular:

Texto que fluye hacia polígonos de forma irregular
Texto que fluye hacia polígonos con formas irregulares

El primer paso para poder desplazar texto alrededor o dentro de formas arbitrarias es desarrollar y optimizar los algoritmos requeridos. Actualmente, Adobe está trabajando en implementaciones que se contribuirán directamente con WebKit. Una vez que se optimicen estos algoritmos, se convertirán en la base sobre la que se construyen el resto de las exclusiones de CSS.

Para obtener más información sobre las exclusiones de CSS, consulta la página Exclusiones de CSS en html.adobe.com. Si quieres conocer en detalle el trabajo de Adobe sobre la tecnología subyacente de las exclusiones de CSS, consulta la entrada de blog de Hans Muller titulada Cuadro horizontal: Intersección de polígonos para exclusiones de CSS.

El estado actual de las regiones y las exclusiones de CSS

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

Estuve en Google I/O este año (2012), 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, alrededor del 80% de la especificación de las regiones de CSS se implementó en WebKit y ya está en la versión más reciente de Google Chrome (ten en cuenta que, actualmente, las regiones de CSS se deben habilitar mediante chrome://flags). La compatibilidad preliminar de las regiones de CSS incluso llegó a Chrome para Android:

Regiones en Chrome para Android
Regiones en Chrome para Android

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

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

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

Conclusión

Adobe tiene una amplia experiencia con el texto, las fuentes y la autoedición en general a través de herramientas como InDesign. Aunque la Web ya es una plataforma muy potente para el texto, queremos usar nuestros conocimientos y experiencia para llevar las presentaciones de texto aún más lejos. Las regiones y las exclusiones de CSS permiten que el contenido se mantenga estructurado de forma semántica, al mismo tiempo que permiten un diseño similar a una revista y, en última instancia, una Web mucho más expresiva.