CSS Gap Decorations
Por muito tempo, quem trabalha com desenvolvimento web teve que recorrer a hacks com bordas e pseudo-elementos para estilizar os espaços (gaps) entre os itens de layouts como grid e flexbox. Hoje, com as CSS Gap Decorations totalmente suportadas no Chrome e no Edge a partir da versão 149, é possível estilizar esses espaços de forma muito mais simples e com bastante controle.
A equipe da plataforma web do Edge, na Microsoft, liderou o design e a padronização do recurso, e a implementação já está sendo lançada em todos os navegadores baseados em Chromium.
Para mais contexto, vale conferir uma prévia inicial das gap decorations, escrita por Patrick Brosset, e um mergulho completo sobre o lançamento estável, escrito por Javier Contreras Tenorio.
Este artigo apresenta o que mudou no recurso desde então.
Recapitulando as gap decorations
As gap decorations estendem a já conhecida propriedade CSS column-rule, que já funcionava em layout multi-coluna, e passam a funcionar também em layouts de grid e flexbox.
Além disso, agora também há suporte à propriedade row-rule, permitindo que as decorações apareçam nos dois eixos. E a sintaxe também foi estendida para oferecer muito mais controle sobre as decorações.
Patrick já fez um bom passo a passo do recurso, mas, desde então, algumas coisas mudaram, como renomeações de propriedades para deixar tudo mais claro, além de novas propriedades, definidas a partir do feedback recebido de desenvolvedores web durante os testes iniciais.
Aqui está um resumo das mudanças:
| Antiga | Nova | O que essa mudança significa |
|---|---|---|
row-rule-outset / column-rule-outset | row-rule-inset / column-rule-inset | ”Outset” virou “inset”, e agora essas propriedades recolhem as linhas para dentro a partir das bordas da decoração. |
Sem controle fino de onde row-rule-inset e column-rule-inset se aplicam | Novas propriedades longhand: row-rule-inset-cap, row-rule-inset-junction, row-rule-inset-start, row-rule-inset-end, e as equivalentes column-rule-inset-cap, column-rule-inset-junction, column-rule-inset-start, column-rule-inset-end | Agora é possível controlar as pontas externas (caps) e as interseções (junctions) de forma independente. Também dá para recolher o início e o fim das decorações de forma independente. |
gap-rule-paint-order | rule-overlap | Essa propriedade foi renomeada para maior clareza. Ela controla como as decorações se sobrepõem onde as linhas de linha e coluna se cruzam. |
| N/A | rule-visibility-items | Essa nova propriedade controla se as linhas aparecem ao lado de áreas vazias dentro de um container. |
Suporte dos navegadores
As gap decorations estão disponíveis no Chrome e no Edge a partir da versão 149, além de outros navegadores baseados em Chromium que correspondam a essas versões.
Outros motores de navegador têm se mostrado receptivos e engajados nos fóruns de padronização, então, com o tempo, esse recurso deve se tornar interoperável.
Para quem quiser usar o recurso agora, vale considerar:
- Se essas decorações forem tratadas como um progressive enhancement, ótimo! Basta começar a usar o recurso hoje mesmo, já que nada quebra em navegadores sem suporte.
- Se as gap decorations forem indispensáveis, há um polyfill em desenvolvimento para navegadores que ainda não têm suporte.
Usando as gap decorations
Chega de teoria: é hora de expandir a demonstração que Patrick usou em seu artigo. Novas seções serão adicionadas, usando os recursos mais recentes das gap decorations ao longo do caminho.


Vamos começar com uma marcação HTML mínima:
<body> <header> <h1>My personal site</h1> <p class="tagline">...</p> </header>
<nav> <ul> <li><a href="#home">Home</a></li> <!-- etc. --> </ul> </nav>
<section id="home" class="home"> <div class="greeting"> <p class="lead">...</p> </div> <div class="photo"> <img src="cat.jpg" alt="A sleeping cat."> </div> <aside class="now"> <h3>Currently</h3> <ul> <li>Lorem <span>— ipsum dolor sit amet</span></li> <!-- etc. --> </ul> </aside> <div class="note"> <p>...</p> </div> <div class="photo"> <img src="tree.jpg" alt="An old olive tree trunk."> </div> </section>
<section id="blog" class="blog"> <h2>Blog</h2> <div class="posts"> <article class="post"> <span class="date">June 2025</span> <h3>Lorem ipsum dolor</h3> <p>...</p> </article> <!-- rest of articles --> </div> </section>
<section id="about" class="about"> <h2>About</h2> <div class="bio"> <img class="avatar" src="bike.jpg" alt="A bicycle leaning against a post."> <div class="text"> <p>...</p> <!-- etc. --> </div> </div> </section>
<section id="links" class="links"> <h2>Elsewhere</h2> <ul> <li><a href="#">GitHub</a></li> <!-- etc. --> </ul> </section>
<footer> <p>© 2025 My personal site.</p> </footer></body>E aqui está o CSS inicial. A página é um grande grid, com linhas de linha (row rules) atuando como divisores de seção. A área de navegação é um layout flexbox, com linhas de coluna tracejadas.
body { display: grid; gap: 4rem; margin: 2rem; row-rule: 1rem solid #efefef, repeat(2, 2px solid #efefef);}
nav ul { display: flex; flex-wrap: wrap; gap: 2rem; column-rule: 2px dashed #666;}O restante do artigo constrói a partir daqui.
Passo 1: suportar qualquer número de seções com repeat(auto)
No CSS inicial, o elemento body usa repeat(2, 2px solid #efefef) porque o site de partida tinha três seções estáticas. Como novas seções estão sendo adicionadas, o ideal é que o site se adapte automaticamente caso mais seções sejam incluídas no futuro.
Por isso, o número fixo de repetições será trocado por um repetidor auto. Assim, a página pode crescer e as linhas divisórias de seção acompanham esse crescimento:
body { /* ... */ row-rule: 1rem solid #efefef, repeat(auto, 2px solid #efefef);}
Passo 2: decorar os espaços do flexbox na seção inicial (home)
Para a seção inicial (home), teremos um container flexbox com quebra de linha (wrap), contendo texto e imagens. O elemento com classe .home define o layout flexbox, e os diversos elementos dentro dele usam diferentes valores de flex-basis:
.home { display: flex; flex-wrap: wrap; gap: 3rem;}
.home > * { flex: 1 1 12.5rem;}
.home .greeting { flex-basis: 26.25rem;}
.home .note { flex-basis: 22.5rem;}Aqui está a seção home, sem decorações:

Agora, para adicionar um pouco da mágica das gap decorations, usaremos as propriedades row-rule e column-rule:
.home { /* ... */ row-rule: 2px solid #999; column-rule: 2px solid #999;}Aliás, como as linhas horizontais e verticais usam o mesmo valor, dá para condensá-las no novo shorthand rule e escrever uma única linha de código:
.home { /* ... */ rule: 2px solid #999;}O resultado é este:

Por padrão, as linhas de coluna ocupam toda a altura de cada linha do flexbox. Como há um gap de 3rem, as duas linhas do flexbox ficam separadas. O objetivo aqui é fazer as linhas de coluna se encontrarem com a linha de linha (row rule).
Para isso, será usada a propriedade column-rule-inset com o valor overlap-join. Esse valor une as linhas adjacentes nas junções, mantendo as pontas externas (os caps) niveladas em 0.
.home { /* ... */ column-rule-inset: overlap-join;}
Passo 3: decorar itens de grid que ocupam múltiplas colunas ou linhas na seção do blog
Para a seção Blog, será usado um grid, permitindo que posts específicos ocupem múltiplas colunas ou linhas para dar destaque.
.posts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3rem;}
.post.feature { grid-column: span 2; }
.post.tall { grid-row: span 2; }Veja como fica a seção sem decorações:

Assim como na seção home, vamos adicionar a mágica das gap decorations:
.posts { /* ... */ rule: 2px solid #999;}O que resulta nisto:

Como as linhas que aparecem ao lado de células vazias do grid não ficam boas visualmente, elas serão removidas com a nova propriedade rule-visibility-items:
.posts { /* ... */ rule-visibility-items: around;}Com esse valor, as gap decorations só serão desenhadas quando pelo menos um dos lados do gap tiver conteúdo, então o espaço entre duas células vazias na última linha fica limpo, em vez de exibir uma linha solta no vazio:

De forma parecida com o passo anterior, para deixar as junções entre as decorações desse grid mais organizadas, será usado novamente o valor overlap-join da propriedade rule-inset:
.posts { /* ... */ rule-inset: overlap-join;}E aqui está o resultado:

Passo 4: recolher decorações na seção Sobre (About)
Para a seção Sobre, a ideia é ter uma foto circular lado a lado com o texto, separadas por uma linha. Mas também será explorada a nova possibilidade de reduzir o tamanho das gap decorations.
Primeiro, um container flexbox posiciona a foto e o texto da bio lado a lado:
.bio { display: flex; align-items: center; gap: 2.5rem;}Isso gera o seguinte resultado, uma espécie de media card comum em diversos sites:

Agora, a gap decoration é aplicada:
.bio { /* ... */ column-rule: 2px solid #999;}O que resulta em:

Desta vez, porém, para dar um pouco mais de respiro, a propriedade column-rule-inset será usada para reduzir o tamanho da linha separadora:
.bio { /* ... */ column-rule-inset: 2.5rem;}E aqui está o resultado:

Passo 5: separar links
Para a seção Links, como há bastante itens, eles serão organizados em um grid.
.links ul { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem 2.5rem;}Assim:

Vamos adicionar gap decorations, desta vez com aparências diferentes para as linhas de linha e de coluna:
.links ul { /* ... */ row-rule: 1px solid #c9a96a; column-rule: 3px solid #6a707a;}
Observando com atenção, as linhas de coluna mais grossas aparecem atrás das linhas de linha mais finas. Para controlar isso e fazer as linhas de coluna aparecerem na frente, será usada a nova propriedade rule-overlap:
.links ul { /* ... */ rule-overlap: column-over-row;}Essa propriedade faz exatamente o que o nome sugere: permite escolher se as colunas devem ser pintadas sobre as linhas, ou as linhas sobre as colunas.
E o resultado é este:

Por fim, a intenção é deixar as linhas de coluna um pouco mais curtas que o grid, sem separá-las por linha. Para isso, entra em cena a propriedade column-rule-inset-cap, que controla as pontas das gap decorations que não são junções ou interseções:
.links ul { /* ... */ column-rule-inset-cap: 1.75rem;}E aqui está o resultado:

Passo 6: juntando tudo
E pronto: a página está finalizada. Confira o exemplo ao vivo e o código-fonte:

Saiba mais
Vale a pena experimentar as gap decorations na prática. A forma mais rápida é pelo playground interativo, mas também há muitas outras demonstrações. É só brincar com cada propriedade e ver os gaps reagirem em tempo real.
Outra boa forma de aprender é visitar a documentação do MDN (em desenvolvimento no momento da publicação deste artigo) para mais referências.
Agradecimentos
As gap decorations do CSS existem graças a um grupo de pessoas que se importa profundamente com a web, nas equipes do Edge, do Chrome e no CSS Working Group. Agradecimentos especiais a Javier Contreras Tenorio, Kevin Babbitt, Alison Maher, Ian Kilpatrick e Patrick Brosset.