Hacks CSS
Publicado em: 28/07/2008Resolver problemas criados por inconsistências de renderização em diferentes navegadores, muitas vezes, consome um grande tempo do desenvolvedor. Em algumas ocasiões não é possível alcançar consistência para um determinado layout sem uso de regras excepcionais para servir determinadas engines de renderização. Hacks implicam em potenciais complicações e devem ser evitados sempre que possível, contudo quando as circunstâncias requerem o uso deles é bom conhecer as opções disponíveis e analisar cuidadosamente as conseqüências do seu uso. A finalidade deste artigo é descrever alguns hacks CSS, também conhecidos como filtros CSS e suas potenciais conseqüências.
Comentários condicionais
Em conseqüência do fraco suporte para as web standards pelo Internet Explorer a maioria dos hacks CSS se destina a esse navegador. Felizmente a partir da versão 5 o Internet Explorer deliberadamente introduziu um mecanismo denominado “comentários condicionais” que pode ser usado com relativa segurança como um hack.. Comentário condicional é uma estrutura especial de comentário HTML que o Internet Explorer para Windows interpreta de maneira diferente de outros navegadores e tem uma sintaxe capaz de ser reconhecida seletivamente por diferentes versões do navegador. O uso deste mecanismo é capaz de fazer com que o Internet Explorer ignore ou inclua o conteúdo do comentário condicional como marcação HTML regular. Comentários condicionais se aplicam unicamente ao navegador Internet Explorer usando a engine de renderização Trident e isto implica em que navegadores baseados no IE, tais como o Maxthon e o Avant também reconheçam comentários condicionais enquanto navegadores usando outras engines reconheçam os comentários condicionais como simples comentários HTML e os ignore para efeito de renderização. O Internet Explorer para Mac usa uma engine diferente e em conseqüência trata os comentários condicionais tal como navegadores que não sejam o IE.
O maior benefício no uso de comentários condicionais é que não nos baseamos em bugs do navegador para solucionar inconsistências. O uso de hacks CSS se baseia em bugs, e assim, ao usarmos, ficamos sujeitos a inconsistências em futuras versões do navegador que tenham tais bugs corrigidos ou em outros navegadores com os mesmos bugs. Comentários condicionais só funcionam em navegadores que os suportam especificamente ou aqueles explicitamente basedos no Internet Explorer.
Existem duas formas de comentários condicionais: afirmativa e negativa. Um comentário condicional afirmativo serve marcação HTML regular para navegadores que casam com uma determinada condição (o comentário condicional é reconhecido apenas pelas versões declaradas na condição). Um comentário condicional negativo serve marcação HTML regular para navegadores que não casam com uma determinada condição (o comentário condicional é reconhecido apenas por navegadores não baseados no IE e pelas versões declaradas na condição). Convém notar que versões anteriores a versão 5 do Internet Explorer não reconhecem comentários condicionais e o uso deles pode trazer resultados inesperados naqueles navegadores.
[Índice ↑]Sintaxe
A sintaxe geral para escrever comentários condicionais é a mostrada a seguir:
- Afirmativa
<!--[if condição]> HTML <![endif]-->
- Negativa
<!--[if !condição]><![IGNORE[-->
<![IGNORE[]]>
HTML<!--<![endif]-->
condição admite uma das seguintes sintaxes:
IE
- Todas as versões do IE
lt IE versão
- Versões anteriores a versão
lte IE versão
- Versões anteriores ou igual a versão
IE versão
- Somente a versão versão
gte IE versão
- Versões posteriores ou igual a versão
gt IE versão
- Versões posteriores a versão
versão é a versão do Internet Explorer, tipicamente 5
, 5.5
, 6
, ou 7
HTML é a marcação HTML regular a ser incluida se a condição for ou não for satisfeita dependendo do tipo de condição declarada, se afirmativa ou negativa. Quando incluida, a marcação será iserida no código, no mesmo local onde se encontra o comentário condicional.
Para condições negativas a diretiva <![IGNORE[-->
<![IGNORE[]]>
pode ser abreviada para -->
se a condição for simplesmente IE
. A sintaxe não abreviada é necessária somente quando o Internet Explorer tem que parsear o conteúdo do comentário.
A diretiva <![IGNORE[ ... ]]>
não é aceita em XML, assim seu uso é ilegal em XHTML. Uma solução é dividir a diretiva em dois comentários condicionais especiais: <!--[if !condição]> XHTML <![endif]-->
<!--[if !IE]>-->
XHTML <!--<![endif]-->
na qual XHTML é o mesmo nas duas diretivas. Notar que o Internet Explorer 7 e anteriores não reconhecem XHTML servido como XML, assim esta observação que acabamos de fazer aplicar-se-á, possivelmente, somente para versões futuras do IE.
Com a finalidade de evitar que o seu site "quebre" em versões futuras do Internet Explorer leia um artigo em inglês denominado Preparing your site for IE.next.
Versões stand-alone do Internet Explorer
O Internet Explorer foi projetado de modo a não permitir a instalação de mais de uma versão e a Microsoft oficialmente não oferece suporte para instalação de múltiplas versões. Se você usa um programa desenvolvido por terceiros que instala múltiplos IE na sua máquina você constatará várias falhas no funcionamento das diferentes versões e entre elas, falhas no tratamento dos comentários condicionais. Falhas acontecem porque as diferentes versões stand-alone funcionam baseadas em um registro central de dados comum que fornece informações gerais de funcionamento para e entre tais informações está a versão do navegador.
Embora não seja simples contornar todas as questões relacionadas ao funcionamento de diferentes versões stand-alone do Internet Explorer é possível forçar que cada cópia do navegador busque as informações corretas para a sua versão resolvendo as falhas de funcionamento para comentários condicionais. O truque consiste em remover o indicador central da versão do navegador. Para fazer isto abra regedit.exe
no menu “Iniciar » Executar" do Windows. Navegue até HKEY_LOCAL_MACHINE/Software/Microsoft/Internet Explorer/Version Vector/
(Se HKEY_LOCAL_MACHINE
não existe, procure por HKLM
). No painel à direita identifique uma linha com o nome IE
. Renomeie o arquivo para zIE (ou um outro nome qualquer não constante da lista). Recarregue o Internet Explorer e o problema para comentários condicionais em múltiplas instalações do IE está resolvido. A partir de agora quando é aberta uma versão do navegador, ela procura pelo arquivo central das versões e não acha (foi renomeado e o novo nome não é reconhecido) sendo então forçado a procurar a versão correta no seu próprio módulo de instalação.
Versões stand-alone do Internet Explorer apresentam uma série de outros problemas é o ideal e ter cada versão do navegador instalada em uma máquina virtual separada para se ter certeza de que o que você vê nos seus testes é exatamente aquilo que os usuários verão quando navegam com o IE. Eu recomendo VMware Server, que é gratuito e fácil de configurar.
Comentários condicionais como hack CSS
Comentários condicionais podem ser usados como hack CSS servindo folhas de estilo basedas na engine de renderização do navegador. Veja a seguir um exemplo de como servir folhas de estilo com uso de comentários condicionais:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Teste</title>
<link href="todos_navegadores.css" rel="stylesheet" type="text/css">
<!--[if IE]> <link href="somente_ie.css" rel="stylesheet" type="text/css"> <![endif]-->
<!--[if lt IE 7]> <link href="ie_6_e_anteriores.css" rel="stylesheet" type="text/css"> <![endif]-->
<!--[if !lt IE 7]><![IGNORE[--><![IGNORE[]]> <link href="recente.css" rel="stylesheet" type="text/css"> <!--<![endif]-->
<!--[if !IE]>--> <link href="nao_ie.css" rel="stylesheet" type="text/css"> <!--<![endif]-->
</head>
<body>
<p>Teste</p>
</body>
</html>
No exemplo mostrado, todos_navegadores.css
se aplica a todos os navegadores, somente_ie.css
se aplica a todas as versões do Internet Explorer, ie_6_e_anteriores.css
se aplica às versões anteriores ao IE 7, recente.css
se aplica a todos os navegadores, exceto aos IE versões anteriores a 7 e nao_ie.css
se aplica a todos os navegadores que não sejam IE.
Hacks CSS
Um dos inconvenientes dos comentários condicionais é que eles requerem mudanças na marcação HTML. Infelizmente não existe um equivalente a comentários condicionais para uso em folhas de estilo. Assim o uso de hacks CSS sem comentários condicionais implica em técnicas menos confiáveis que normalmente exploram e se baseiam em bugs do navegador.
[Índice ↑]Seletores
A maioria dos hacks CSS se baseia em bugs de interpretação de seletores. A seguir apresentamos uma lista relacionando a versão do navegador e um seletor específico para aquela versão. Notar que uma vez que o hack se baseia em um bug ou em uma funcionalidade não disponível no navegador os resultados obtidos podem variar em navegadores menos conhecidos ou em futuras versões de navegadores. Todos os seletores mostrados a seguir são válidos.
- IE 6 e anteriores
* html {}
- IE 7 e anteriores
*:first-child+html {} * html {}
- IE 7 somente
*:first-child+html {}
- IE 7 e navegadores modernos
html>body {}
- Navegadores modernos (não IE 7)
html>
/*
*/
body {}- Recentes Opera 9 e anteriores
html:first-child {}
Observar que o hack para IE 7 e anteriores é composto de dois seletores: um para IE 7 e outro para IE 6 e anteriores. O elemento alvo do hack deve ser adicionado no final do seletor. Os dois seletores não podem ser combinados com uso de vírgula, pois neste caso o IE 6 e anteriores não parsearão o seletor.
Para funcionar, alguns destes seletores requerem que o documento tenha um doctype declarado, mas sem nenhuma instrução de processamento (inclusive o prólogo XML). Assim fazendo obtemos a configuração ideal para evitar que o IE 6 entre em modo quirks.
Os seletores mostrados selecionam o elemento html
ou o elemento body
. Este é o ponto de partida para o seu seletor completo. Por exemplo: se você deseja selecionar #foo .bar
e aplicá-lo somente no IE 7, o seletor final será: *:first-child+html #foo .bar
.
Atenção: O uso do seletor :first-child
específico para o navegador Opera deve ser considerado com muita precaução pois é provável que futuras versões do Internet Explorer também ofereçam suporte para este seletor. Por outro lado, como este seletor se baseia em um bug do Opera é muito provável que o bug seja corrigido em futuras versões deste navegador. Adiante descrevemos um método alternativo que apesar de ser mais um hack na lista, pelo menos é uma maneira menos insegura, considerando as prioridades de correção de bugs.
Seletores de atributos abreviados
Estes hacks são baseados na diferença de tratamento dado aos seletores de atributo quando declarados na sua forma abreviada. Considere as duas formas de escrita, abreviada e completa: <input disabled>
, input[disabled="disabled"] {}
. Uma regra CSS assim é interpretada diferentemente por navegadores diferentes. Observe a seguir:
><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Teste</title>
</head>
<body>
<input type="hidden" disabled id="attrhack">
<p>Teste</p>
</body>
</html>
Para a marcação mostrada acima veja diferentes seletores para o elemento p
e os respectivos navegadores que os reconhecem:
#attrhack[disabled=""]+p {}
- Firefox 1.5 e anteriores, possivelmente versões futuras
- Safari 2.0 e anteriores, possivelmente versões futuras
- Konqueror 3.5 e anteriores, possivelmente versões futuras
#attrhack[disabled="true"]+p {}
- Opera 9 e anteriores, possivelmente versões futuras
É bom ressaltar que nenhum dos seletores mostrados acima é reconhecido pelo Internet Explorer 7. Embora este navegador reconheça seletores de atributo e seletores combinados para elementos irmãos adjacentes ele não reconhece um valor de string para atributos quando em sintaxe abreviada
Lembrança: Atributos em sintaxe abreviada são permitidos em HTML mas ilegais em XHTML. Este hack não funciona em documentos XHTML.
!important
O Internet Explorer 6 e anteriores são problemáticos no tratamento da diretiva !important
fazendo com que a diretiva seja ignorada quando uma declaração para a mesma propriedade aparecer posteriormente no mesmo bloco de regras de estilo. Este comportamento pode ser usado para servir estilo ao Internet Explorer 6 e anteriores que será ignorado pelos outros navegadores. O Internet Explorer 7 corrigiu este bug.
A seguir um exemplo de uso desta técnica de hack:
><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Teste</title>
<style type="text/css">
p {
background: green !important; /* Navegadores que não o IE 6 e anteriores aplicam esta regra imediatamente */
background: red; /* IE 6 e anteriores aplicam esta regra mesmo havendo uma regra anterior com a diretiva important */
}
</style>
</head>
<body class="page-body">
<p>Teste</p>
</body>
</html>
@import "nao-ie.css" all;
O Internet Explorer 7 e anteriores não reconhecem seletores de mídia em regras declaradas com @import
, ignorando completamente todas as regras ali existentes. Assim, você pode criar uma folha de estilo completa e serví-la para navegadores que não sejam IE importando-a para a folha de estilo principal declarando @import "nao-ie.css" all;
.
Futuras versões do Internet Explorer podem vir a reconhecer @import
.
A declaração @import "stylesheet.css" all;
importa a folha de estilo para todos os navegadores modernos exceto o IE 7 e anteriores. A declaração poderá funcionar ou não em futuras versões do IE.
body[class|="page-body"]
A especificação para CSS 2.1 não é clara no que diz respeito a inclusão ou não de um hífen no valor do atributo quando se trata de seletor de atributo do tipo separado por hífen. A maioria dos navegadores inclusive o Firefox e o Internet Explorer 7 reconhecem uma marcação tal como <body class="page-body">
como alvo do seletor body[class|="page-body"]
. Contudo o Opera interpreta este seletor de modo diferente. Ele considera apenas a primeira parte do valor do atributo, ignorando a segunda parte após o hífen. Fazendo isto o seletor não casa com o elemento cujo atributo tem um valor separado por hífen. No exemplo mostrado o Opera não seleciona o elemento body
e o Internet Explorer 7 e outros navegadores modernos seleciona. Opera deverá mudar este comportamento em versões futuras, mas atualmente sabe-se que o hack funciona para o Opera 8 e 9.
A seguir um exemplo de uso desta técnica:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Teste</title>
<style type="text/css">
p {
background: red; /* Se aplica à maioria dos navegadores */
}
body[class|="page-body"] p {
background: green; /* Se aplica ao IE e à maioria dos navegadores exceto ao Opera */
}
</style>
</head>
<body class="page-body">
<p>Teste</p>
</body>
</html>
body[class|="page-body"] {}
casa com o elemento body
cuja classe é page-body
in no IE 7 e demais navegadores modernos exceto Opera 9 e anteriores . Este hack pode ou não, funcionar em futuras versões.
Hacks não recomendados
Se você pretende usar hacks o uso de uma das técnicas descritas anteriormente é uma boa escolha. Convém alertar para alguns hacks que não devem ser usados. Alguns usam regras CSS inválidas e outros são menos elegantes que os hacks já estudados.
_propriedade: valor e -propriedade: valor
Devido a um erro de parseamento o Internet Explorer 6 e anteriores não reconhecem caracteres não alfanuméricos inseridos no início das propriedades CSS. Iniciando a escrita de uma propriedade com o caractere _
ou -
faz com que a regra CSS seja aplicada pelo Internet Explorer 6 e anteriores e ignorada pelos outros navegadores. O Internet Explorer 7 corrigiu este bug.
As especificações das CSS permitem que os navegadores reconheçam um (_
) ou hífen (-
) como prefixo para o nome de uma propriedade específica para determinado fabricante de navegador com a garantia de que tais propriedades não serão adotadas em futuras especificações das CSS. Considerando isoladamente esta garantia, estes dois caracteres usados como prefixo para uma propriedade seria uma boa opção para hack.
Embora as especificações CSS definam esta sintaxe específica para fabricantes de navegador ela não é endossada em nenhum perfil CSS do W3C e em conseqüência não valida nos validadores CSS do W3C. Por esta razão e considerando que existe uma alternativa aceitável , este hack não é recomendado.
As declarações _propriedade: valor
e -propriedade: valor
são reconhecidas pelo IE 6 e anteriores. Atenção: este hack usa CSS que não valida!
*propriedade: valor
Embora o Internet Explorer 7 tenha corrigido o comportamento errôneo na interpretação de propriedades precedidas dos caracteres _ e - um outro caractere não alfanumérico continua sendo ignorado pelo IE7 e anteriores quando escrito no início da propriedade. Se um caractere não alfanumérico tal como um asterísco (*
) for colocado imediatamente antes do nome de uma propriedade esta será aplicada em todos os IE e ignorada pelos outros navegadores. Ao contrário dos caracteres _ e - as especificações para CSS não fazem reservas ao asterísco como prefixo, assim usar este hack pode resultar em comportamento inesperado com a evolução das especificações CSS.
A declaração *propriedade: valor
é reconhecida pelo IE 7 e anteriores. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS que não valida!
body:empty
A pseudoclasse :empty
é uma proposta das CSS 3 e seleciona elementos que não contenham outros elementos ou textos. Contudo quando esta pseudoclasse é usada no elemento body
os navegadores Firefox 1.5 e 2.0 (e outras versões de navegadores baseados na engine Gecko) sempre selecionam, mesmo que o elemento body
contenha algo (normalmente sempre contém).
Embora este hack, provavelmente, seja validado nas CSS 3 ainda não atingiu o status de recomendação do W3C e é inválido nas CSS 2.x, assim atualmente seu uso não é recomendado. Apesar disto é provavelmente o melhor caminho a seguir para selecionar as versões recentes do Firefox.
body:empty {}
aplica regras CSS no elemento body
no somente no Firefox 1.5 e 2.0. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS 2.x que não valida e CSS 3 válida segundo os rascunhos desta especificação.
a:link:visited, a:visited:link
De acordo com as especificações CSS os estados de links :link
e :visited
são mutuamente exclusivos: :link
significa “link não visitado”. Contudo IE 7 e anteriores ignora uma destas pseudoclasse se a outra for declarada posteriormente no mesmo seletor.
Suponha a tag <a href="foo.html" id="linkhack">
, tanto o seletor #linkhack:link:visited {}
como o seletor #linkhack:visited:link {}
seleciona o elemento no IE 7 e anteriores. Os dois seletores podem ser combinados em um único bloco de declarações assim: #linkhack:link:visited, #linkhack:visited:link {}
. No IE 7, você pode ainda usar seletor combinado do tipo (+
) para selecionar um elemento próximo do link
Este hack usa CSS válida, mas é menos prático que alguns métodos descritos acima e em conseqüência não é recomendado.
a:link:visited, a:visited:link {}
aplica regras CSS no IE 7 e anteriores . Este hack pode ou não, funcionar em versões futuras.
>body
Se um seletor simples for omitido em dos lados do sinal de combinação (>
) o Internet Explorer 7 considera erroneamente que o seletor omitido é o seletor universal. Assim >body
é tratado pelo IE7 como *>body
enquanto os demais navegadores ignoram o seletor devido a erro de parseamento por grafia errada. De modo idêntico, o IE7 considera >>
como se fosse *>*>*
.
O mesmo erro ocorre no IE7 com outros sinais de combinação para seletores. +p
é tratado como *+p
e ~p
é tratado como *~p
. (Nota: o sinal de combinação ~
é uma funcionalidade prevista nas CSS 3 e não valida nas CSS 2.1.
>body {}
aplica regras CSS somente no IE 7. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS que não valida!
html*
Internet Explorer 7 corrigiu o bug que permitia (*
) selecionar um elemento-pai inexistente para o elemento html
, mas permanece um erro não corrigido: quando o seletor universal é colocado imediatamente adjacente a um outro seletor simples o Internet Explorer 7 assume que existe um espaço entre eles. Por exemplo: html*
é tratado pelo IE7 como html *
, enquanto outros navegadores ignoram o seletor devido a erro de parseamento por grafia errada. De modo idêntico, o IE7 considera **
como se fosse * *
.
html* {}
aplica regras CSS em todos os elementos descendentes do elemento html
no IE 7 e anteriores. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS que não valida!
!ie
Internet Explorer 7 corrigiu um dos erros que ocorriam com a diretiva !important
, mas ainda permanece um problema quando há um erro na grafia da diretiva. Se usarmos um nome diferente no lugar de important,
o Internet Explorer 7 e anteriores não consideram erro de parseamento na grafia da propriedade e aplicam a regra CSS normalmente. Assim, em um bloco de declarações você pode usar uma diretiva tipo !ie
para aplicar a propriedade somente naqueles navegadores. Qualquer outra palavra diferente de important pode ser usada no lugar de ie
.
A diretiva !ie
permite aplicar a propriedade CSS no IE 7 e anteriores. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS que não valida!
!important!
Outro problema não corrigido pelo IE7 com relação a diretiva !important
é o tratamento dado a caracteres não alfanuméricos colocados após a diretiva. O Internet Explorer 7 e anteriores erroneamente ignoram tais caracteres e aplicam a propriedade normalmente como se fosse a diretiva !important
.
A diretiva !important!
permite aplicar a propriedade CSS no IE 7 e anteriores enquanto outros navegadores ignoram a diretiva devido a erro de parseamento por grafia errada. Este hack pode ou não, funcionar em versões futuras. Atenção: este hack usa CSS que não valida!
Direitos autorais
Copyright © 2008 David Hammond licenciado segundo Atribuição Compartilhamento pela mesma Licença 3.0 Unported. Você pode modificar e distribuir livremente este trabalho desde que sob as mesmas condições de licença e que atribua os devidos créditos ao autor da versão original. Ver os termos da licença.
Conheça os livros do Maujor®
Ir para a página de entrada nos sites dos livros.