Assinar
Voltar
Frontend

CSS gap decorations: a linha entre as colunas agora é propriedade, não gambiarra

row-rule e column-rule chegaram ao grid e ao flexbox no Chrome 149. O detalhe que autoriza usar hoje, mesmo sem Firefox e Safari: o fallback é a ausência da linha, não layout quebrado.

</>

Desenhar uma linha entre os cards de um grid é um daqueles problemas de CSS que parecem triviais e não são. Existem três soluções conhecidas, e as três são ruins.

A primeira é colocar border nos filhos. Funciona até você reparar que a borda ocupa espaço, soma com o gap e aparece duplicada onde dois itens se encontram. A segunda é pseudo-elemento posicionado de forma absoluta em cada item. Funciona até a grade quebrar linha em outro ponto e as linhas ficarem penduradas no vazio. A terceira é criar colunas vazias no próprio grid, só para pintar. Funciona e transforma o seu grid-template-columns em algo que ninguém mais consegue ler.

O CSS resolveu isso de vez com gap decorations, disponível em Chrome e Edge a partir da versão 149. A ideia é curta: o espaço entre os itens deixa de ser vazio inerte e passa a aceitar decoração própria.

A propriedade que já existia e ninguém podia usar

Quem escreve CSS há tempo suficiente conhece column-rule. Ela desenha a linha entre colunas em layout multi-column, aquele do column-count, e sempre foi a prova de que o conceito funcionava. O problema é que ela existia só ali, num modelo de layout que quase ninguém usa.

A mudança é que column-rule passou a valer em grid e flexbox. E ganhou o par que faltava, row-rule, para os espaços horizontais. A sintaxe é a mesma de sempre, largura, estilo e cor:

.posts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3rem;
  column-rule: 2px solid #999;
  row-rule: 1px dashed #ccc;
}

Existem as longhand correspondentes, column-rule-width, column-rule-style, column-rule-color e as versões com row-. E existe rule, atalho que aplica o mesmo valor nos dois eixos.

O detalhe que autoriza usar isso hoje

Suporte só em Chromium costuma ser motivo para adiar. Aqui, não.

A razão é a semântica da propriedade: a decoração é pintada dentro do gap, um espaço que já foi reservado pelo layout. Ela não empurra nada, não soma largura, não participa do cálculo de tamanho. É pintura em cima de espaço que já existia.

A consequência prática é que o fallback de gap decorations é a ausência dela. No Firefox e no Safari de hoje, a declaração é ignorada e o usuário vê o mesmo grid, com o mesmo espaçamento, sem as linhas. Nada desalinha, nada quebra, nada precisa de ajuste.

Compare com desenhar a mesma linha usando border: ali o fallback não é “sem linha”, é “layout com 2px a mais em cada item”. Por isso a técnica antiga exigia compensar, e esta não exige nada.

É a definição de progressive enhancement, e é raro uma feature nova de CSS chegar com essa propriedade. Se quiser ser explícito, o teste de suporte é direto:

@supports (row-rule: 1px solid red) {
  .posts { row-rule: 1px solid #ccc; }
}

Padrões com repeat()

As propriedades aceitam repeat(), o que permite valores diferentes para gaps sucessivos em vez de um valor único para todos:

.sudoku {
  row-rule-width: repeat(2, 1px), 4px;
}

O padrão cicla ao longo dos espaços: duas linhas finas, uma grossa, duas finas, uma grossa. É exatamente o desenho de uma grade de sudoku, e antes disso exigia seletor :nth-child calculado à mão em cima do número de colunas, que quebrava quando o número mudava no breakpoint seguinte.

Onde a linha começa e termina

Uma linha que vai de ponta a ponta do gap raramente é o que o designer pediu. Normalmente ela precisa respirar nas extremidades, ou encostar exatamente no cruzamento.

É o papel das propriedades de inset. Elas encurtam ou estendem a decoração, e separam dois lugares diferentes: cap, que é a ponta externa da linha, e junction, que é o encontro com uma decoração do outro eixo. Existem as longhand por direção, do tipo column-rule-inset-cap-start e row-rule-inset-junction-end, aceitando comprimento, porcentagem ou a palavra-chave overlap-join.

overlap-join resolve sozinha o problema clássico do cruzamento em L mal fechado: ela estende a decoração para dentro da junção pela metade da largura do gap que cruza mais metade da espessura da própria decoração, que é a conta certa para o encontro ficar limpo.

.links ul {
  row-rule: 1px solid #c9a96a;
  column-rule: 3px solid #6a707a;
  column-rule-inset-cap: 1.75rem;
}

O caso da última linha incompleta

Aqui está a armadilha visual mais comum de grid, e ela tem tratamento próprio.

Um grid de três colunas com sete itens termina com uma linha de um item só e dois espaços vazios. Se a decoração de coluna for pintada em todo gap, ela continua descendo ao lado do nada, e o resultado parece bug.

As propriedades column-rule-visibility-items e row-rule-visibility-items decidem isso, com os valores normal, all, around e between. Em vez de pintar todo o espaço disponível, você diz para pintar só onde há item de fato dos dois lados. É a diferença entre a grade parecer desenhada e parecer sobrando.

Na mesma linha de controle fino, column-rule-break e row-rule-break definem o que acontece no cruzamento, com normal, none e intersection. E a ordem de pintura de quem cruza quem é decidida por rule-overlap.

Cuidado com tutorial de um ano atrás

Este aviso economiza uma tarde. A feature passou por um período de teste em Chrome e Edge 139, atrás da flag de recursos experimentais, e os nomes mudaram desde então.

O que era outset virou inset. O que era gap-rule-paint-order virou rule-overlap. As propriedades de visibility-items não existiam. Ou seja: material escrito naquela janela usa nomes que hoje não existem, e o navegador ignora sem reclamar, porque propriedade desconhecida em CSS não gera erro. Se você copiou algo de um post antigo e nada aconteceu, é provavelmente isto.

Vale lembrar que animação também entrou depois. Largura, cor e insets são animáveis, então transição de decoração no :hover do container funciona.

Quando usar

Use em separador visual: lista de links no rodapé, grade de artigos, tabela de preços, qualquer lugar onde hoje existe um pseudo-elemento fazendo o trabalho. O código encolhe e o layout deixa de depender de compensação.

Não use quando a linha for informação, e não decoração. Se o traço separa dados que precisam ser lidos como separados por leitor de tela, o elemento certo continua sendo estrutura, não pintura no gap. Vale o mesmo raciocínio que se aplica a View Transitions API: recurso visual novo que degrada bem é convite para usar cedo, desde que a informação não more nele.

Perguntas frequentes

Funciona em flexbox com quebra de linha?

Funciona. Em flex-wrap: wrap, column-rule pinta entre itens da mesma linha e row-rule pinta entre as linhas. É justamente o cenário que o pseudo-elemento nunca resolveu direito, porque a posição da quebra depende da largura da tela.

A linha entra no cálculo de tamanho do grid?

Não. A decoração é pintada dentro do gap já reservado. Se a decoração for mais larga que o gap, ela transborda para cima dos itens em vez de empurrar a grade.

Existe polyfill?

Há um em desenvolvimento, sem versão estável. Como o comportamento sem suporte é apenas não desenhar a linha, na maioria dos casos o polyfill não se paga.

E Firefox e Safari?

A padronização segue no grupo de trabalho de CSS e a implementação está no Chromium. Não há data anunciada para os outros motores, o que reforça tratar isso como enfeite opcional e não como parte estrutural do layout.

Fontes

RP

Ricardo Perdigão

https://rickytech.com.br

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *