08 fevereiro 2006

Em Busca do Santo Graal

por Matthew Levine

Desculpe. Mesmo. Eu não pretendo sobrepor sua importância ou menosprezar os outros, talvez mais respeitados, Santo Graals.

Mas o nome está aí, e todos nós sabemos o que significa.

Três colunas. Uma barra lateral fixa para sua navegação, outra para, digamos, seus anúncios do Google ou suas fotos no Flickr – e, como num passe de mágica, um miolo líquido para o que realmente interessa. Sua vasta versatilidade nesta época dourada de blogs, em conjunto com sua considerável dificuldade, foi o que deu a este layout o título de Santo Graal.

Muitos artigos foram escritos sobre ele. E muitos templates existem. No entanto, todas as soluções existentes envolvem sacrifício: ordem específica de código, rodapés de largura inteira e código pobre estão geralmente ligados à aplicação deste vago layout.

Um projeto recente levou minha busca pelo Graal ao fim. A técnica que vou descrever permitirá que você aplique o “Santo layout” sem comprometer seu código ou sua flexibilidade. Ele vai:

  1. ter um miolo líquido com barras laterais fixas,
  2. permitir que a coluna central apareça antes no código,
  3. permitir que qualquer coluna seja a mais alta,
  4. necessitar de uma única div adicional, e
  5. necessitar de um CSS muito simples, com “patches” mínimos.

Nos ombros dos gigantes

A técnica apresentada aqui é inspirada pela brilhante One True Layout, de Alex Robinson. Alex até falou sobre o problema do Santo Graal em seu artigo, mas sua solução precisa de dois boxes externos e dificulta o “padding” sem o uso de uma div adicional em cada coluna.

Outro caminho veio da adaptação de Eric Meyer, que usa posicionamento para misturar diversos tipos de medida. Seu exemplo também conta com um layout de três colunas com laterais fixas e um miolo líquido. Infelizmente, ele se baseia em porcentagem aproximada e ocupa uma porção da área visível que varia dependendo da resolução.

Chega de papo – vamos ver o código

O HTML necessário é intuitivo e elegante.

(Para deixar clara a demonstração desta técinca, estamos intencionalmente usando os ids não-semânticos “center”, “left” e “right”. Recomendamos que você use ids semânticos em qualquer aplicação desta técnica.)

<div id="header"></div>

<div id="container">

<div id="center" class="column"></div>

<div id="left" class="column"></div>

<div id="right" class="column"></div>

</div>

<div id="footer"></div>

É isso. Uma única div adicional que contém as colunas é tudo o que você precisa; isto satisfaz até meus hábitos compulsivos de codificação.

O CSS é quase tão simples. Digamos que você quer uma coluna esquerda com uma largura fixa de 200px e uma coluna direita com uma largura fixa de 150px. Para simplicar os comentários, vou abreviar as colunas da esquerda (left), direita (right) e central (center) como LC, RC e CC, respectivamente. O CSS básico está aqui:

body {

min-width: 550px; /* 2x LC width + RC width */

}

#container {

padding-left: 200px; /* LC width */

padding-right: 150px; /* RC width */

}

#container .column {

position: relative;

float: left;

}

#center {

width: 100%;

}

#left {

width: 200px; /* LC width */

right: 200px; /* LC width */

margin-left: -100%;

}

#right {

width: 150px; /* RC width */

margin-right: -150px; /* RC width */

}

#footer {

clear: both;

}

/*** IE6 Fix ***/

* html #left {

left: 150px; /* RC width */

}

Simplesmente substitua os valores com as dimensões que desejar e ele é todo seu. A técnica funciona em todos os navegadores modernos: Safari, Opera, Firefox e (com o pequeno hack) IE6. Para suportar o IE5.5, precisaríamos de pelo menos um hack de box-model, que deixo como um exercício para o leitor.

Dê uma olhada e se impressione com a elegância.

Como funciona

A estratégia é bem direta. A div externa terá um miolo líquido e “paddings” fixos nas laterais. O truque está em fazer com que a coluna esquerda se alinhe com o “padding” esquerdo e a coluna direita com o “padding” direito, deixando a coluna central preencher a largura variável da caixa externa.

Vamos construir isto passo a passo.

Passo 1: Crie a moldura

Comece com o cabeçalho, rodapé e conteúdo.

<div id="header"></div>

<div id="container"></div>

<div id="footer"></div>

Definimos o padding do conteúdo com a largura que queremos para as colunas esquerda e direita.

#container {

padding-left: 200px; /* LC width */

padding-right: 150px; /* RC width */

}

Nosso layout se parece com isto:

Passo 1: Crie a moldura

Passo 2: Adicione as colunas

Agora que temos nossa moldura básica, vamos nos concentrar nas colunas.

<div id="header"></div>

<div id="container">

<div id="center" class="column"></div>

<div id="left" class="column"></div>

<div id="right" class="column"></div>

</div>

<div id="footer"></div>

Em seguida informamos as larguras apropriadas e definimos o “float” para exibí-las na mesma linha. Também precisaremos ajustar o rodapé para mantê-lo abaixo das colunas com “float”.

#container .column {

float: left;

}

#center {

width: 100%;

}

#left {

width: 200px; /* LC width */

}

#right {

width: 150px; /* RC width */

}

#footer {

clear: both;

}

Perceba que a largura de 100% da coluna central se refere à largura da caixa externa (#container), excluindo o padding. Veremos esta largura de 100% novamente quando o layout estiver completo, e ela vai continuar se referindo a esta largura central da “#container”.

Agora as colunas querem se alinhar na ordem, mas como a coluna central está ocupando 100% do espaço, as colunas esquerda e direita descem.

Passo 2: Adicione as colunas

Passo 3: Puxe a coluna esquerda para seu lugar

A única coisa que falta é alinhar as colunas ao padding da “#container”. A coluna central começa exatamente onde deveria, então vamos focar na esquerda.

São dois passos para colocar a coluna esquerda no lugar. Primeiro, colocaremos ela junto da coluna central com uma margem negativa de 100%. Lembre-se que estes 100% se referem à largura central da “#container”, que é exatamente a largura da coluna central.

#left {

width: 200px; /* LC width */

margin-left: -100%;

}

Agora a coluna esquerda está sobrepondo a central, compartilhando seu lado esquerdo. A coluna direita vai para a esquerda e se aproxima do lado direito da coluna central (mas ainda desce), nos deixando com o seguinte:

Passo 3: Puxe a coluna esquerda para seu lugar – quase lá

Para movermos a coluna esquerda pela distância restante, usaremos um posicionamento relativo com um valor que é exatamente a largura dela.

#container .columns {

float: left;

position: relative;

}

#left {

width: 200px; /* LC width */

margin-left: -100%;

right: 200px; /* LC width */

}

A propriedade right empurra a coluna para 200 pixels da borda direita, ou seja, para a esquerda. Agora a coluna esquerda se alinha perfeitamente com o “padding” esquerdo da “#container”.

Passo 3: A coluna esquerda em seu lugar

Passo 4: Puxe a coluna direita para seu lugar

A única coisa que falta é puxar a coluna direita para seu lugar. Para fazer isso, só precisamos puxá-la para fora da “#container” e dentro do padding. Novamente usaremos uma margem negativa.

#right {

width: 150px; /* RC width */

margin-right: -150px; /* RC width */

}

Agora tudo está em seu luigar, e a quebra desaparece.

Passo 4: Puxe a coluna direita para seu lugar

Passo 5: Desenvolva defensivamente

Se a janela do navegador for redimensionada até que a coluna central fique menor que a esquerda, o layout se quebra num navegador em conformidade com os padrões (standards-compliant). Definindo um min-width no body mantém suas colunas no lugar. Com o IE6 isto não acontece, então o fato de ele não suportar min-width não chega a ser um problema.

body {

min-width: 550px; /* 2x LC width + RC width */

}

É claro, nenhuma técnica de layout estaria completa sem precisar de algum tipo de gambiarra no Internet Explorer. A margem negativa puxa a coluna esquerda além do necessário para o IE6 (a largura inteira da janela). Precisamos empurrá-la de volta com mesma distância da coluna direita – usando o hack da estrela-html para escondê-lo de outros navegadores – e aí estaremos prontos.

* html #left {

left: 150px; /* RC width */

}

O motivo de precisarmos usar a largura da coluna direita envolve um pouco de álgebra. Não vou chateá-los com os detalhes; você pode tentar descobrir sozinho ou simplesmente considerar isto como um dos muitos charmes do IE.

Padding, por favor

Eu não sou designer, mas olhar para o layout acima ofende até meus sentidos sem estética. As colunas grudadas dificultam a visão e a leitura. Precisamos de espaço.

Uma das desvantagens de usar porcentagem com o One True Layout para criar layouts líquidos é que ele dificulta a definição do “padding” das colunas. “Paddings” em porcentagem tendem a ficar feios em algumas resoluções. “Paddings” fixos podem ser definidos, mas só se inserirmos uma div adicional dentro de cada coluna.

Com esta técnica, o “padding” não é um problema. Ele pode ser definido diretamente nas colunas esquerda e direita; simplesmente ajuste a largura correspondente. Para dar um “padding” de 10px à coluna esquerda no exemplo acima, mas manter sua largura (“padding” + largura) em 200px, simplesmente mude o CSS como abaixo:

#left {

width: 180px; /* LC fullwidth - padding */

padding: 0 10px;

right: 200px; /* LC fullwidth */

margin-left: -100%;

}

Aplicar o “padding” à coluna central requer um pouco mais de habilidade, mas nenhum código html e só alguns detalhes no CSS.

O “padding” mais a largura de 100% fazem com que a coluna central fique maior que a largura sem “padding” da “#container”. Para fazer com que ela volte ao lugar, precisamos aumentar a margem direita com o total do “padding”. Isto garante que a coluna central tenha a largura que esperamos.

Além disso, uma vez que a coluna central está maior, a esquerda tem uma distância maior a percorrer para ficar no lugar certo. Aumentando esta distância com o total do “padding” central faz o serviço.

Para concretizar, vou modificar o exemplo para adicionar um “padding” de 10px para cada lado das colunas (num total de 20px), e um “padding” de 20px para cada lado da coluna central (num total de 40px). O novo CSS se parece com isso:

body {

min-width: 630px; /* 2x (LC fullwidth + CC padding) + RC fullwidth */

}

#container {

padding-left: 200px; /* LC fullwidth */

padding-right: 190px; /* RC fullwidth + CC padding */

}

#container .column {

position: relative;

float: left;

}

#center {

padding: 10px 20px; /* CC padding */

width: 100%;

}

#left {

width: 180px; /* LC width */

padding: 0 10px; /* LC padding */

right: 240px; /* LC fullwidth + CC padding */

margin-left: -100%;

}

#right {

width: 130px; /* RC width */

padding: 0 10px; /* RC padding */

margin-right: -190px; /* RC fullwidth + CC padding */

}

#footer {

clear: both;

}

/*** IE Fix ***/

* html #left {

left: 150px; /* RC fullwidth */

}

Logicamente, “paddings” superiores e inferiores podem ser adicionados sem problemas. Veja esta simpática versão com “padding” para o template.

Esta técnica funciona tão bem para sem quanto para pixels. Infelizmente, você não pode misturar ems e pixels, então faça sua sábia escolha.

Colunas de alturas iguais

Esta técnica realmente fica completa quando as colunas ganham alturas iguais. O método que estou usando foi adaptado completamente do One True Layout, então não vou entrar em detalhes. Para aplicá-lo, simplesmente adicione o CSS abaixo:

#container {

overflow: hidden;

}

#container .column {

padding-bottom: 20010px; /* X + padding-bottom */

margin-bottom: -20000px; /* X */

}

#footer {

position: relative;

}

Aqui eu coloquei um “padding” adicional de 10px no inferior das colunas.

Os avisos comuns se aplicam. Fique atento com o bug de overflow:hidden do Opera 8 que deixa todas suas colunas enormes. Uma alternativa é detalhada no One True Layout; você pode usá-la, ou esperar que o Opera 9 (que corrige o bug) saia do beta.

Um outro problema deste layout é que o IE não corta o fundo das colunas no final da “#container”. Eles passam por cima do rodapé se a página não é tão alta quanto a janela. Isto não é um problema se você não tem um rodapé separado, ou se suas páginas são altas o suficiente para garantir que elas sempre serão maiores que a janela.

Mas se você precisa mesmo do rodapé, não tenha medo. Isto também pode ser arrumado, mas requer mais uma div . Adicione uma caixa externa ao rodapé, assim:

<div id="footer-wrapper">

<div id="footer"></div>

</div>

Agora use o mesmo truque com as colunas para fazer com que a caixa externa do rodapé se extenda para além da página, deixando o rodapé em si para que você faça como quiser.

* html body {

overflow: hidden;

}

* html #footer-wrapper {

float: left;

position: relative;

width: 100%;

padding-bottom: 10010px;

margin-bottom: -10000px;

background: #fff; /* Same as body

background */

}

Isto resolve o problema e nos deixa com o resultado desejado.

Ah, e tem mais uma coisa

Os extremistas por aí podem estar pensando se não existe um jeito ainda melhor de se fazer isso. Afinal, o método que apresentei utiliza uma “#container” não-semântica. Certamente não podemos ter uma div adicional atrapalhando nosso impecável código.

Se você, como eu, está pensando neste detalhe, não pense mais. Como um bônus especial, apresento a você o Santo Graal sem “container”, em toda sua glória minimalista. Uma div para cada seção do código – nada mais, nada menos. O supra-sumo semântico, quase merecedor do título de “Santo Graal”.

O princípio por trás do CSS é o mesmo. O “padding” foi aplicado diretamente ao body , eliminando a necessidade de “containers”. Margens negativas delimitam o cabeçalho e o rodapé para garantir que eles fiquem no lugar certo.

Esta versão funciona em todos os navegadores citados anteriormente, até no (quase um milagre) Internet Explorer. No entanto, as colunas de alturas iguais não funcionam e este layout ficará quebrado em janelas muito estreitas. Use-o com cuidado.

E agora?

Enquanto esta aplicação específica do Santo Graal é um tanto quanto restrita, a técnica pode ser bem generalizada. Por que não ter duas colunas líquidas? Por que não inverter a ordem das colunas? Estas aplicações estão além do escopo deste artigo, mas atingíveis com pequenas modificações. Use o Graal com sabedoria, e ele pode ser uma adição muito útil para sua bagagem de truques de CSS.

-----

Este artigo foi publicado originalmente na edição 211 da A List Apart e pode ser acessado aqui.

Traduzido por Luciano Rodrigues.

6 Comments:

Anonymous Anônimo said...

Salve!

Obrigado pelo artigo traduzido, muito bom mesmo, consegui observar muita coisa que não sabia.

Continue assim!

Abraços1

2:36 PM  
Anonymous Anônimo said...

Gostei dessa técnica!
Eu tive uns 'poréns' ao usá-la. Ei-los:

. "min-width" para o "body" não funcionou no IE... eu fiz isso:
" body { min-width: 550px !important; width: 550px; /* 2x LC width + RC width */ } "

. a definição da margem esquerda da 'DIV esquerda' em porcentagem não funcionou legal no IE. Neste caso (e só para este caso) eu atribuí um valor absoluto, que vem a ser o resultado da largura do 'container' menos a soma da largura das respectivas colunas laterais. Esse resultado, como dá pra perceber, é a largura, digamos, 'efetiva' da DIV central.

No firefox e no ópera, o valor de 100% na margem esquerda da 'DIV esquerda' ficou perfeito.

. o "/*** IE6 Fix ***/" pra mim não foi útil em nada. Simplesmente limei-o do código e tudo ficou OK. (Não testei no iE 5.0)

No mais, ótima técnica! By the way: se precisar de ajuda nas traduções do ALA, fico à sua disposição. Valeu!

4:35 PM  
Anonymous Anônimo said...

coloquei o resultado das minhas pretensas correções aqui: http://www.personaraujo.com/estudos/css/

4:37 PM  
Anonymous Anônimo said...

muito legal esse layout e parabéns pela tradução! sou iniciante em Web, mas acho que aos poucos vou aprendendo...

uma coisa person araujo, eu estive observando o codigo, e o resultado. Fui lendo o texto e fazendo o meu layout. No final, ficou tudo zoado no IE, fiquei um tempao tentando acertar aqui e ali, ate que descobri que a declaração Doctype estava fazendo diferença. Inclui essa declaração no meu código e ficou perfeito no IE. Qto. ao FF e Opera, funcionam perfeitamente, uma maravilha!

1:49 AM  
Anonymous Anônimo said...

As alturas do container e das colunas não acompanham a coluna maior, mesmo definindo o Doctype corretamente. Tanto no FF, quanto no IEca, fui verificar o exemplo, mas esse aparece atribuindo um padding enorme à div container.
Continuo tentando.

4:34 PM  
Blogger groove said...

valeu pelo post...
estou começando a trab. com CSS e
estava me matando tentando resolver um problema no ie6, algumas "divs" estavam descendo na coluna direita do meu site, mas com a dica do min-width resolveu o problema...
vlw galera...
fico devendo essa...

2:12 AM  

Postar um comentário

<< Home