Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
ComparaçãoIntermediáriocódigo testado

Sass vs Less vs CSS nativo: qual compila mais rápido

A mesma folha de 400 componentes escrita nas três abordagens, compilada na mesma máquina, com tempo e tamanho do CSS medidos.

Rodolfo Mori11 min de leitura

CSS nativo ganhou porque não há pré-processador para executar. Entre os dois compiladores, Dart Sass teve mediana de 223,775 ms e Less de 643,824 ms neste teste: Sass foi 2,88 vezes mais rápido no workload escolhido. Esse resultado não é ranking universal. Ele descreve 400 componentes gerados, versões fixadas, processos novos e uma Apple M4 Pro em 24 de agosto de 2026.

O ponto mais útil não é declarar vencedor. É publicar fonte, método, amostras e tamanhos para você reproduzir e decidir se a diferença importa no seu build.

O mesmo componente escrito nas três abordagens

Cada componente tem regra base, título BEM e hover. O CSS sem pré-processador é direto:

css
.component-1 {
  color: #6d28d9;
  padding: 1rem;
  border: 1px solid #d1d5db;
}
.component-1__title { font-weight: 700; }
.component-1:hover { transform: translateY(-2px); }

Sass usa variáveis, loop e nesting para gerar a mesma estrutura:

css
$brand: #6d28d9;
$border: #d1d5db;

@for $i from 1 through 400 {
  .component-#{$i} {
    color: $brand;
    padding: 1rem;
    border: 1px solid $border;
    &__title { font-weight: 700; }
    &:hover { transform: translateY(-2px); }
  }
}

Less usa variáveis, mixin recursivo e nesting:

css
@brand: #6d28d9;
@border: #d1d5db;

.generate(@i) when (@i > 0) {
  .generate(@i - 1);
  .component-@{i} {
    color: @brand;
    padding: 1rem;
    border: 1px solid @border;
    &__title { font-weight: 700; }
    &:hover { transform: translateY(-2px); }
  }
}
.generate(400);

As entradas não têm o mesmo tamanho: SCSS e Less descrevem um gerador; CSS nativo contém 400 expansões. A saída, porém, representa o mesmo conjunto de 1.200 seletores. O benchmark mede um caso em que pré-processadores oferecem geração programática de verdade, não apenas trocam a sintaxe de um arquivo.

Essa escolha favorece a pergunta “quanto custa gerar?”. Ela não mede tempo de autoria, facilidade de revisão ou um projeto típico. Uma base com poucos loops e muitos imports pode ter perfil diferente.

O banco de teste: 400 componentes gerados por script

O gerador versionado em examples/sass-less-css-benchmark/generate.mjs gravou três entradas. Para CSS, um loop JavaScript expandiu as regras antes da medição; esse tempo ficou fora do benchmark porque, num repositório real, o CSS já estaria versionado. O trecho central foi:

js
let css = '';
for (let i = 1; i <= 400; i += 1) {
  css += `.component-${i} {\n`;
  css += `  color: #6d28d9;\n`;
  css += `  padding: 1rem;\n`;
  css += `  border: 1px solid #d1d5db;\n}\n`;
  css += `.component-${i}__title {\n  font-weight: 700;\n}\n`;
  css += `.component-${i}:hover {\n  transform: translateY(-2px);\n}\n`;
}
writeFileSync('bench.css', css);
bench.scss: 241 bytes e 12 linhas bench.less: 278 bytes e 14 linhas bench.css: 73.676 bytes e 4.400 linhas

O ambiente foi registrado com comandos simples:

bash
node --version
npx --yes sass@1.103.1 --version
npx --yes --package less@4.9.0 lessc --version
uname -sm
sysctl -n machdep.cpu.brand_string
v26.3.0 1.103.1 compiled with dart2js 3.13.1 lessc 4.9.0 (Less Compiler) [JavaScript] Darwin arm64 Apple M4 Pro

Os pacotes já estavam no cache do npm. Antes de medir, o script executou uma compilação de aquecimento por ferramenta. Depois chamou diretamente cada binário, evitando que resolução do npx contaminasse a amostra.

Tempo de compilação medido: Sass, Less e nenhum

Foram 15 execuções por opção. A ordem girou entre três sequências para reduzir viés térmico ou de posição. Cada amostra abriu um processo novo com spawnSync; portanto, o número inclui startup da CLI e transformação. Para CSS, a tarefa foi copiar o arquivo para o destino, pois não existe compilação.

O núcleo do medidor:

js
const orders = [
  ['sass', 'less', 'css'],
  ['less', 'css', 'sass'],
  ['css', 'sass', 'less'],
];

for (let round = 0; round < 15; round += 1) {
  for (const name of orders[round % orders.length]) {
    const start = performance.now();
    jobs[name]();
    samples[name].push(performance.now() - start);
  }
}
opção mediana mínimo máximo interpretação
CSS, cópia 0,332 ms 0,294 ms 0,580 ms I/O, nenhuma transformação
Dart Sass 1.103.1 223,775 ms 216,549 ms 248,747 ms processo novo + loop + emissão
Less 4.9.0 643,824 ms 597,317 ms 738,449 ms processo novo + recursão + emissão

O recorte timings do JSON bruto preservado pelo script foi:

json
{
  "sass": { "medianMs": 223.775, "minMs": 216.549, "maxMs": 248.747 },
  "less": { "medianMs": 643.824, "minMs": 597.317, "maxMs": 738.449 },
  "css":  { "medianMs": 0.332, "minMs": 0.294, "maxMs": 0.580 }
}
643,824 ÷ 223,775 = 2,88; Sass foi 2,88× mais rápido que Less neste teste.

O resultado diverge dos números sugeridos no plano editorial anterior, que colocavam Less à frente. Foi exatamente por isso que a medição foi refeita. A versão atual, o desenho recursivo do Less e o hardware alteram o perfil. Números sem fonte executável envelhecem; método reproduzível continua útil.

Há quatro limites importantes. Primeiro, o Sass usa @for, enquanto Less usa recursão porque essa é uma forma idiomática de expressar a faixa na linguagem; o custo do algoritmo faz parte do caso, mas não representa toda folha Less. Segundo, cada amostra abre processo. Uma integração por API JavaScript ou um servidor persistente pode reduzir startup. Terceiro, não foram ativados sourcemaps, minificação nem plugins. Quarto, uma única máquina não descreve CI Linux, notebook Intel ou runner com CPU compartilhada.

Por isso a tabela não oferece intervalo de confiança sofisticado nem casas decimais como promessa. Os três dígitos apenas preservam a leitura do relógio. A variação interna já aparece em mínimo e máximo: Less oscilou mais de 140 ms, Sass cerca de 32 ms e a cópia menos de 0,3 ms na segunda rodada. Mediana foi escolhida porque resiste melhor a uma amostra isolada lenta.

Um estudo para decisão de migração deveria acrescentar pelo menos três workloads: o projeto completo, uma alteração em folha raiz e uma alteração em partial profundo no modo watch. Também deveria rodar no CI usado pela equipe. O microteste serve para verificar uma hipótese controlada, não para substituir o perfil do produto.

Tamanho do CSS gerado: bruto e depois do gzip

O script leu bytes do filesystem e aplicou gzip nível 9 em memória. Também contou quebras de linha:

js
const content = readFileSync(file);
result[name] = {
  bytes: statSync(file).size,
  gzip9Bytes: gzipSync(content, { level: 9 }).byteLength,
  lines: content.toString('utf8').split('\n').length - 1,
};
saída bytes brutos gzip -9 linhas seletores
Sass 74.075 3.661 4.799 1.200
Less 73.676 3.663 4.400 1.200
CSS nativo 73.676 3.663 4.400 1.200

Sass adicionou uma linha em branco entre os 400 componentes: 399 bytes e 399 linhas a mais, aumento bruto de 0,542%. O gzip absorveu a repetição e o arquivo Sass terminou dois bytes menor — variação irrelevante. Less e CSS tiveram o mesmo SHA-256, portanto foram byte a byte iguais. Sass teve outro hash somente pela formatação. Depois de executar a reprodução ao fim do artigo no mesmo shell, conferi os arquivos temporários com:

bash
(
  cd "$BENCH_WORK"
  wc -l -c sass.css less.css native.css
  shasum -a 256 sass.css less.css native.css
)
4799 74075 sass.css 4400 73676 less.css 4400 73676 native.css 13599 221427 total

e3ca73a93529ec08beca6cd5fa415f67d84a35d9f8a4d0e508e4beae60e79aad sass.css 063ad0d3c4b43fb280b2021bac6e4dddc0d9b16349f19349a720fc8da333ddcd less.css 063ad0d3c4b43fb280b2021bac6e4dddc0d9b16349f19349a720fc8da333ddcd native.css

Comparar bytes sem olhar a semântica seria enganoso. Os três publicaram os mesmos seletores e declarações; a diferença Sass era espaço em branco. Em produção, minificação anterior ao gzip provavelmente elimina até isso.

Equivalência foi conferida de duas formas. O hash provou identidade entre Less e CSS. Para Sass, um diff mostrou apenas linhas vazias entre o hover de um componente e a regra base do próximo. Não houve valor reformatado, seletor reordenado nem unidade convertida. Em benchmark de cores ou matemática, esse passo precisa ser mais rigoroso: saída parecida pode ter valores numericamente diferentes.

Tamanho do fonte também conta para revisão. SCSS com 241 bytes e Less com 278 bytes expressaram uma regra geradora que o CSS expandido levou 73.676 bytes para registrar. Isso não torna os primeiros automaticamente melhores; torna a fonte mais abstrata. Uma alteração de uma linha tem alcance muito maior, exigindo teste da saída. CSS explícito é volumoso, mas cada regra é local e pesquisável. A escolha troca concisão por transparência, além de trocar tempo de compilação.

O que só o pré-processador faz em 2026

O benchmark usa geração de 400 famílias. Sass e Less transformam uma entrada de poucas linhas em uma API CSS inteira sem script separado. Sass oferece maps, loops, funções, mixins e módulos com namespace. Less oferece mixins, guards, avaliação preguiçosa e mecanismos presentes em bases históricas.

O ganho é legítimo quando a coleção é fonte de verdade de um design system. Alterar $brand ou @brand recompila todos os componentes. Adicionar um item ao map pode gerar documentação e classes de forma consistente. O custo aparece quando a geração publica combinações que ninguém usa ou esconde seletores difíceis de depurar.

No Sass, maps e loops oferecem uma forma mais expressiva que um loop numérico fixo. No Less, o padrão recursivo testado representa código que ainda aparece em bibliotecas antigas. A diferença de velocidade não autoriza migrar uma base sem medir o custo de comportamento.

O que o CSS nativo tomou de volta: nesting, var() e color-mix()

O CSS entregue ao navegador já possui custom properties, nesting, cálculo fluido, funções de cor, layers, container queries e mais. Uma página que precisa somente agrupar um hover e trocar tema não precisa gerar linguagem intermediária:

css
:root { --brand: #6d28d9; }
[data-theme="dark"] { --brand: #a78bfa; }

.button {
  background: var(--brand);
  &:hover {
    background: color-mix(in srgb, var(--brand), black 15%);
  }
}

A cor permanece dinâmica no navegador; nenhuma recompilação é necessária para trocar data-theme.

Essa capacidade é diferente de gerar 400 seletores. CSS nativo substitui muitos usos cotidianos de Sass, não todos os fluxos de build. Pergunte se o valor precisa responder ao DOM ou se a folha precisa ser produzida a partir de dados conhecidos.

O custo escondido: watch e o tempo entre Ctrl+S e a tela

O benchmark mede processo novo, como um build isolado. Desenvolvimento costuma usar watch, que mantém estado e recompila só após mudança. Startup deixa de dominar; tamanho do grafo de dependências e granularidade da alteração ganham peso.

bash
sass --watch src/scss:public/css
less-watch-compiler src/less public/css

Esses comandos representam fluxos diferentes; o segundo depende de ferramenta adicional, não do lessc puro. Para medir experiência real, automatize uma edição idêntica, capture o horário do save e o momento em que o arquivo muda. Rode pelo menos 15 vezes, reporte mediana e piores casos e mantenha plugins do projeto. Não extrapole os 223,775 ms de processo novo para hot reload.

Um atraso de 400 ms pode incomodar em cada salvamento e ser irrelevante num build de CI de oito minutos. Antes de trocar ferramenta, encontre a fatia dominante no perfil total.

Ant Design e a razão pela qual Less não morreu

Ant Design 4 documenta variáveis Less e modifyVars para personalizar cor, raio e outros tokens. Produtos nessa versão possuem tema, loader e overrides acoplados à linguagem. Bootstrap 3 e sistemas internos antigos criam o mesmo efeito: Less continua porque remover exige comparar milhares de regras e estados.

Ant Design 5 não sustenta a tese de dependência eterna: a versão atual usa tokens e CSS-in-JS. O legado, porém, não migra sozinho quando a documentação muda. A pergunta correta é “quanto custa atualizar o produto e preservar o tema?”, não “qual compilador venceu 420 ms?”.

A aula de Less em projeto legado mostra modifyVars, divisão e erros atuais. Se a base está estável, manter Less com versão fixada pode ser decisão mais segura que converter por moda.

A tabela de decisão: qual escolher em cada cenário

cenário escolha inicial por quê o que medir
página pequena, navegadores modernos CSS nativo zero linguagem extra e valores em runtime compatibilidade e tamanho final
design system que gera famílias de tokens Sass maps, loops, funções e módulos regras geradas, watch e API pública
Ant Design 4 ou Less consolidado manter Less menor risco de regressão build, tema, cobertura visual
aplicação migrando de legado fatia piloto decisão depende de comportamento diff CSS, screenshots e esforço
build lento com Sass perfilar primeiro compilador pode não ser gargalo cold build, incremental e plugins
tema dinâmico CSS custom properties responde à cascata e ao DOM contraste, fallback e hidratação

Velocidade isolada não escolhe arquitetura. Sass foi mais rápido que Less neste loop, mas migrar milhares de linhas pode consumir meses e introduzir regressão. CSS evitou compilação, porém escrever manualmente uma escala gerada pode criar outra fonte de verdade. O problema concreto decide qual custo vale pagar.

Reproduzir a medição na sua máquina em cinco minutos

Na raiz blog/, fixe versões, gere as entradas dentro de um diretório temporário, aqueça cada comando e rode amostras alternadas. O npx resolve os pacotes antes de iniciar o medidor; bench.mjs chama sass e lessc diretamente pelo PATH injetado, então a resolução não entra nas 15 amostras.

bash
BENCH_WORK=$(mktemp -d)
node examples/sass-less-css-benchmark/generate.mjs "$BENCH_WORK"
npx --yes --package sass@1.103.1 --package less@4.9.0 -- \
  node examples/sass-less-css-benchmark/bench.mjs "$BENCH_WORK" 15 >/dev/null
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));for(const k of ["sass","less","css"]){const t=r.timings[k],a=r.artifacts[k];console.log(`${k}: mediana ${t.medianMs} ms | ${a.bytes} bytes | gzip ${a.gzip9Bytes} | ${a.selectors} seletores | ${a.sha256}`)}' \
  "$BENCH_WORK/benchmark.json"
sass: mediana 223.775 ms | 74075 bytes | gzip 3661 | 1200 seletores | e3ca73a93529ec08beca6cd5fa415f67d84a35d9f8a4d0e508e4beae60e79aad less: mediana 643.824 ms | 73676 bytes | gzip 3663 | 1200 seletores | 063ad0d3c4b43fb280b2021bac6e4dddc0d9b16349f19349a720fc8da333ddcd css: mediana 0.332 ms | 73676 bytes | gzip 3663 | 1200 seletores | 063ad0d3c4b43fb280b2021bac6e4dddc0d9b16349f19349a720fc8da333ddcd

Além do resumo acima, o script grava benchmark.json, sass.css, less.css e native.css no diretório temporário. O JSON conserva máquina, versões e as 15 amostras de cada opção para a auditoria não depender apenas da mediana.

Depois mude uma variável de cada fonte e confirme que os 1.200 seletores continuam equivalentes. Acrescente o workload do seu projeto: imports, mapas, plugins e sourcemaps. Publique resultados que possam ser contestados e repetidos.

Guarde o script junto do resultado e imprima versões dentro da própria execução. Um JSON sem commit do gerador não permite saber se “400 componentes” continuou significando a mesma coisa. Se atualizar Sass ou Less, rode novamente em vez de editar somente a versão no texto. Mudanças de runtime e do sistema operacional também merecem nova linha de histórico.

Ao comunicar o resultado para o time, separe fato e decisão. Fato: neste teste, Sass teve mediana 223,775 ms e Less 643,824 ms. Inferência: a recursão e o startup contribuíram para a diferença. Decisão possível: não fazer nada, porque o build real é aceitável; otimizar o loop; ou testar uma migração. Essa separação impede que um número verdadeiro sustente uma recomendação que ele sozinho não prova.

Para decidir além do cronômetro, use o guia completo de Sass e compare o que a plataforma já resolve. O benchmark é uma evidência localizada; a escolha correta continua sendo a que deixa o fluxo explicável, reproduzível e seguro para a base real.

  • sass
  • less
  • css
  • benchmark
  • comparação
  • build

Perguntas frequentes

Sass é sempre mais rápido que Less?
Não. Neste workload, nesta máquina, a mediana do Sass foi menor. Fonte, plugins, versão, cache e modo watch podem inverter ou reduzir a diferença.
CSS nativo tem tempo de compilação zero?
Ele não exige pré-processamento. O benchmark mediu 0,332 ms de mediana para copiar o arquivo, custo de I/O, não de transformar a linguagem.
O menor tempo deve decidir a ferramenta?
Raramente sozinho. Compatibilidade do legado, API de tokens, clareza da saída e custo de migração normalmente pesam mais que centenas de ms.
Os três arquivos geraram o mesmo CSS?
Less e CSS nativo ficaram byte a byte iguais. Sass acrescentou linhas em branco entre componentes, mas os seletores e declarações foram equivalentes.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Apple M4 Pro (Darwin arm64), Node 26.3.0, Dart Sass 1.103.1, Less 4.9.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. Sass — Command-Line Interface — sass-lang.com
  2. Less — Using Less.js — lesscss.org
  3. MDN — CSS nesting — developer.mozilla.org
  4. Node.js — Performance measurement APIs — nodejs.org

Continue por aqui