Meu layout tem altura de tela cheia, com o scroll acontecendo dentro do main e
não na janela:
<div className="flex h-screen overflow-hidden">
<AppSidebar />
<main className="flex-1 overflow-y-auto">{children}</main>
</div>
Isso dá uma sensação de aplicação, e quebra duas coisas que normalmente funcionam de graça.
Títulos param atrás do header
Clicar em um link de âncora rola o título até o topo do container, exatamente onde fica o header fixo de 4rem. O título some atrás dele.
scroll-margin-top resolve, e o valor precisa considerar a altura do header:
.prose h2,
.prose h3 {
scroll-margin-top: 5rem;
}
A propriedade vai no elemento de destino, não no container. Isso é contraintuitivo na primeira vez: você quer mexer no que rola, mas quem precisa do recuo é quem chega.
IntersectionObserver observa a janela por padrão
O segundo tropeço: para destacar a seção ativa em um índice lateral, o
IntersectionObserver precisa saber qual é o container de scroll. O padrão é o
viewport, e com o scroll no main nenhum título nunca entra ou sai de vista do
ponto de vista dele.
const observer = new IntersectionObserver(callback, {
root: document.querySelector("main"),
rootMargin: "-80px 0px -70% 0px",
});
Sem o root, o callback dispara uma vez no carregamento e nunca mais.