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 avanzar en la Web, avanzar aún más en las capacidades de texto de la Web parecía un lugar obvio para comenzar. Por lo general, la Web supone una sola columna y una orientación vertical para el texto. Aunque es posible hacer que el texto fluya alrededor de los gráficos y hasta dar formato al texto en varias columnas con CSS, aún es 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 lidera el esfuerzo por llevar la potencia de la publicación en computadoras de escritorio a los navegadores modernos. Por ejemplo, en la siguiente captura de pantalla, se usan 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 algunos de los ejemplos a los que se hace referencia en este artículo y crear los tuyos propios.

Habilita las regiones de CSS en Google Chrome

A partir de la versión 20 de Chrome (la 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 la función 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 Relaunch Now que se encuentra en la parte inferior.

Para obtener más información sobre las marcas de Chrome, consulta mi entrada de blog sobre 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 marcado semántico fluya automáticamente a "cajas" (actualmente, elementos). En el siguiente diagrama, se muestra la separación del texto (el flujo) y los cuadros (las regiones a las que fluye el texto):

El contenido fluye 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. Publico mi trabajo en línea con frecuencia bajo una licencia de Creative Commons y, para permitir que funcione en la mayor cantidad posible de dispositivos y navegadores, suelo usar un formato extremadamente simple similar al siguiente:

Ejemplo de proyecto heredado de Human sin diseño
Ejemplo de proyecto heredado de recursos humanos sin diseño

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

Proyecto Human Legacy que muestra la región
Proyecto heredado de humanos con regiones.

A modo 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 dar la impresión de ser columnas que rodean un gráfico y una cita destacada en el centro:

Proyecto Human Legacy que muestra las regiones
Proyecto de legado humano 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 mostrar las regiones. Los prototipos anteriores también están disponibles aquí.

Cómo crear un flujo con nombre

El CSS necesario para que un bloque de texto fluya a través de las regiones es muy simple. En el siguiente fragmento, se asigna un flujo llamado “article” a un div con el ID “content” y se asigna ese mismo flujo llamado “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 de la div "content" no tiene ningún conocimiento de su presentación. En otras palabras, puede permanecer intacto semánticamente incluso mientras fluye a través de varias regiones. Además, como las regiones son solo elementos, se posicionan y se les asigna un tamaño 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 CSS Object Model, 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 muestra la colección de flujos nombrados disponibles en el documento.
  • document.webkitGetNamedFlows().namedItem("article"): Es una función que muestra una referencia a un flujo específico con nombre. 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 campo de hielo nombrado con 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 tiene las siguientes características:
      • false cuando el contenido del flujo nombrado se ajusta a las regiones asociadas
      • true cuando el contenido no se ajusta y se requieren más regiones para contenerlo todo.
    • getContent(): Es una función que muestra una colección con referencias a los nodos que fluyen hacia el flujo nombrado.
    • getRegions(): Es una función que muestra una colección con referencias a regiones que contienen el contenido del flujo nombrado.
    • 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 un 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étera) y hace que cambie la propiedad webkitRegionOverset de una región. Este evento es útil para detectar cambios de diseño generales. Es un indicador de que sucedió algo importante y que el diseño podría necesitar atención, por ejemplo: se requieren más regiones, algunas 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 algún motivo, de manera 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 necesariamente afectan todo el diseño del flujo nombrado, 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 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. 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 de que finalice 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 le debe aplicar 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, es posible que debas agregar o quitar regiones para adaptar el cambio en el flujo. Además, si deseas 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 JavaScript, se muestra 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 quita ni se define el tamaño ni las posiciones de las regiones; 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 de CSS

Aprovechar el CSSOM es probablemente la forma más potente 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 durante el tiempo suficiente como para saber que los diseñadores y desarrolladores también querrán 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 para las plantillas de páginas CSS. En el siguiente fragmento de código, se muestra el uso de CSS para crear dos flujos nombrados: "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 debe paginarse automáticamente a lo largo del eje x o horizontalmente:

<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 de las cuales corresponde a una columna. El texto de "article-flow" se mostrará en las columnas de la izquierda y la derecha, y el texto de "timeline-flow" se propagará en la columna del medio. El resultado podría verse de la siguiente manera:

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

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 en el centro está en alemán. Además, las páginas del documento se desplazan horizontalmente sin necesidad de ningún código JavaScript. Todo se hizo de forma completamente declarativa en CSS.

Las Plantillas de página de CSS aún son una propuesta. Sin embargo, tenemos un prototipo que usa un "empalmador" 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 diseño similar al de una revista, no es suficiente poder hacer que el texto fluya a través de 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 del 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 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

En la siguiente captura de pantalla, se muestra lo inverso: texto que fluye dentro de polígonos de forma irregular:

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

El primer paso para poder hacer que el texto fluya alrededor o dentro de formas arbitrarias es desarrollar y optimizar los algoritmos necesarios. Actualmente, Adobe está trabajando en implementaciones que se enviarán directamente a WebKit. Una vez que se optimicen estos algoritmos, se convertirán en la base sobre la que se compilará 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 obtener una perspectiva más detallada del trabajo de Adobe en la tecnología subyacente de las exclusiones de CSS, consulta la entrada de blog de Hans Muller titulada Horizontal Box: Polygon Intersection for CSS Exclusions.

Estado actual de las regiones y exclusiones de CSS

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 personalizados. La recepción fue muy entusiasta, pero hubo una sensación palpable de decepción cuando los observadores descubrieron que ninguna de las funciones que mostraba estaba disponible en ninguno de los navegadores principales.

Volví a asistir a 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 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 deben habilitarse a través de chrome://flags). La compatibilidad preliminar con las regiones de CSS incluso llegó a Chrome para Android:

Regiones en Chrome para Android
Regiones en Chrome para Android

Además, las regiones y las exclusiones de CSS se implementan en la versión preliminar de Internet Explorer 10 y, actualmente, se encuentran en el plan de trabajo de Mozilla para Firefox de 2012. La próxima versión principal de Safari debería admitir la mayoría 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 logramos 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 cantidad de experiencia con el texto, las fuentes y la 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 permanezca estructurado semánticamente y, al mismo tiempo, habilitan un diseño similar al de una revista y, en última instancia, una Web mucho más expresiva.