Acessar o CSS com javascript é algo que fazemos com frequência e que não envolve grandes mistérios, mas há certas coisas que raramente precisamos fazer e acabamos esquecendo até que aquilo é possível. Desculpem, estou escrevendo na 3ª pessoa mas na verdade estou falando apenas por mim… Nesse texto vou responder às minhas próprias dúvidas, tentando exorcisar o comodismo, mas também por acreditar que outros podem ganhar com as respostas que encontrei.
O CSS declarado inline, dentro da própria TAG, está facilmente acessível ao javascript, tanto para ler quanto para modificar. Podemos também ler e modificar com facilidade o valor da propriedade className das TAGs, alternando entre grupos de regras css pelos nomes das classes correspondentes. Mas, até pouco tempo atrás, havia para mim dois pontos incógnitos, duas perguntas que me perseguiam: "como modificar regras dentro de uma classe?" e "como obter as regras que incidem em determinado elemento por herança?". Bem, sou um autodidata e é essa curiosidade que me faz andar para frente, portanto, pesquisei e, como sempre, descobri que é simples. Aliás, essa é uma lição que posso dar aos iniciantes que são autodidatas como eu: difícil é aquilo que ainda não aprendemos a fazer, o resto é fácil. Não se deixe intimidar.
Como essas questões me incomodaram por bastante tempo, achei que valia escrever esse tutorial. Vamos lá, vou responder a elas da melhor maneira que conseguir.
Como modificar regras dentro de uma classe CSS?Bem, naturalmente o javascript não pode modificar o que está escrito (hard-coded) no arquivo, mas entre a leitura das classes CSS declaradas na página e a renderização dos elementos a partir delas, o navegador faz mais do que sonha a nossa vã filosofia… e o fato é que o documento é rederizado com base em um objeto que contém as regras CSS lidas e não no texto-base do documento exibido. E este objeto (document.styleSheets) pode ser lido e modificado! Sua anatomia é complexa e prá variar (mesmo nesses tempos de padronização), muda de um navegador para outro. Mais correto seria dizer "de um navegador para os outros"… mas deixa prá lá. Vamos tentar concentrar em áreas acessíveis aos dois (Mozilla e IE).
A primeira propriedade que precisamos entender é o length, que está disponível em todos os browsers e faz referência aos elementos de estilo existentes no ducumento. Estou falando das duas TAGs que são usadas para esse fim: <STYLE> e <LINK>. No documento que você está vendo há o seguinte CSS:
para as TAGs body, h1 e h2 –>
<link rel="stylesheet" type="text/css" href="test.css" />
<style type="text/css">
.codigo {
padding:8px;
width: 90%;
height:auto;
font-family:"Courier New", "Lucida Console";
font-size: 1.1em;
background-color: #FAFAFA;
height: auto;
border:3px dashed #CCC;
margin:20px 10px 20px 10px;
overflow:auto;
}
</style>
Bem, temos um elemento STYLE e um elemento LINK, portanto a propriedade document.styleSheets.length será igual a 2. A eventual presença de um @import url(…) dentro de um elemento STYLE não iria interferir na propriedade length, mas numa outra propriedade, da qual não trataremos aqui: imports.
Os elementos do objeto são idênticos para regras adquiridas de arquivos CSS externos ou de elementos STYLE declarados na própria página e a forma de reconhecê-los é pela propriedade href, que não existe em TAGs STYLE. A propriedade href do objeto document.styleSheets[_INDICE_], por outro lado, existirá em todos os elementos, mas para as TAGs STYLE o IE devolverá uma string vazia e o Mozilla, a URL do arquivo atual (…?).
Outra forma é usar o atributo owningElement (IE) / ownerNode (Moz), que aponta para uma referência ao nódulo DOM relativo à TAG em questão. Daí basta usar o atributo tagName. Veja:
&& document.all)); // é Internet Explorer?
// propriedades que mudam de nome do IE para o Mozilla…
var rulesName = isIE ? ‘rules’ : ‘cssRules’;
var domNode = isIE ? ‘owningElement’ : ‘ownerNode’;
function showCSS() {
var stl = document.styleSheets;
// para cada elemento de estilo na página
for(var i = 0; i < stl.length; i++) {
alert(’Elemento ‘+i+’: ‘+stl[i][domNode].tagName+
‘\nRegras: ‘+stl[i][rulesName].length);
// para cada regra desse elemento
for(var g = 0; g < stl[i][rulesName].length; g++) {
// o seletor
var selector = stl[i][rulesName][g].selectorText;
// o cssText
var csstext = stl[i][rulesName][g].style.cssText;
// os replaces apenas colocam quebras de linha
// e garantem um ponto-e-vírgula no final
csstext = csstext.replace(/;?\s*$/,’;');
csstext = csstext.replace(/;\s*/g,’;\n’);
alert(selector+’ {\n’+csstext+’}');
}
}
}
Dessa forma, já pegamos os valores que queríamos e já podemos modificar as classes e regras em geral pelo atributo cssText (a declaração textual de todas as propriedades contidas em determinada regra). A sentença abaixo…
var obj = document.styleSheets[0][rulesName][0];
obj.style.backgroundColor = ‘#000′;
obj.style.color = ‘#FFF’;
E com isso repondemos à nossa primeira questão, certo?
Veja aqui um script mais completo para manipular os estilos na página.
Mas ainda restou a outra pergunta…
Como obter as regras CSS herdadas por determinado elemento?A real dificuldade aqui é que não basta ler os estilos inline e as classes CSS declarados na TAG, pois um elemento pode, além disso, herdar do seu elemento-pai ou de um ancestral qualquer, uma grande quantidade de regras que, apesar de não estarem explicitamente declaradas na TAG, incidem sobre a renderização visual do elemento.
Bem, essa resposta é mais simples mas, mais uma vez, formas diferentes para navegadores diferentes… O IE disponibiliza uma propriedade no nódulo DOM dos elementos, a currentStyle que engloba todos os estilos a incidir sobre o elemento. Já no Mozilla precisamos usar um método do objeto document.defaultView, o getComputedStyle(). Bem, para facilitar vamos construir uma funçãozinha crossbrowser, a getCurrentStyle(). Veja:
// a expressão "(VALOR || false)" tem o efeito
// de um try/catch. Se VALOR não existir,
// retorna false ao invés de dar erro.
if(elem.currentStyle || false)
return elem.currentStyle;
else
return (document.defaultView.getComputedStyle(elem, null) || false);
}
O elemento acima é um PRE apenas com a classe codigo definida e o id "codetest". Na classe codigo não há definição para a cor da fonte, mas ela é exibida com a cor "#333" por herança da da classe definida para a TAG BODY. Veja na prática:
O objeto de retorno da função acima pode ser enorme, pois inclui todas as propriedades específicas de cada navegador e, no caso do Mozilla, até funções. Por isso nosso exemplo foi direcionado a uma propriedade escolhida (color) e recomendo que você faça da mesma forma, para evitar dores de cabeça. Senão, teste o valor de cada item e ignore strings vazias e funções… isso vai melhorar um pouco a confusão.
Atenção!
Este tutorial leva em consideração apenas os navegadores da família Mozilla e o Internet Explorer.
Escrevi este texto em casa, sem pensar em publicar aqui no blog, por isso fui mesclando o texto com javascript para ter exemplos alive, mas as restrições do wordpress não permitem javascript. Além disso, os estilos declarados eram específicos para os testes pensados, enfim…
O resultado disso tudo é que a "versão completa desse post" está em uma página separada. Aqui temos apenas uma cópia sem correspondência com o JS ou CSS dessa página.
Clique aqui para ler o texto com exemplos
Abraço a todos, Cau Guanabara










Muito interessante! Quando tiver um tempinho vou fazer uns testes com isso.
Queria pedir uma coisa… coloca o título do post no TITLE das páginas do permalink… é chatão mandar adicionar no Delicious e ter que modificar o título por que tá escrito só “Pensamento Web - blog de Cau Guanabara”… seria muuuito melhor “Duas questões sobre javascript e CSS - Pensamento Web - blog de Cau Guanabara”.
Por Leonardo A. Souza em 2007-04-30 08:36:03, segunda
Leonardo, você está coberto de razão!
Não sabia como, mas inventei um jeito que deu certo. Ó o title lá em cima…
Valeu o toque!
Por Cau Guanabara em 2007-04-30 08:36:03, segunda
Grande Cau.
Ótimo tutorial sobre o assunto, que eu já conhecia mas nunca tinha tido vontade de pesquisar.
Merece ótima repercussão este tutorial.
Por Micox em 2007-04-30 08:36:03, segunda
Acessar o CSS com o Javascript torna-se mais fácil utilizando-se de frameworks como a Jquery, que permite usar seletores de CSS3, além de permitir um grande controle com suporte a maioria dos Browsers. Acho que vale a pena experimentar, depois de conhecê-la, o Javascript para mim nunca mais foi o mesmo.
Por Alexandre Magno em 2007-04-30 08:36:03, segunda
Você deve ter razão, Alexandre… é que eu sempre sofri de alergia a frameworks, achando que aprender uma ’sub-linguagem’ poderia confundir e atrapalhar o aprendizado da linguagem em si.
Talvez seja hora de perder preconceitos e conhecer mais a fundo alguns dos ditos frameworks…
Por Cau Guanabara em 2007-04-30 08:36:03, segunda