Portas corrediças com CSS

Publicado em: 29/08/2006

Autor: Douglas Bowman
URL do original: http://www.alistapart.com/articles/slidingdoors/
Título original: Sliding Doors of CSS
Translated with the permission of A List Apart Magazine and the author.

Introdução

Uma das vantagens das CSS raramente explorada é a possibilidade de se criar imagens de fundo em camadas, e fazer com que elas deslizem umas sobre as outras criando efeitos bem interessantes. As CSS2 permitem que somente uma imagem de fundo possa ser colocada em um elemento HTML. Para muitos dos componentes de uma interface, temos a nossa disposição vários elementos para a marcação estrutural.

Um destes componentes é a navegação em abas. Já está na hora de termos o total controle sobre as abas, que a cada dia se tornam mais populares como um componente primário de navegação no site. Agora que as CSS são bem suportadas, podemos incrementar a qualidade e aparência das abas em nossos sites. Você sabe muito bem que as CSS podem ser usadas para estilizar de muitas maneiras um elemento lista ( link para artigo em inglês: tame a plain unordered list). Talvez você já tenha visto listas estilizadas como abas, parecida com esta mostrada a seguir:

Tres abas retangulares

E que tal, se com a mesma marcação usada para a lista acima, pudessemos estilizar de modo a obter as abas mostradas abaixo:

Tres abas com cantos arredondados

Podemos sim, com simples estilização.

O que há de novo ?

Muitas das abas construidas com CSS que eu tenho visto, apresentam características gerais de estilização comuns: blocos retangulares coloridos, as vezes um destaque, como uma borda faltando na aba corrente e uma mudança de cor para o estado de mouse sobre a aba. Isto é tudo que as CSS podem nos oferecer? Um conjunto de caixas coloridas?

Antes mesmo da adoção ampla das CSS nós presenciamos uma série de inovações no design da navegação. Formas criativas, elaboradas misturas de cores e convincentes simulações do mundo real. Contudo estas criações em geral baseiam-se em complexas construções de textos incorporados em imagens ou de múltiplas tabelas aninhadas. Editar um texto ou alterar a ordem de tabulação é um processo extremamente incômodo. Redimensionamento de texto é impossível ou causa sérios problemas ao layout da página.

Navegação construida com texto puro é muito mais fácil de se manutenir e carrega muito mais rápido que construção de textos com imagens. E mais ainda, embora seja possível definir o atributo alt para cada imagem, texto puro ainda e mais acessível uma vez que podem ser aumentados por usuários com restrições visuais. Não é novidade que navegação construida com texto puro estilizada com CSS é um passo atrás no design web. A maioria das navegações com abas e CSS, há muito são inferiores em aparência àquelas complexas construções que fazíamos antigamente. — com certeza nada que possa ser incluido em um portfolio. Uma tecnologia nova (como CSS) deve permitir a criação de algo melhor, sem perda da qualidade de design das construções antigas baseadas em tabelas e imagens.

A técnica das portas corrediças

O uso de duas imagens de fundo, nos permite criar consistentes e flexíveis componentes de interface que se expandem e contraem com o redimensionamento dos textos. Uma imagem à direita e outra à esquerda. Pense nestas duas imagens como se fossem as duas folhas de uma Porta Corrediça que deslizam para fechar o vão total da passagem. As folhas das portas correm uma sobre a outra fechando ou abrindo o vão conforme mostrado no diagrama a seguir:

Diagrama mostrando porta fechada porta aberta

Segundo este modelo, uma imagem cobre uma porção da outra imagem. Suponha que nas imagens o canto superior externo seja arredondado e que nós não permitiremos que a imagem da frente cubra completamente a imagem de trás. Para conseguir este efeito nós construiremos a imagem da frente (vamos supor que a da frente seja aquela que está a esquerda no diagrama mostrado) com uma largura mínima. Uma largura mínima mas o suficiente para mostrar o canto arredondado em cima. Então a imagem da frente terá uma largura suficiente apenas para mostrar a curva do canto superior esquerdo. Ver esquema abaixo:

Diagrama mostrando a falta de preenchimento descrita no texto

Na figura acima se a aba mostrada no lado direito, crescer em largura devido ao tamanho do texto contido nela ou devido a um redimensionamento do tamanho de fonte pelo usuário as duas imagens serão separadas uma da outra, criando um espaço vazio entre elas. Precisamos fazer uma avaliação de quanto a aba poderá expandir-se para evitar este efeito. Como avaliar a expansão da aba em consequência de um redimensionamento da fonte no navegador, pelo usuário? Um dado real a considerar para este caso é algo em torno de pelo menos 300%. Precisamos aumentar a largura da imagem para compensar esta expansão da aba. Para o exemplo mostrado nesta matéria nós construimos a imagem de fundo que fica atrás (a do lado direito) com as dimensões de 400x150 pixels, e a imagem da frente, a da esquerda com 9x150 pixels.

Não se esqueça que imagens de fundo são mostradas na porção disponível do “vão da porta ” do elemento onde são aplicadas (área de conteúdo + padding). As duas imagens são posicionadas nas laterais dos elementos onde são aplicadas. A porção visível das imagens de fundo se unem para dar o formato final a aba:

Diagrama mostrando as imagens aumentadas

Se aba expandir as imagens deslizam para os lados preenchendo o novo vão maior com mais trecho da imagem direita:

Diagrama mostrando o preenchimento com as imagens aumentadas

Para este exemplo eu usei o Photoshop para construir as tres abas mostrada no início deste artigo. Uma das abas é mais clara que a outra — a ser usada para representar a aba, ou link corrente. Segundo esta técnica, para obtenção das imagens esquerda e direita, construimos uma imagem maior que a aba e cortamos em duas partes:

As duas imagens com seus efeitos de cantos e sombras

A mesma construção gráfica deve ser feita para a aba que representará o link corrente. Uma vez construidas as quatro imagens, (1, 2, 3, 4) podemos passar para a marcação e CSS para as abas.

Criando a aba

Se você analisar a construção de listas na horizontal com uso de CSS vai chegar a conclusão que existem pelo menos dois métodos para dispor uma lista em uma linha. Cada um deles com suas vantagens e desvantagens. Ambos empregam técnicas CSS intrincadas que podem tornar as coisas confusas. Um método usa boxes inline o outro floats.

O primeiro método — e possivelmente o mais comum — é o de atribuir display “inline” para cada item da lista. Este método é atrativo pela sua simplicidade. Contudo causa alguns problemas para a técnica de portas corrediças em alguns navegadores.
O segundo método, que é o que empregaremos, usa floats para alinhar na horizontal cada item da lista. Floats podem ser frustantes. O seu comportamento inconsistente vai contra a própria lógica. O entendimento dos conceitos básicos de como lidar com múltiplos floats e o conhecimento de como contornar suas inconsistências proporciona ao autor condições de conseguir maravilhas com floats.

Iremos aninhar vários elementos flutuados, contidos dentro de um elemento float. Faremos isso com o objetivo de colocar todos os elementos float dentro de um elemento pai também flutuado. Assim fazendo poderemos colocar cor e/ou imagem de fundo nas nossas abas. É importante lembrar que o elemento que se segue a aba deverá ser reconfigurado para sua posição com uso da propriedade CSSclear. Isto evita que as abas flutuadas interfiram com o posicionamento dos outros elementos da página.

Vamos começar com a marcação mostrada a seguir:

<div id="header">
    <ul>
      <li><a href="#">Home</a></li>
      <li id="current"><a href="#">News</a></li>
      <li><a href="#">Products</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </div>

Na verdade a div #header deverá conter o logotipo e uma caixa de busca. No nosso exemplo definimos um link morto para valor do atributo href Obviamente em um caso real este valor deverá ser o caminho de destino para o link.

Começamos a estilização flutuando o container #header. Isto assegura que o container “contenha” os items da lista que também serão flutuados. Uma vez que flutuamos, precisamos definir uma largura de 100%. Definimos um fundo temporário na cor amarela para nos assegurarmos de que o container se expande e ocupa toda a área atrás das abas. Definimos ainda mais duas propriedades de fonte e texto, para uniformizar tudo dentro do container:

#header {
    float:left;
    width:100%;
    background:yellow;
    font-size:93%;
    line-height:normal;
}

Uniformizamos ainda as margens e padding default das listas não ordenadas para “0” e removemos os marcadores de lista. Cada item da lista é flutuado à esquerda:

#header ul {
    margin:0;
    padding:0;
    list-style:none;
}
  #header li {
    float:left;
    margin:0;
    padding:0;
    }

Definimos as âncoras para o status de elementos nível de bloco com a finalidade de ter total controle sobre elas sem preocupações com as características típicas de elementos inline:

#header a {
    display:block;
}

A seguir adicionamos a regra para colocar a imagem de fundo direita nos itens da lista (modificações/adicões estão marcadas em forte ênfase):

#header li {
    float:left;
    background:url("norm_right.gif") no-repeat right top;
    margin:0;
    padding:0;
}

Antes de colocarmos a imagem de fundo à esquerda vamos visitar uma página mostrando como estamos até aqui: Exemplo 1. (Na página do Exemplo 1 desconsidere as regras de estilo que eu apliquei para o elemento body. Elas destinam-se apenas a definir valores básicos para margens, padding, cores e texto da página.)

- - -

Agora podemos colocar a imagem da esquerda na frente da imagem da direita definindo-a no elemento âncora (elemento interno na marcação). Definimos também, padding para expandir a aba e desgrudar o texto das laterais:

#header a {
    display:block;
    background:url("norm_left.gif") no-repeat left top;
    padding:5px 15px;
    }

Com estas novas regras, chegamos ao Exemplo 2. Notar como nossas abas começam a ganhar forma. A esta altura um esclarecimento aos usuários do IE5/Mac que devem estar confusos se perguntando “O que está havendo aqui ? As abas estão empilhadas na vertical e esticadas ao longo de toda a extensão da tela.” Não se preocupem, nos veremos adiante. Por agora faça um esforço para seguir, ou temporariamente mude para outro navegador, se tiver um à mão, mas esteja certo que logo resolveremos o problema com o IE5/Mac.

- - -

Já temos as imagens no lugar para as abas normais, agora vamos tratar das abas “correntes”. Faremos isto definindo as regras CSS para os itens da lista contendo suas âncora marcadas com id="current". Não há necessidade de mudar mais nada além da imagem de fundo via a propriedade background-image:

#header #current {
    background-image:url("norm_right_on.gif");
}
  #header #current a {
    background-image:url("norm_left_on.gif");
}

Vamos precisar de uma borda inferior para as abas. Se aplicarmos a propriedade border ao container #header estaremos impedidos de remover a borda para a aba corrente. Então criamos uma outra imagem que contenha a borda a ser incluida ao longo da parte inferior das abas. Para incrementar o visual acresentamos um gradiente na imagem para a borda, conforme mostrado abaixo:

Imagem gradiente superior e borda em baixo

Aplicamos esta imagem como fundo do container #header (para substituir aquela cor amarela que havíamos colocado) posicionando-a na parte inferior do elemento e usando uma cor de fundo igual a cor mais clara do gradiente. A seguir removemos o padding que havíamos aplicado ao elemento body e aplicamos 10 pixels de padding em volta do elemento ul:

#header {
    float:left;
    width:100%;
    background:#DAE0D2 url("bg.gif")
      repeat-x bottom;
    font-size:93%;
    line-height:normal;
}
  #header ul {
    margin:0;
    padding:10px 10px 0;
    list-style:none;
    }

Para completar o efeito nas abas precisamos remover a borda inferior na aba corrente conforme mencionamos anteriormente. Você poderia pensar que a solução seria simplesmente aplicar uma borda inferior nas abas com a cor igual a cor da imagem de fundo que acabamos de colocar em #header e assim mudar a cor da borda para a aba corrente. Contudo esta solução implica no aparecimento de uma pequena 'falha' quase imperceptível, mas visível a um observador atento. Então a solução está em alterar o padding da âncoras, criando um fechamento perfeito das bordas conforme mostrado na figura ampliada abaixo:

Imagem aumentada de duas abas mostrando a falha e a correcao

fazemos isso diminuindo o padding das âncoras de 1 pixel (5px - 1px = 4px), e acresentando de volta 1pixel para a âncora corrente:

#header a {
    display:block;
    background:url("norm_left.gif")
      no-repeat left top;
    padding:5px 15px 4px;
}
  #header #current a {o
    background-image:url("norm_left_on.gif");
    padding-bottom:5px;
    }

Esta ateração retira a borda inferior da âncora corrente enquanto conserva a borda para as demais. Tudo conforme mostrado no nosso Exemplo 3.

Acertos finais

Olhares atentos devem ter percebido que aparece um fundo branco junto aos cantos arrendodados das abas. Estes cantos opacos estão impedindo que a imagem de trás (NT: a imagem de fundo do container #header) possa ser visualizada através do canto esquerdo da imagem em frente. Teoricamente a solução seria a de igualar as cores naquele cantinho das imagens das abas com a cor do fundo do container #header atrás delas. Mas, as abas podem se estender em altura o que causaria um deslocamento para baixo do fundo de trás das abas inviabilizando esta solução, pois ali há um gradiente de cor. Vamos então fazer nossas imagens com os cantos das abas transparentes. E definindo curvas anti-aliased com cor de mate igual a cor do fundo por trás delas.

Agora que os cantos são transparentes, através desta transparência, no lado esquerdo, vai aparecer a imagem que está por trás ou seja a imagem da direita (NT: e não o fundo do container #header como queríamos). Para corrigir isso definimos um padding à esquerda para os itens de lista com valor igual a largura da imagem esquerda (9px). Uma vez que este padding foi acrescido precisamos compensar removendo o mesmo valor do padding das âncoras para mentê-las centradas (15px - 9px = 6px):

#header li {
    float:left;
    background:url("right.gif")
      no-repeat right top;
    margin:0;
    padding:0 0 0 9px;
}
  #header a {
    display:block;
    background:url("left.gif")
      no-repeat left top;
    padding:5px 15px 4px 6px;
}

Contudo, as coisas não podem ficar como estão, pois ao adicionarmos um padding de 9 pixels, a imagem da esquerda foi empurrada estes 9 pixels para a esquerda tornando-se agora invisível. As laterais das duas imagens se tocam na porção visível da aba e assim não há mais a necessidade de se manter a imagem da esquerda na frente. Podemos trocar a posição das imagens aplicando-as a elementos opostos. Faremos isto também para a aba corrente:

#header li {
    float:left;
    background:url("left.gif") no-repeat left top;
    margin:0;
    padding:0 0 0 9px;
}
  #header a, #header strong, #header span {
    display:block;
    background:url("right.gif")  no-repeat right top;
    padding:5px 15px 4px 6px;
}
  #header #current {
    background-image:url("left_on.gif");
}
  #header #current a {
    background-image:url("right_on.gif");
    padding-bottom:5px;
}

Isto feito, podemos visitar nosso Exemplo 4. Notar, lá no Exemplo 4, que o fato de termos feito o fundo das imagens das abas, transparentes, criou um pequeno espaço morto não clicável no lado esquerdo da aba. Este espaço está fora da área de texto, contudo o usuário poderá percebê-lo. Usar transparência para o fundo das imagens não é obrigatório. Se não desejamos aquele pequeno espaço não clicável, podemos optar por usar para fundo geral das abas, ou seja fundo do container #header uma cor contínua em lugar de um gradiente como fizemos, e usar esta mesma cor para fundo das imagens das abas. Por enquanto deixaremos as coisas como estão, com fundo transparente para as imagens das abas.

- - -

Vamos agora fazer umas estilizações gerais: bold para os textos das abas, mudar a cor da fonte das abas para cor marrom, mudar cor do texto da aba corrente para cinza escuro. Podemos agora notar estas estilizações no nosso Exemplo 5.

Um hack para consistência

Quando vimos o Exemplo 2, falamos de uma inconsistência de renderização no navegador IE5/Mac que posiciona as abas na vertical e ainda estende cada uma por toda a largura do navegador. Não era bem isto que estávamos querendo.

Na maioria dos navegadores ao flutuar um elemento, ele se encolhe a uma largura mínima possível no elemento que o contém. Se o elemento flutuado contém ou é uma imagem, ele se encolhe para uma largura igual a largura da imagem. Se o elemento flutuado contém texto, ele se encolhe para uma largura igual a largura da maior palavra.

Para o navegador IE5/Mac quando um elemento nível de bloco com largura auto é inserido dentro de um elemento flutuado há uma inconsistência de renderização. Nestes casos o IE5/Mac não reduz a largura do float como explicado acima. Ao contrário, ele expande o float e o elemento nível de bloco para toda a largura disponível. Para solucionar este problema precisamos flutuar os elementos âncoras, mas somente para o IE5/Mac, escondendo dos outros navegadores a declação float para as âncoras. Primeiro declaramos float para as âncoras — todos os navegadores 'enxergam'. A seguir usamos Commented Backslash Hack para anular a declaração para todos os navegadores menos para o IE5/Mac:

#header a {
    float:left;
    display:block;
    background:url("right.gif")
      no-repeat right top;
    padding:5px 15px 4px 6px;
    text-decoration:none;
    font-weight:bold;
    color:#765;
}
  /* Commented Backslash Hack
     esconde para o IE5-Mac \*/
  #header a {float:none;}
  /* End IE5-Mac hack */

Agora os navegadores IE5/Mac renderizam corretamente as abas conforme nosso Exemplo 6. Nada mudou para os demais navegadores. Notar que o IE5.0/Mac teve uma quantidade grande de bugs corrigidos com a versão... (NT: Retirei da tradução um parágrafo onde o autor à epoca em que escreveu este artigo — ano 2003 — considera as versões já em desuso dos navegadores IE5.x/Mac.)

Variantes

Acabamos de ver a técnica das portas corrediças para abas de navegação que utiliza texto puro e é marcada com o elemento lista e estilizada com algumas regras CSS. O carregamento é rápido, a manutenção é facil e o texto pode ser redimensionado sem quebrar o layout. Precisamos falar mais alguma coisa sobre a grande flexibilidade desta técnica para criar qualquer tipo de sofisticadas navegação com abas?

O limite é a sua imaginação. Neste exemplo final mostramos uma das possibilidades. Não devemos deixar que um exemplo limite nossa criatividade.

Por outro lado abas não precisam ser simétricas e quadradas. Criei uma Versão 2 para nossa navegação com abas, retirando a aperência 3-D e usando cores sólidas, vértices angulares, e um canto esquerdo maior e mais elaborado. Podemos até mesmo inverter a ordem das imagens esquerda e direita das abas como mostrado na Versão 2. Com um planejamento cuidadoso e uma manipulação de imagens inteligente a borda inferior das abas pode ser substituida por outros efeitos combinando o fundo conforme mostro na minha deco Versão 3. Se o seu navegador permite que você alterne as folhas de estilo da página renderizada então neste este arquivo mestre que eu construi você poderá visualizar as três versões alterando as folhas de estilo disponíveis.

Outros efeitos podem ser conseguidos. Neste exemplo eu usei efeito de troca de cores de texto na ação do ponteiro sobre a aba, mas você poderá colocar efeitos de rollover de imagens bem interessantes.Uma vez que dois elementos aninhados sejam colocados na marcação, nós poderemos começar a pensar em imagens de fundo para obter efeitos que talvez nem imaginamos ainda. Nos usamos a técnica das Portas corrediças para criar uma navegação horizontal com abas, contudo ela poderá ser usada em muitas outras situações. E você? O que você seria capaz de criar com esta técnica?

topo