Você sabia?
JavaScript não possui classes, mas possui construtores. More...

Bordas arredondadas no CSS com uma forcinha do PHP

Posted: junho 29th, 2008 | Author: diegoquinteiro | Filed under: PHP, css | Tags: , , | 1 Comment »
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?

Posted: junho 29th, 2008 | Author: diegoquinteiro | Filed under: css | Tags: , | 2 Comments »
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)!