# CLS Fix — Cumulative Layout Shift

Meta: CLS < 0.1 (bom), < 0.25 (precisa melhorar), > 0.25 (ruim)

---

## Como identificar o culpado

No PageSpeed Insights, na seção "Diagnosticar problemas de desempenho":
- Abrir "Evitar grandes mudanças de layout" ou "Causas da troca de layout"
- O painel mostra o **elemento** e o **score de shift**
- Elemento mais comum: `div.hero-copy`, `h1`, `p` com fonte web

---

## Causa 1: FOUT — Flash of Unstyled Text (fontes)

**Sintoma**: PageSpeed aponta um parágrafo ou título como culpado do shift. A fonte web carrega depois do render inicial e muda o tamanho/spacing do texto, deslocando tudo abaixo.

**Solução A — `display=optional`** (recomendado para headings):
```html
<!-- ANTES (causa FOUT → CLS) -->
<link href="...family=Oswald&display=swap">

<!-- DEPOIS (sem swap = sem CLS) -->
<link href="...family=Oswald&display=optional">
```
O browser usa a fonte local se Oswald não carregar rápido o suficiente. **Não há troca visual.**

**Solução B — `@font-face` fallback com `size-adjust`** (elimina shift mesmo com `display=swap`):
```css
/* Fallback que imita as métricas da fonte alvo */
@font-face {
    font-family: 'Oswald Fallback';
    src: local('Arial Narrow Bold'), local('Impact'), local('Arial');
    font-weight: 700 800;
    size-adjust: 90%;        /* ajusta tamanho geral */
    ascent-override: 105%;   /* altura acima da baseline */
    descent-override: 20%;   /* profundidade abaixo */
    line-gap-override: 0%;
}

/* Usar como segundo valor na stack */
.heading { font-family: 'Oswald', 'Oswald Fallback', sans-serif; }
```

**Parâmetros de referência por fonte:**

| Fonte | size-adjust | ascent | descent | line-gap |
|-------|-------------|--------|---------|----------|
| Oswald | 90% | 105% | 20% | 0% |
| Montserrat | 95% | 96% | 22% | 0% |
| Fira Code | 98% | 90% | 22% | 0% |
| Raleway | 93% | 100% | 25% | 0% |

**Ferramenta para calcular**: https://screenspan.net/fallback

---

## Causa 2: Imagem sem dimensões explícitas

**Sintoma**: Imagem "empurra" o conteúdo abaixo quando carrega.

**Solução**: Sempre definir `width` e `height` no HTML:
```html
<!-- ANTES (CLS quando carrega) -->
<img src="mentor.jpg" class="mentor-photo">

<!-- DEPOIS (browser reserva o espaço antes) -->
<img src="mentor.jpg" class="mentor-photo" width="340" height="400">
```
O CSS pode redimensionar livremente — o `width`/`height` HTML define apenas o aspect ratio.

---

## Causa 3: GHL Full-Screen Fix JS rodando no render

**Sintoma**: CLS leve (~0.05-0.1) mesmo sem fontes problemáticas.

**Causa**: O JS que move `.oap-root` para o body roda durante/após o parse, antes do primeiro paint, causando um reflow visível.

**Solução — double `requestAnimationFrame`**:
```js
(function() {
    function applyFix() {
        var root = document.querySelector('.oap-root');
        if (!root) return;
        if (root.parentElement !== document.body) {
            var placeholder = document.createElement('div');
            placeholder.style.display = 'none';
            root.parentElement.insertBefore(placeholder, root);
            document.body.insertBefore(root, document.body.firstChild);
        }
        document.body.style.margin = '0';
        document.body.style.padding = '0';
        document.body.style.overflow = 'hidden auto';
        Array.prototype.forEach.call(document.body.children, function(el) {
            if (el !== root) el.style.display = 'none';
        });
    }
    // Se já está no body direto: rodar imediatamente (sem CLS)
    // Se está aninhado no GHL: adiar para depois do primeiro paint
    var root = document.querySelector('.oap-root');
    if (root && root.parentElement === document.body) {
        applyFix();
    } else {
        requestAnimationFrame(function() { requestAnimationFrame(applyFix); });
    }
})();
```

---

## Causa 4: `min-height: 100vh` em containers

**Sintoma**: Container expande após JS calcular altura real, deslocando rodapé.

**Solução**: Remover `min-height: 100vh` de containers que têm conteúdo dinâmico. Usar apenas em `body` ou `.root`.

---

## Checklist CLS

- [ ] Fontes web: `display=optional` para headings, `display=swap` apenas para body text com fallback calibrado
- [ ] `@font-face` fallback com `size-adjust` para cada fonte crítica
- [ ] Todas as imagens com `width` e `height` explícitos no HTML
- [ ] GHL Fix JS com double `requestAnimationFrame`
- [ ] Nenhum `min-height: 100vh` em containers filhos
- [ ] SVG de logo com `viewBox` definido (não expande ao carregar)
