Telles Logo
Pular para o conteúdo
Ver todos os artigos
set 18, 2023
·
views
·
likes
·
6 min

CSSOM: O que é e como funciona?

Compreendendo o Modelo de Objeto CSS

Quando o browser lê seu CSS, ele não o armazena como texto — ele o processa numa estrutura de dados em memória chamada CSSOM. É essa estrutura que o JavaScript manipula quando você escreve element.style.color = 'red'. Entender o CSSOM é entender como o browser pensa sobre estilo.

O que é o CSSOM

O CSSOM (CSS Object Model) é o contraparte CSS do DOM. Assim como o DOM representa o HTML em forma de árvore de nós que o JavaScript pode ler e modificar, o CSSOM representa as regras CSS em uma estrutura hierárquica análoga.

Quando o browser encontra uma folha de estilo — seja via <link>, <style> ou element.style — ele faz o parse das regras e constrói o CSSOM. Cada regra vira um objeto com propriedades como selectorText, cssText e acesso individual às declarações.

A combinação de DOM + CSSOM gera a Render Tree: apenas os nós visíveis, já com seus estilos calculados. É sobre a Render Tree que o browser executa Layout, Paint e Composite.

🌐DOM

Árvore de nós gerada a partir do HTML. Representa a estrutura e o conteúdo da página.

🎨CSSOM

Árvore de regras gerada a partir do CSS. Representa os estilos calculados para cada seletor.

DOM + CSSOM → Render TreeLayoutPaintComposite

Inspecionando o CSSOM

Cada propriedade que você vê no DevTools em "Computed" vem do CSSOM calculado. O browser resolve herança, cascata e especificidade e entrega um valor final para cada propriedade de cada elemento.

HTML
<button class="cta">Clique aqui</button>
Computed Styles
background-colorrgb(203, 166, 247).cta
colorrgb(30, 30, 46).cta
padding8px 16px.cta
border-radius6px.cta
font-size16pxbody (herdado)
font-familysystem-ui:root (herdad…
cursorpointeruser-agent
Box Model
margin0
border0
padding8px 16px
content
88x36px
margin — espaço externo
Área transparente fora da borda. Separa o elemento dos vizinhos. Não herda background e não faz parte das dimensões do elemento em box-sizing: content-box.
const el = document.querySelector('.cta');
getComputedStyle(el).backgroundColor; // "rgb(203, 166, 247)"
el.style.backgroundColor; // "" (inline style, empty)

Dois conceitos importantes:

  • Computed styles (getComputedStyle(el)): o valor final resolvido, após cascata e herança. Sempre retorna um valor absoluto — nunca em ou %, sempre px ou rgb().
  • Inline styles (el.style): apenas os estilos aplicados diretamente no atributo style do elemento. Se o estilo vem de uma classe ou herança, el.style.property retorna string vazia.

Cada valor tem uma origem (source): pode vir de uma regra de classe, de herança de um ancestral, ou do stylesheet padrão do browser (user-agent). A origem e a especificidade determinam qual regra vence quando há conflito.

Manipulando o CSSOM com JavaScript

Existem três formas principais de alterar estilos via JavaScript, cada uma com tradeoffs diferentes:

Estilos inline — maior especificidade, afeta apenas este elemento.
Código
const box = document.querySelector('.box');
box.style.backgroundColor = '#cba6f7';
box.style.transform = 'scale(1.05)';
box.style.transition = 'all 0.3s ease';
Preview
const box = document.querySelector('.box');
box.style.backgroundColor = '#cba6f7';
box.style.transform = 'scale(1.05)';
box.style.transition = 'all 0.3s ease';

element.style — estilos inline, altíssima especificidade, afeta apenas aquele elemento. Bom para animações ou estilos calculados em runtime.

classList.toggle/add/remove — mantém a lógica de estilo no CSS, o JS só controla qual classe está ativa. É a abordagem mais limpa para estados (hover, active, open, disabled).

CSSStyleSheet.insertRule — insere regras diretamente no stylesheet. Útil quando você precisa aplicar estilos a muitos elementos de uma vez sem poluir o HTML com classes ou inline styles. É como o browser aplica @keyframes gerados dinamicamente.

Performance: reflow e repaint

Nem toda mudança CSS tem o mesmo custo. O browser tem um pipeline de renderização, e dependendo do que você muda, pode ser necessário recalcular tudo do zero ou apenas repintar alguns pixels.

  • Compositor apenas (GPU) — transform, opacity

    O browser não precisa recalcular layout nem repintar. A mudança acontece direto no compositor, na GPU. Custo praticamente zero. Use para animações.

  • Repaint — color, background-color, box-shadow

    O layout não muda (nenhum elemento se move ou muda de tamanho), mas o browser precisa repintar os pixels afetados. Custo médio.

  • Reflow (layout) — width, height, margin, padding, top, left

    O browser precisa recalcular a posição e o tamanho de todos os elementos afetados, depois repintar. Custo alto, especialmente em árvores grandes.

Prefira transform a top/left para animações

Animar top ou left dispara reflow a cada frame. Animar transform: translate() roda inteiramente na GPU sem tocar no layout. O resultado visual é o mesmo, mas o custo de performance é ordens de magnitude menor.

Outro padrão que causa problemas: ler e escrever estilos alternadamente no mesmo frame (layout thrashing). O browser é obrigado a recalcular o layout a cada leitura se houve uma escrita antes.

// Ruim — layout thrashing
box.style.width = box.offsetWidth + 10 + 'px'; // write → read → write
 
// Bom — agrupa leituras antes das escritas
const w = box.offsetWidth; // read
box.style.width = w + 10 + 'px'; // write

O CSSOM no Critical Rendering Path

O CSSOM é render-blocking: o browser não pode construir a Render Tree — e portanto não pode pintar nada — enquanto não terminar de baixar e processar todo o CSS. Por isso arquivos CSS pesados atrasam o First Contentful Paint.

O caminho completo:

  1. DOM — parse do HTML, construção da árvore de nós
  2. CSSOM — parse das folhas de estilo, resolução de cascata e herança
  3. Render Tree — combina DOM + CSSOM, inclui apenas nós visíveis
  4. Layout — calcula posição e tamanho de cada elemento
  5. Paint — rasteriza pixels em camadas
  6. Composite — une as camadas e envia para a tela

CSS inline (<style>) é processado mais rápido porque já está no HTML e não gera um request extra. CSS externo deve ser servido com cabeçalhos de cache adequados e, se possível, o CSS crítico (above-the-fold) deve ser inlined.

Resumo

🌳CSSOM é uma árvore

Assim como o DOM, o CSSOM representa o CSS em memória como uma estrutura hierárquica que o JavaScript pode ler e modificar.

🔍Computed vs Inline

getComputedStyle retorna o valor final resolvido (sempre absoluto). element.style retorna apenas estilos inline — vazio se o estilo vem de uma classe.

3 formas de manipular

element.style para runtime dinâmico, classList para estados, CSSStyleSheet.insertRule para regras programáticas em larga escala.

🚀transform > top/left

Animações com transform e opacity rodam no compositor (GPU) sem reflow. São sempre a melhor escolha para performance.

🔒CSS bloqueia renderização

O browser não pinta nada até processar todo o CSS. CSS crítico deve ser pequeno e servido rapidamente para um bom FCP.

🔄Evite layout thrashing

Não alterne leituras e escritas de layout no mesmo frame. Agrupe todas as leituras antes de fazer as escritas.

As minhas notas

Selecione um trecho e use Destacar no menu (somente neste aparelho).

Artigos relacionados