Archive for the ‘css’ Category

Bordas arredondadas no CSS com uma forcinha do PHP

29 \29UTC junho, 2008

Bordas arredondadas parecem nunca sair de moda. Para a infelicidade dos webdesigners, adicionar mais de uma imagem de fundo a um elemento e a propriedade “border-radius” são exclusividades da versão 3 do CSS, que ainda não é suportada pelo navegador da Microsoft e por isso seu uso está fora de cogitação.

Mas nem tudo está perdido: uma ótima técnica que utiliza CSS2, descrita no artigo “Even More Rounded Corners”, permite mostrar bordas arredondadas utilizando apenas uma imagem PNG com a caixa inteira e uma porção de declarações “background-position” para fatiar virtualmente a imagem. Como todas as soluções compatíveis com o IE, ela necessita de marcação extra no HTML para funcionar. Na verdade, ela é bem compacta, vejam:

<div class="dialog">
<div class="content">
<div class="t"></div>
<!-- Seu contéudo vai aqui --></div>
<div class="b">
<div></div>
</div>
</div>

Mesmo compacta ela ainda causa, em menor intensidade, os mesmos já conhecidos problemas das marcações extras:

  • Dificuldade de manutenção: é necessário reproduzir a estrutura cada vez que quisermos uma caixa arredondada.
  • Perda de legibilidade: seu conteúdo ficará escondido num mar de DIVs inúteis.
  • Quebra de encapsulamento: tags com propósito unicamente visual (DIVs vazias!) tornam o código menos semântico e intuitivo.

Não sendo possível diminuir mais a quantidade de porcaria marcação inútil servida para o usuário, podemos ao menos reduzir algumas linhas do nosso código fonte no servidor, utilizando o PHP.

A solução aqui apresentada permitirá escrever no fonte:

<div class="dialog">
<!-- Seu conteúdo vai aqui --></div>

E ter como resultado o código “sujo” da técnica do “Even More Rounded Corners” na saída. O truque é fazer com que o PHP injete as divs necessárias e sirva para o usuário a marcação extra sem sujar o fonte, melhorando legibilidade, facilitando a manutenção e evitando em certo nível a quebra de encapsulamento. Para executar a mágica vamos usar o controle de buffer de saída do PHP e a extensão DOM, para manipular o HTML.

Primeiro, vamos precisar adicionar o seguinte código no início da página, fazendo com que ele execute antes do script emitir qualquer saída:

<?
// Captura a saída em um buffer.
ob_start();
?>

Isso garantirá que toda a saída do PHP seja guardada em um buffer, ao invés de ser enviada diretamente ao user agent.

O próximo e último passo é pegar toda a saída e injetar a marcação extra. Isso deve ser feito, é claro, no fim do script, depois de qualquer saída ter sido gerada e, conseqüentemente, guardada no buffer:

<?
// Lê o buffer de saída para uma variável string.
$saida = ob_get_contents();

ob_end_clean();

// Defina aqui a classe a ser considerada
// para caixas arredondadas.
$classe = "dialog";

// Carrega o documento na classe DOM.
$dom = new DomDocument("1.0");

// Detecta a codificação da página.
if (
  mb_detect_encoding(
  $saida . 'a' , 'UTF-8, ISO-8859-1' )
  ==
  "UTF-8"
  )
{
  $saida = utf8_decode($saida);
}
$dom->loadHTML($saida);

// Seleciona todas as DIVs
$divs = $dom->getElementsByTagName("div");

foreach ($divs as $div) {

  // Filtra as DIVs da classe selecionada.
  if (strstr($div->getAttribute("class"), $classe)) {

    // Cria os nós adicionais
    $content_div = $dom->createElement("div");
    $content_div->setAttribute("class", "content");

    $t_div = $dom->createElement("div");
    $t_div->setAttribute("class", "t");

    $b_div = $dom->createElement("div");
    $b_div->setAttribute("class", "b");

    $extra_div = $dom->createElement("div");

    // Cria a árvore correta
    $b_div->appendChild($extra_div);
    $content_div->appendChild($t_div);

    // Importa o conteúdo do div a ser arredondado
    // para dentro de 'content'.
    while ($div->hasChildNodes()) {
      $content_div->appendChild(
      $div->removeChild($div->firstChild)
      );
    }

    // Adiciona tudo de volta à div.
    $div->appendChild($content_div);
    $div->appendChild($b_div);
  }
}

$resultado = $dom->saveHTML();

echo $resultado;

?>

É claro que você não irá copiar e colar esse texto em todas as suas páginas. Você pode usar dois includes (um no começo do documento e outro ao final), e ainda, se você usa algum sistema de templates, fazer esses includes apenas no arquivo do template.

Podemos adaptar essa técnica para várias outras situações onde necessitamos de marcação extra. Podemos ainda adaptá-la facilmente para rodar no lado do cliente, uma vez que as funções DOM do PHP e do javascript são praticamente idênticas. O único porém deste último método é que não podemos garantir que o user agent suporte e esteja com o javascript habilitado e é então sujeitos a falhas, motivo pelo qual escolhi o método server-side.

Agora ninguém mais tem desculpa para fazer cara feia quando tiver que implementar aquele design todo arredondado!

CSS Hacks ou comentários condicionais?

29 \29UTC junho, 2008

Meu xará Diego Eis escreveu um interessante artigo já há alguns meses em seu famoso blog do site Tableless, o qual recomendava o não uso de comentários condicionais e defendia o uso de CSS Hacks.

O argumento central do texto é que o uso de comentários condicionais duplicam o trabalho do desenvolvedor, pois é criado um arquivo CSS para os navegadores mais compatíveis com as especificações da W3C e outro(s) para os navegadores Internet Explorer. Dada a opção de usar dois arquivos, a tendência é criar uma folha de estilos muito diferente ou até mesmo independente para o navegador da Microsoft.

Mas ao dar uma passada de olho nas estatísticas de uso de navegadores deste mês notamos que cerca de 98% dos usuário utilizam Internet Explorer 6, Internet Explorer 7, Firefox, Opera ou Safari. Menos de 1% utilizam o Internet Explorer 5, conhecido pelo sua implementação problemática do CSS Box Model. Isto significa que se usarmos o Doctype Switch para deixar o IE6 em Strict Mode, atenderemos mais de 98% dos visitantes sem nos valermos do famigerado Box Model Hack! Sendo assim, não precisamos mais definir a altura/largura de cada elemento duas vezes, enxugando de forma decisiva o arquivo CSS exclusivo para os IEs.

Podemos em alguns casos eliminar completamente esse arquivo e ao mesmo tempo não usar nenhum hack, nivelando por baixo os recursos usados e tolerando algumas pequenas diferenças de renderização. Esse é melhor dos mundos, mas em layouts mais rígidos ou complexos e no uso de algumas técnicas mais sofisticadas isso infelizmente não é uma opção, e voltamos a ter que decidir entre hacks e comentários condicionais. Levando em conta o que já foi dito, faço uma avaliação dos prós e contras de cada solução:

Comentarios condicionais:

  • Prós:
    • Mantém o CSS original inalterado e válido.
    • Permite servir CSS customizado ou proprietário de forma segura e suportada pela Microsoft.
    • Pode-se criar um arquivo diferente para cada versão do IE.
    • Feitos para serem usados!
  • Contras:
    • Arquivo separado pode ser difícil de manter.
      • Não é trivial notar onde existe ou não uma correção para o IE ao ler o arquivo original.
      • Por vezes também não é imediata a compreensão do funcionamento da correção no arquivo customizado sem ler a definição no arquivo original.
    • Uma requisição HTTP a mais.
    • Adições no HTML que apesar de comentadas são grandes.
    • Horrível de implementar em definições do atributo style da tag.

CSS Hacks:

  • Prós:
    • Tudo no mesmo arquivo, é fácil ver onde as correções acontecem e ao que se aplicam.
    • Mais compacto, pode ser aplicado facilmente no atributo style.
    • Pode ser usado em definições do atributo style do javascript.
    • Em alguns casos são necessários para outros navegadores que não o Internet Explorer.
  • Contras:
    • Alterações no CSS original, possivelmente comprometendo a validação.
    • Método não suportado, pode criar problemas a cada atualização que a Microsoft liberar.
    • Hacks diferenciais (que afetam apenas uma versão) são deselegantes e deus sabe quanto deselegantes eles podem se tornar nas próximas versões do IE, ou mesmo se alguém será capaz de desenvolvê-los.
    • Baseados em bugs!

Atentando para cada um destes detalhes, faço minhas recomendações. Seguem passo a passo:

  1. Use o Doctype Switch para ativar o Strict Mode no IE6.
  2. Ignore o IE5 e anteriores.
  3. Procure diminuir ao máximo as diferenças entre as definições CSS dos navegadores. Tente eliminá-las completamente, utilizando um CSS Reset e simplificando o layout de forma que as pequenas diferenças de renderização não atrapalhem muito. Isso é fácil de fazer para o IE7, mas pode ser bastante difícil para o IE6, então não complique muito seu código para atingir esse objetivo e considere o próximo passo.
  4. Caso sobrem diferenças, separe-as em outro arquivo (use um nome sugestivo, ‘iefix.css’) utilizando os comentários condicionais. Não crie mais de um arquivo, trabalhe bastante no passo anterior para não precisar de um específico para o IE7.
  5. Utilize comentários no CSS original para indicar onde existem correções no arquivo ‘iefix.css’.
  6. Não utilize o atributo style. Se precisar alterar o estilo por javascript, utilize classes.
  7. Se notar que seu ‘iefix.css’ estiver crescendo muito, considere voltar ao passo 3. Se não houver mais onde enxugar e o tamanho do arquivo ainda for um problema, considere utilizar os Hacks, mas não utilize uma técnica híbrida: utilize CSS Hacks ou comentários condicionais – misturar os dois é a receita certa para dores de cabeça.

Espero ter ajudado (a colocar mais lenha na fogueira desta disussão)!