Layout semelhante a uma revista para a Web com regiões e exclusões de CSS

Christian Cantrell
Christian Cantrell

Introdução

A web é uma plataforma extremamente poderosa para texto, uma área em que o Adobe tem muita experiência e conhecimento. Quando a Adobe estava procurando maneiras de ajudar a web a progredir, o avanço dos recursos de texto parecia um lugar óbvio para começarmos. A Web geralmente pressupõe uma única coluna na orientação vertical para o texto. Embora seja possível fluir o texto ao redor dos gráficos e até mesmo formatar o texto em várias colunas com CSS, ainda é muito difícil obter um verdadeiro layout semelhante a uma revista na Web. Com as regiões do CSS e as exclusões de CSS, a Adobe está liderando o esforço para levar o poder da publicação eletrônica para os navegadores modernos. Por exemplo, na captura de tela abaixo, as exclusões de CSS estão sendo usadas para transmitir o texto ao longo do contorno da montanha:

Exemplo das exclusões de CSS em ação
Exemplo de exclusões de CSS em ação

O documento na captura de tela abaixo também usa exclusões de CSS para permitir que o texto se ajuste a formas nas imagens, assim como regiões CSS para formatar o texto em colunas e ao redor de uma citação:

Exemplo de regiões do CSS em ação
Exemplo de regiões do CSS em ação

Regiões CSS

Antes de entrar nos detalhes das regiões CSS, quero mostrar como as regiões podem ser ativadas no Google Chrome. Depois de ativar as regiões do CSS, é possível testar alguns dos exemplos mencionados neste artigo e criar os seus.

Como ativar regiões CSS no Google Chrome

A partir da versão 20 do Chrome (versão 20.0.1132.57, exatamente), as regiões de CSS são ativadas pela interface chrome://flags. Para ativar as regiões do CSS, siga estas etapas:

  1. Abra uma nova guia ou janela no Chrome.
  2. Digite chrome://flags na barra de local.
  3. Use Localizar na página (control/command + f) e pesquise a seção "Recursos experimentais da plataforma Web".
  4. Clique no link Ativar.
  5. Clique no botão Reiniciar agora na parte inferior.

Para ver mais informações sobre as sinalizações do Chrome, consulte minha postagem do blog sobre Tudo sobre as sinalizações do Chrome.

Depois de reiniciar o navegador, você poderá testar as regiões do CSS.

Uma visão geral das regiões CSS

As regiões CSS permitem que um bloco de texto marcado semanticamente flua automaticamente para "caixas" (atualmente elementos). O diagrama abaixo demonstra a separação de texto (o fluxo) e caixas (as regiões para as quais o texto flui):

O conteúdo flui para regiões definidas
O conteúdo flui para regiões definidas

Vamos analisar um caso de uso real das regiões do CSS. Além de ser desenvolvedor na Adobe, também sou escritor de ficção científica. Eu frequentemente publico meu trabalho on-line sob uma licença Creative Commons e, para permitir que ele funcione na maior quantidade de dispositivos e navegadores, com frequência uso um formato extremamente simples semelhante a este:

Exemplo de projeto legado humano sem estilo
Exemplo de projeto legado humano sem estilo

Com as regiões do CSS, pude criar uma experiência visualmente mais interessante e muito mais funcional, já que é mais fácil de navegar e mais confortável de ler:

Projeto humano legado mostrando a região
Projeto de legado humano com regiões.

Para fins de demonstração, adicionei a capacidade de revelar regiões CSS neste protótipo. A captura de tela abaixo mostra como as regiões são organizadas de modo que dão a impressão de serem colunas que envolvem um gráfico e uma citação no centro:

Projeto de legado humano mostrando regiões
Human Legacy Project mostrando regiões

Você pode testar o protótipo (e ver o código-fonte) aqui. Use as teclas de seta para navegar e a tecla Esc para revelar as regiões. Protótipos anteriores também estão disponíveis aqui.

Como criar um fluxo nomeado

O CSS necessário para que um bloco de texto flua pelas regiões é extremamente simples. O snippet abaixo atribui um fluxo nomeado "article" a um div com o ID "content" e esse mesmo fluxo nomeado "article" a qualquer elemento com a classe "region". O resultado é que o texto contido no elemento "content" passa a fluir automaticamente por meio de qualquer elemento com a classe "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>

O resultado será este:

Resultado do código acima
Resultado do código acima

O texto dentro do div "content" não tem conhecimento de sua apresentação. Em outras palavras, ele pode permanecer totalmente semanticamente intacto enquanto flui por várias regiões. Além disso, como as regiões são apenas elementos, elas são posicionadas e dimensionadas usando CSS como qualquer outro elemento e, portanto, são perfeitamente compatíveis com os princípios de design responsivo. Designar elementos como parte de um fluxo nomeado significa simplesmente que o texto especificado flui automaticamente por eles.

O modelo de objetos CSS

O modelo de objeto CSS (CSSOM, na sigla em inglês) define APIs JavaScript para trabalhar com CSS. Confira abaixo uma lista das novas APIs relacionadas às regiões do CSS:

  • document.webkitGetNamedFlows(): uma função que retorna a coleção de fluxos nomeados disponíveis no documento.
  • document.webkitGetNamedFlows().namedItem("article"): função que retorna uma referência a um fluxo nomeado específico. O argumento corresponde ao nome especificado como o valor das propriedades CSS flow-into e from-from. Para obter uma referência ao fluxo nomeado especificado no snippet de código acima, transmita a string "article".
  • WebKitNamedFlow: uma representação de objeto de um floe nomeado com as seguintes propriedades e funções:
    • firstEmptyRegionIndex: um valor inteiro que aponta para o índice da primeira região vazia associada ao fluxo nomeado. Consulte getRegions() abaixo para saber como conseguir a coleção de regiões.
    • name: um valor de string com o nome do fluxo.
    • overset: uma propriedade booleana que é:
      • false quando o conteúdo do fluxo nomeado se encaixa nas regiões associadas
      • true quando o conteúdo não cabe e mais regiões são necessárias para conter todo o conteúdo.
    • getContent(): uma função que retorna uma coleção com referências aos nós que fluem para o fluxo nomeado.
    • getRegions(): uma função que retorna uma coleção com referências a regiões que contêm o conteúdo do fluxo nomeado.
    • getRegionsByContentNode(node): uma função que retorna uma referência à região que contém o nó especificado. Isso é útil principalmente para encontrar regiões que contenham elementos como âncoras nomeadas.
  • webkitregionoversetchange. Esse evento é acionado em um WebkitNamedFlow sempre que o layout do conteúdo associado muda por qualquer motivo (conteúdo é adicionado ou removido, o tamanho da fonte muda, a forma da região muda etc.) e faz com que a propriedade webkitRegionOverset de uma região mude. Esse evento é útil para detectar alterações aproximadas de layout. É um indicador de que algo importante aconteceu e o layout pode precisar de atenção, como: mais regiões são necessárias, algumas regiões podem estar vazias etc.
  • webkitregionfragmentchange. Não implementado no momento desta edição. Esse evento é acionado em uma WebkitNamedFlow sempre que o layout do conteúdo associado muda por qualquer motivo, semelhante a webkitregionoversetchange, mas independentemente de qualquer mudança nas propriedades webkitRegionOverset. Esse evento é útil para detectar alterações detalhadas de layout que não afetam necessariamente todo o layout do fluxo nomeado, por exemplo: o conteúdo se move de uma região para outra, mas o conteúdo geral ainda se encaixa em todas as regiões.
  • Element.webkitRegionOverset: os elementos se tornam regiões quando têm a propriedade CSS flow-from atribuída. Esses elementos têm uma propriedade webkitRegionOverset que, se fizerem parte de um fluxo nomeado, indica se o conteúdo de um fluxo está transbordando da região. Os valores possíveis de webkitRegionOverset são:
    • "overflow" se houver mais conteúdo do que a região é capaz de conter
    • "fit" se o conteúdo parar antes do final da região
    • “empty” se o conteúdo não tiver atingido a região

Um dos principais usos do CSSOM é detectar eventos webkitregionoversetchange e adicionar ou remover regiões dinamicamente para acomodar quantidades variadas de texto. Por exemplo, se a quantidade de texto a ser formatada for imprevisível (talvez gerada pelo usuário), se a janela do navegador for redimensionada ou o tamanho da fonte mudar, talvez seja necessário adicionar ou remover regiões para acomodar a alteração no fluxo. Além disso, se você quiser organizar seu conteúdo em páginas, precisará de um mecanismo para modificar dinamicamente o DOM e suas regiões.

O snippet de código JavaScript a seguir demonstra o uso do CSSOM para adicionar regiões de modo dinâmico conforme necessário. Para simplificar, ele não processa a remoção de regiões nem define o tamanho e as posições das regiões; serve apenas para fins de demonstração.

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.
}

Veja mais demonstrações na página de exemplos de regiões do CSS.

Modelos de página do CSS

Aproveitar o CSSOM provavelmente é a maneira mais eficiente e flexível de implementar coisas como paginação e layout responsivo, mas a Adobe trabalha com ferramentas de publicação de texto e computador há tempo o suficiente para saber que designers e desenvolvedores também querem uma maneira mais fácil de conseguir recursos de paginação relativamente genéricos. Portanto, estamos trabalhando em uma proposta chamada Modelos de página CSS, que permite que o comportamento da paginação seja definido de maneira totalmente declarativa.

Vamos analisar um caso de uso comum para modelos de página de CSS. O snippet de código abaixo mostra o uso de CSS para criar dois fluxos nomeados: "article-flow" e "timeline-flow". Além disso, define um terceiro seletor chamado "combined-articles" dentro do qual os dois fluxos serão contidos. A simples inclusão da propriedade overflow-style no seletor "combined-articles" indica que o conteúdo precisa ser paginado automaticamente ao longo do eixo X ou horizontalmente:

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

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

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

Agora que os fluxos foram definidos e o comportamento de transbordamento desejado foi especificado, podemos criar o próprio modelo 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; % }
    }
}

Os modelos de página são definidos usando a nova sintaxe "at". No snippet de código acima, definimos três slots, cada um correspondendo a uma coluna. O texto do "article-flow" passa pelas colunas à esquerda e à direita, e o texto do "timeline-flow" (fluxo da linha do tempo) preenche a coluna do meio. O resultado vai ser parecido com este:

Exemplo de modelos de página
Exemplo de modelos de página

O texto do artigo (o texto nas colunas da esquerda e da direita) está em inglês e o cronograma no centro está em alemão. Além disso, as páginas do documento horizontalmente sem a necessidade de códigos JavaScript. Tudo era feito de maneira totalmente declarativa no CSS.

Os modelos de página do CSS ainda são uma proposta, mas temos um protótipo que usa um "shim" JavaScript (também conhecido como polyfill) para permitir que você os teste agora.

Para saber mais sobre as regiões do CSS em geral, confira a página Regiões do CSS em html.adobe.com.

Exclusões de CSS

Para ter um layout parecido com uma revista, não basta conseguir fluir o texto pelas regiões. Um elemento crítico da publicação em computadores de alta qualidade e visualmente interessante é a capacidade de fazer o texto fluir ao redor ou dentro de gráficos e formas irregulares. Com as exclusões de CSS, você está trazendo esse nível de qualidade de produção para a Web.

A captura de tela abaixo é de um protótipo do CSS Exclusões e mostra um texto fluindo dinamicamente ao redor de um caminho que corresponde ao contorno de uma grande formação rochosa:

Exemplo das exclusões de CSS em ação
Exemplo de exclusões de CSS em ação

O inverso é ilustrado na próxima captura de tela: texto fluindo dentro de polígonos com forma irregular:

Texto fluindo em polígonos de forma irregular
Texto fluindo para polígonos de forma irregular

A primeira etapa para fluir texto dentro ou fora de formas arbitrárias é desenvolver e otimizar os algoritmos necessários. A Adobe está trabalhando atualmente em implementações que serão disponibilizadas diretamente para o WebKit. Depois que esses algoritmos forem otimizados, eles se tornarão a base sobre a qual o restante das exclusões de CSS é criado.

Para mais informações sobre exclusões de CSS, acesse a página de exclusões de CSS em html.adobe.com (em inglês). Para conhecer melhor o trabalho da Adobe na tecnologia subjacente de exclusões de CSS, consulte a postagem do blog de Hans Muller intitulada Horizontal Box: Polygon Intersection for CSS Exclusões (Caixa horizontal: interseção de polígonos para exclusões de CSS).

O estado atual das regiões e exclusões de CSS

A primeira vez que falei publicamente sobre regiões e exclusões de CSS foi no Adobe Developer Pod no Google I/O 2011. Na época, eu estava mostrando demonstrações no nosso próprio navegador de protótipo personalizado. A recepção estava extremamente entusiasmada, porém, houve uma sensação palpável de decepção quando os espectadores descobriram que nenhuma das funcionalidades que eu estava mostrando estava disponível em nenhum dos principais navegadores ainda.

Estive no Google I/O novamente este ano (2012), desta vez como apresentador com meu colega de trabalho Vincent Hardy e Alex Danilo do Google (você pode assistir à apresentação aqui). Apenas um ano depois, cerca de 80% da especificação de regiões de CSS foi implementada no WebKit, e ela já está na versão mais recente do Google Chrome. No momento, as regiões do CSS precisam ser ativadas pelo chrome://flags. O suporte preliminar para regiões de CSS chegou ao Chrome para Android:

Regiões no Google Chrome para Android
Regiões no Chrome para Android

Além disso, tanto as regiões quanto as exclusões de CSS são implementadas na visualização do Internet Explorer 10 e estão atualmente no mapa de ação do Mozilla para o Firefox em 2012. A próxima versão principal do Safari será compatível com a maioria das especificações de regiões de CSS e as atualizações subsequentes incluirão o restante.

Veja abaixo um cronograma detalhado do progresso que fizemos com as regiões e as exclusões de CSS desde a proposta inicial do W3C em abril de 2011:

Progresso da região e da exclusão
Progresso por região e exclusão

Conclusão

A Adobe tem muita experiência com texto, fontes e publicação gráfica em geral por meio de ferramentas como o InDesign. Embora a web já seja uma plataforma muito eficiente para texto, queremos usar nosso conhecimento e experiência para aprimorar a apresentação de textos. As regiões e exclusões de CSS permitem que o conteúdo permaneça estruturado semanticamente, além de permitir um verdadeiro layout semelhante a uma revista e, por fim, uma Web muito mais expressiva.