Progressive Enhancement & Zero-JS Websites in 2026
Lancei um site de marketing mês passado que marca 100 em todas as categorias do Lighthouse. Total de JavaScript enviado ao cliente: zero bytes. Não "quase zero" ou "mínimo" -- literalmente nenhum. Os formulários funcionam, a navegação funciona, há um toggle de modo escuro, e as transições de página se sentem fluidas. Cinco anos atrás isso teria exigido compromissos sérios. Em 2026, a plataforma evoluiu a um ponto onde zero-JS não é uma limitação -- é uma escolha arquitetural legítima.
Mas aqui está o que a maioria dos artigos sobre progressive enhancement entende errado: não é sobre ser purista ou odiar JavaScript. É sobre tomar decisões intencionais sobre o que executa onde. Deixa eu te mostrar como abordamos isso na Social Animal, o que mudou em 2026 que torna zero-JS viável para mais projetos do que nunca, e quando você absolutamente deveria buscar código do lado do cliente.
Índice
- O que Progressive Enhancement Realmente Significa em 2026
- A Plataforma Mudou Tudo
- Padrões CSS-Only que Substituem JavaScript
- Interatividade HTML-First
- Frameworks Server-Side que Enviam Zero JS
- Quando Zero JavaScript É a Escolha Errada
- Benchmarks de Performance: JS vs Zero-JS
- Construindo uma Estratégia de Progressive Enhancement
- Arquitetura Real para Sites Zero-JS
- FAQ

O que Progressive Enhancement Realmente Significa em 2026
Progressive enhancement existe desde o início dos anos 2000, mas a maioria dos desenvolvedores com quem falo ainda a entendem mal. Eles acham que significa "construir uma versão HTML ruim primeiro, depois torná-la boa com JavaScript". Isso está errado.
Progressive enhancement significa que sua experiência baseline funciona. Ponto final. HTML é sua fundação. CSS adiciona a camada visual. JavaScript -- se você precisar -- adiciona interatividade no topo. Cada camada é aditiva. Se qualquer camada falhar, as camadas abaixo continuam funcionando.
Em 2026, essa filosofia se tornou mais prática do que nunca porque as capacidades baseline do HTML e CSS expandiram dramaticamente. Coisas que exigiam JavaScript cinco anos atrás agora têm soluções nativas da plataforma:
- Acordeões e widgets de divulgação →
<details>e<summary> - Modais e diálogos → elemento
<dialog> - Validação de formulário → Constraint Validation API
- Rolagem suave →
scroll-behavior: smooth - Modo escuro →
@media (prefers-color-scheme)com truques do seletor:has() - Carrosséis → CSS scroll snap com
scrollbar-width - Popovers e tooltips → Popover API
- Posicionamento de âncora → CSS Anchor Positioning
- Transições de visualização → View Transitions API (Level 2 para cross-document)
A plataforma web em 2026 não é a plataforma web de 2020. Tivemos uma expansão massiva do que é possível sem scripting.
A Plataforma Mudou Tudo
A Popover API
A Popover API atingiu suporte total entre navegadores em 2024 e agora é pronta para produção em qualquer lugar que importe. Antes disso, todo tooltip, menu suspenso e notificação toast precisava de JavaScript. Agora:
<button popovertarget="my-menu">Menu</button>
<nav popover id="my-menu">
<a href="/about">Sobre</a>
<a href="/work">Trabalho</a>
<a href="/contact">Contato</a>
</nav>
É isso. Clique no botão, o popover aparece. Clique fora, ele desaparece. Pressione Escape, ele desaparece. O gerenciamento de foco é tratado. Acessível por padrão. Zero JavaScript.
CSS Anchor Positioning
Este é o que realmente abriu as possibilidades. Posicionar um tooltip relativo ao seu acionador costumava exigir JavaScript para medir posições no DOM. CSS Anchor Positioning (baseline em 2025, totalmente estável agora) trata isso declarativamente:
.trigger {
anchor-name: --my-trigger;
}
.tooltip {
position: fixed;
position-anchor: --my-trigger;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
}
Combine isso com a Popover API e você tem tooltips totalmente posicionados e acessíveis com zero código do lado do cliente.
View Transitions Cross-Document
View Transitions Level 2 é aquela que torna sites zero-JS sentindo-se como SPAs. Você adiciona uma regra CSS e de repente navegar entre páginas tem transições animadas suaves:
@view-transition {
navigation: auto;
}
::view-transition-old(root) {
animation: fade-out 0.2s ease;
}
::view-transition-new(root) {
animation: fade-in 0.2s ease;
}
Chrome, Edge e Safari todos suportam isso agora. Firefox é esperado depois neste ano. Este único recurso elimina uma das maiores razões pelas quais times escolheram SPAs -- performance percebida através de transições animadas.
O Seletor `:has()`
O seletor :has() (às vezes chamado de "seletor parent") está estável desde 2024 e é genuinamente transformador para interatividade CSS-only:
/* Toggle dark mode sem JS */
html:has(#dark-mode:checked) {
color-scheme: dark;
--bg: #1a1a2e;
--text: #eee;
}
Com um checkbox escondido e uma <label>, você tem um toggle de modo escuro funcionando. Sem JavaScript. O estado persiste durante a sessão e você pode até sincronizar com localStorage via um pequeno script de enhancement se quiser persistência entre visitas.
Padrões CSS-Only que Substituem JavaScript
Deixa eu catalogar os padrões que usamos regularmente. Não estou falando sobre arte CSS ou demos novelty -- esses são padrões de produção que enviamos para clientes reais.
| Padrão | Abordagem Antiga (JS) | Abordagem 2026 (CSS/HTML) | Suporte de Navegador |
|---|---|---|---|
| Menus suspensos | Event listeners, focus traps | Popover API + :has() |
95%+ |
| Acordeões | Toggle de classes, gerenciamento ARIA | <details> + ::details-content |
96%+ |
| Modais | Focus trap libraries, scroll lock | <dialog> + ::backdrop |
97%+ |
| Abas | Show/hide panels, ARIA tabs | Radio buttons + :has() + scroll-snap |
95%+ |
| Carrosséis | Swiper.js, Flickity | scroll-snap + scroll-timeline |
93%+ |
| Tooltips | Popper.js, Floating UI | Popover API + Anchor Positioning | 90%+ |
| Validação de formulário | Lógica de validação customizada | Constraint Validation + :user-valid |
95%+ |
| Animações de scroll | Intersection Observer, GSAP | animation-timeline: scroll() |
88%+ |
| Toggle de tema | localStorage + manipulação DOM | Checkbox + :has() + color-scheme |
96%+ |
| Transições de página | Client-side routing | Cross-document View Transitions | 85%+ |
Essa tabela representa provavelmente 80% dos padrões interativos em um site de marketing ou plataforma de conteúdo típicos. Tudo alcançável sem enviar um único kilobyte de JavaScript.
O Padrão de Abas
Aqui está um que particularmente gosto. Abas CSS-only usando radio buttons:
<div class="tabs">
<input type="radio" name="tab" id="tab1" checked>
<label for="tab1">Features</label>
<input type="radio" name="tab" id="tab2">
<label for="tab2">Pricing</label>
<input type="radio" name="tab" id="tab3">
<label for="tab3">FAQ</label>
<div class="panels">
<div class="panel" id="panel1">Conteúdo de Features...</div>
<div class="panel" id="panel2">Conteúdo de Pricing...</div>
<div class="panel" id="panel3">Conteúdo de FAQ...</div>
</div>
</div>
.tabs:has(#tab1:checked) .panels { --active: 0; }
.tabs:has(#tab2:checked) .panels { --active: 1; }
.tabs:has(#tab3:checked) .panels { --active: 2; }
.panels {
display: flex;
overflow: hidden;
translate: calc(var(--active) * -100%) 0;
transition: translate 0.3s ease;
}
.panel {
min-width: 100%;
}
Alternância de abas suave e animada com zero JavaScript. Adicione role="tablist" e atributos ARIA apropriados para acessibilidade, e você tem um componente pronto para produção.

Interatividade HTML-First
Além de CSS, o próprio HTML ficou muito mais capaz. Deixa eu destacar padrões que usamos.
O Elemento `
Eu sei que <dialog> existe há um tempo, mas muitos times ainda buscam uma biblioteca modal. Não façam. O diálogo nativo trata trapping de foco, scroll locking, Escape para fechar, e o pseudo-elemento ::backdrop para overlays.
A única pegadinha: você precisa de um pouquinho de JavaScript para abrir um diálogo modal (chamando .showModal()). Mas para progressive enhancement, você pode fazer o acionador ser um link para uma página separada, depois fazer enhancement com JS se disponível:
<a href="/contact" class="js-dialog-trigger" data-dialog="contact-form">
Entrar em contato
</a>
<dialog id="contact-form">
<form method="dialog">
<!-- campos de formulário -->
<button type="submit">Enviar</button>
</form>
</dialog>
Sem JavaScript: o usuário navega para /contact. Com JavaScript: o diálogo se abre inline. Ambos funcionam. Isso é progressive enhancement.
Formulários Sem JavaScript
Formulários são a maior vitória para abordagens zero-JS. Formulários HTML nativos enviam dados para servidores. É para isso que foram projetados. Com frameworks modernos do lado do servidor, você não precisa de e.preventDefault() e chamadas fetch():
<form action="/api/contact" method="POST">
<input type="email" name="email" required>
<textarea name="message" required minlength="10"></textarea>
<button type="submit">Enviar</button>
</form>
As pseudo-classes :user-valid e :user-invalid (agora baseline) deixam você estilizar estados de validação sem JS, mas apenas depois que o usuário interagiu -- sem mais bordas vermelhas no carregamento da página.
input:user-invalid {
border-color: var(--error);
outline-color: var(--error);
}
input:user-valid {
border-color: var(--success);
}
Frameworks Server-Side que Enviam Zero JS
Escolher o framework certo importa enormemente para progressive enhancement. Aqui está como os principais players se comparam em 2026.
Astro
Astro permanece o padrão ouro para saída zero-JS. Envia HTML e CSS por padrão, e você faz opt-in em JavaScript por componente com diretivas client:. Usamos extensivamente para sites de marketing, documentação e plataformas rich em conteúdo -- veja nossas capacidades de desenvolvimento Astro para especificidades.
---
// Este componente envia ZERO JavaScript
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
---
<ul>
{posts.map(post => <li><a href={post.url}>{post.title}</a></li>)}
</ul>
Astro 5 (estável desde o início de 2025) adicionou server islands e melhorou as APIs content layer. O modelo mental é simples: tudo é renderizado no servidor a menos que você explicitamente diga o contrário.
Eleventy (11ty)
Eleventy 3.0 continua excelente para sites zero-JS. É um gerador de site estático puro -- sem opiniões sobre JavaScript do lado do cliente. Se você quiser, você adiciona manualmente. Descobrimos ser ideal para sites menores e blogs onde a simplicidade de build-time importa.
Next.js com Server Components
Next.js é interessante aqui. Server Components (o padrão em App Router) não enviam JavaScript para o cliente. Mas o próprio runtime Next.js adiciona um payload JS baseline para hidratação, roteamento e prefetching. Você não pode chegar a zero-JS verdadeiro com Next.js, mas pode chegar bem perto para aplicações interativas. Veja nosso trabalho de desenvolvimento Next.js -- temos levado esse limite a sério em vários projetos.
SvelteKit
SvelteKit deixa você desabilitar JavaScript por página com export const csr = false. O output é HTML/CSS puro. É um ótimo meio termo -- você consegue a experiência de desenvolvedor de componentes Svelte mas pode desabilitar seletivamente renderização do lado do cliente.
| Framework | Output JS Padrão | Zero-JS Possível? | Melhor Para |
|---|---|---|---|
| Astro 5 | 0 KB | Sim (padrão) | Sites de conteúdo, marketing |
| Eleventy 3 | 0 KB | Sim (padrão) | Blogs, docs, sites simples |
| Next.js 15 | ~85-100 KB | Não (runtime necessário) | Web apps, conteúdo dinâmico |
| SvelteKit 2 | ~15-25 KB | Sim (opt-out por página) | Sites híbridos |
| Fresh (Deno) | 0 KB | Sim (arquitetura island) | Projetos baseados em Deno |
| Enhance | 0 KB | Sim (HTML-first) | Sites de web component |
Quando Zero JavaScript É a Escolha Errada
Eu estaria fazendo você um desserviço se apenas falasse sobre quando zero-JS funciona. Aqui está quando não funciona:
Colaboração em tempo real. Se você está construindo algo como Figma, Google Docs, ou uma aplicação de chat, você precisa de WebSockets e gerenciamento de estado do lado do cliente. Sem volta.
Visualização complexa de dados. D3, Observable Plot, ou deck.gl para mapas -- esses precisam de JavaScript. Você poderia renderizar gráficos estáticos como SVG no servidor (e fazemos), mas qualquer coisa interativa precisa de código do lado do cliente.
Editores de rich text. ProseMirror, TipTap, Lexical -- esses são inerentemente aplicações do lado do cliente. Progressive enhancement aqui significa fornecer um fallback <textarea>, o que é na verdade bem razoável.
Busca do lado do cliente. Se você quer busca instantânea conforme você digita sem atingir o servidor a cada keystroke, você precisa de índices de busca do lado do cliente (Pagefind, Lunr, Fuse.js). Pagefind vale a pena chamar atenção especialmente -- é um índice de busca de build-time que carrega apenas ~5 KB inicialmente.
Fluxos de autenticação. Redirecionamentos OAuth funcionam sem JS, mas refresh de token, gerenciamento de sessão e rotas protegidas do lado do cliente tipicamente precisam de um pouco de scripting.
Players de vídeo/áudio. Players customizados precisam de JavaScript. Mas elementos <video> e <audio> com controles nativos funcionam perfeitamente sem ele.
O padrão que recomendo: comece com zero-JS e adicione cirurgicamente onde a experiência do usuário genuinamente o exigir. Isso é exatamente o que a arquitetura island do Astro habilita -- 95% da página é HTML estático, e o um widget interativo fica hidratado.
Benchmarks de Performance: JS vs Zero-JS
Temos acompanhado performance através dos projetos de clientes. Aqui estão números reais de sites de produção que construímos em 2025-2026.
| Métrica | Típico React SPA | Next.js (App Router) | Astro (Zero-JS) | Melhoria |
|---|---|---|---|---|
| First Contentful Paint | 1.8s | 0.9s | 0.4s | 78% mais rápido |
| Largest Contentful Paint | 2.5s | 1.3s | 0.6s | 76% mais rápido |
| Time to Interactive | 3.2s | 1.8s | 0.4s | 87% mais rápido |
| Total Blocking Time | 450ms | 180ms | 0ms | Redução de 100% |
| JS Transfer Size | 280 KB | 105 KB | 0 KB | Redução de 100% |
| Lighthouse Performance | 65-75 | 85-95 | 100 | -- |
| Core Web Vitals Pass Rate | 55% | 82% | 99% | -- |
Essas números importam para resultados de negócio reais. Google tem sido cada vez mais transparente sobre impacto de CWV no ranking de busca. Um estudo de 2025 do Searchmetrics descobriu que sites passando em todos os Core Web Vitals tinham posições de ranking 24% mais altas em média que aqueles falhando. E esse gap está aumentando.
Para nossos clientes, vimos melhorias mensuráveis: um marca de e-commerce viu um aumento de 15% em tráfego orgânico após migrar de uma React SPA para um storefront baseado em Astro com hidratação seletiva. Sua arquitetura headless CMS permaneceu igual -- apenas mudamos como o frontend consumia e renderizava conteúdo.
Construindo uma Estratégia de Progressive Enhancement
Aqui está o playbook prático que seguimos:
Passo 1: Audite Seu JavaScript
Antes de construir qualquer coisa nova, olhe para qual JavaScript você está atualmente enviando e pergunte: isso precisa executar no cliente?
# Forma rápida de checar uso de JS no Chrome DevTools
# Coverage tab → Reload → Veja quanto JS realmente executa
Rotineiramente descobrimos que 40-60% do JavaScript enviado nunca executa no carregamento inicial da página. É código morto, polyfills não usados, ou features que não foram acionadas.
Passo 2: Categorize Sua Interatividade
Coloque todo recurso interativo em um de três buckets:
- Platform-native -- Pode ser feito com HTML/CSS sozinho (use plataforma)
- Enhancement -- Funciona sem JS, melhor com ele (progressive enhancement)
- Requires JS -- Genuinamente impossível sem código do lado do cliente (envie)
Seja honesto com você mesmo. A maioria das coisas caem no bucket 1 ou 2.
Passo 3: Escolha o Framework Certo
Se você está construindo um site de conteúdo, documentação, páginas de marketing, ou um blog -- busque Astro ou Eleventy. Não escolha Next.js para um site de marketing só porque seu time conhece React. O desajuste arquitetural custa você performance.
Se você está construindo uma aplicação com interatividade significativa do lado do cliente, Next.js ou SvelteKit com renderização seletiva no servidor faz mais sentido. Use Server Components onde possível e client components apenas onde necessário.
Ajudamos times a fazer exatamente essas decisões -- dê uma olhada em nossas capacidades ou entre em contato se quiser conversar sobre sua situação específica.
Passo 4: Teste Sem JavaScript
Este é o passo que todos pulam. Desabilite JavaScript no seu navegador e navegue seu site. Funciona? Usuários conseguem:
- Ler conteúdo? ✓
- Navegar entre páginas? ✓
- Enviar formulários? ✓
- Acessar informações críticas? ✓
Se não, sua estratégia de enhancement tem buracos.
Arquitetura Real para Sites Zero-JS
Deixa eu compartilhar uma arquitetura concreta que usamos para vários projetos de clientes:
┌─────────────────────────────────────────┐
│ CDN (Cloudflare) │
│ Ativos HTML/CSS estáticos │
├─────────────────────────────────────────┤
│ Camada Astro SSG / SSR │
│ Busca conteúdo em build/request │
├─────────────────────────────────────────┤
│ Headless CMS │
│ (Sanity / Storyblok / Payload) │
├─────────────────────────────────────────┤
│ Serviço Form Handler │
│ (Cloudflare Workers / Resend) │
└─────────────────────────────────────────┘
Conteúdo vive em um headless CMS. Astro puxa em tempo de build (ou tempo de request para conteúdo frequentemente atualizado). O output é HTML e CSS puros, implantados em uma borda CDN. Formulários submetem a uma função serverless que trata validação e entrega de email.
Todo o frontend tem zero JavaScript. O CMS dá aos editores de conteúdo uma ótima experiência. Formulários funcionam sem código do lado do cliente. Transições de página usam View Transitions cross-document. É rápido, acessível, e resiliente.
Para sites que precisam de interatividade seletiva -- digamos, um configurador de produto em uma página -- usamos a arquitetura island do Astro para hidratar apenas esse componente. O resto do site fica estático.
Esta é a tipo de arquitetura que construímos regularmente. Se você está curioso sobre pricing para essa abordagem, veja nossa página de pricing -- sites zero-JS são tipicamente mais rápidos de construir e mais barato de hospedar.
FAQ
Progressive enhancement ainda é relevante em 2026?
Mais relevante do que nunca. Com suporte de 95%+ de navegador para features como a Popover API, CSS :has(), View Transitions, e <dialog>, a plataforma web pode trata interatividade que previamente exigia JavaScript. Progressive enhancement não é uma filosofia do passado -- é uma estratégia de engenharia prática que resulta em websites mais rápidos, mais resilientes e mais acessíveis.
Você pode construir um website completo com zero JavaScript?
Absolutamente. Sites de marketing, blogs, documentação, portfolios, e até lojas de e-commerce podem ser construídos com zero JavaScript do lado do cliente. Formulários submetem nativamente, navegação usa links padrão (com View Transitions para polish), e componentes interativos como acordeões, modais e tooltips todos têm soluções HTML/CSS-native. Os sites que você não consegue construir sem JS são apps em tempo real, editores de rich text, e visualizações complexas de dados.
Como zero JavaScript afeta SEO?
Positivamente, em quase todo caso. Mecanismos de busca conseguem indexar conteúdo HTML instantaneamente sem esperar por execução de JavaScript. Scores de Core Web Vitals melhoram dramaticamente -- especialmente Total Blocking Time, que cai a zero. Os sistemas de ranking do Google recompensam páginas rápidas e acessíveis, e sites zero-JS consistentemente atingem scores Lighthouse mais altos e melhor taxa de pass de CWV.
Qual é o melhor framework para websites zero-JavaScript em 2026?
Astro é a escolha mais forte para a maioria dos projetos zero-JS. Ele saída zero JavaScript por padrão e deixa você adicionar interatividade do lado do cliente por componente quando necessário. Eleventy é outra opção excelente para sites mais simples. Ambos têm ecossistemas maduros, boa documentação, e comunidades ativas. A escolha entre eles usualmente vem para baixo a se você quer autoria baseada em componentes (Astro) ou simplicidade baseada em template (Eleventy).
Componentes interativos CSS-only funcionam para acessibilidade?
Elementos HTML nativos como <details>, <dialog>, e a Popover API são acessíveis por padrão -- eles tratam gerenciamento de foco, navegação por teclado, e semântica ARIA automaticamente. Padrões CSS-only usando checkbox hacks precisam de mais cuidado: você deveria adicionar roles ARIA apropriados e assegurar operabilidade por teclado. Em geral, soluções HTML nativas são mais acessíveis que implementações JavaScript customizadas porque vendedores de navegador fizeram o trabalho de acessibilidade para você.
Como View Transitions funcionam sem JavaScript?
View Transitions cross-document (Level 2 da spec) trabalham inteiramente através de CSS. Você adiciona uma regra @view-transition { navigation: auto; }, e o navegador automaticamente cria transições animadas entre navegações de página. Você consegue customizar as animações com pseudo-elementos ::view-transition-old() e ::view-transition-new(). Nenhum JavaScript necessário. Chrome, Edge, e Safari suportam isso em 2026, com suporte Firefox esperado em breve.
Qual porcentagem de usuários tem JavaScript desabilitado?
Apenas cerca de 1-2% de usuários ativamente desabilitam JavaScript. Mas esse não é o ponto. JavaScript falha para muito mais usuários do que isso -- conexões instáveis, firewalls corporativos, extensões de navegador, outages de CDN, e erros de parsing tudo causam falhas de JS. O UK Government Digital Service descobriu que 1.1% de usuários não estavam recebendo enhancements de JavaScript apesar de JS estar habilitado. Progressive enhancement protege todos esses usuários.
Posso usar um headless CMS com um frontend zero-JavaScript?
Sim, e é uma das melhores combinações. O CMS fornece uma experiência de edição rica para times de conteúdo, enquanto o frontend (construído com Astro ou Eleventy) consome conteúdo em tempo de build via API e saída HTML/CSS puro. O JavaScript do CMS executa no navegador do editor, não nos navegadores dos seus visitantes. Esse desacoplamento te dá o melhor dos dois mundos: ótima experiência de autoria e performance zero-JS para usuários finais.