← Biblioteca componentes/rodape/cortina-fixa/ficha.md CódigoTela cheia
rodape/cortina-fixa

Rodapé cortina de tela cheia

🟢 estavel complexidade baixa prefixo curt- rodape footer 100vh cortina parallax fixo revelacao tela-cheia sem-js sem javascript

Incluir · as linhas que se colam num site novo, depois do core (CLAUDE.md §10)

<link rel="stylesheet" href="componentes/rodape/cortina-fixa/estilo.css">

markup.html · 73 linhas · 2,9 KB

<!-- ==========================================================================
     RODAPÉ CORTINA — painel de tela cheia parado atrás da página
     Prefixo: curt-
     Requer: core (tokens, base, motion.css) + estilo.css
     SEM JavaScript. O efeito inteiro são três regras de CSS.

     ATENÇÃO — ESTE COMPONENTE PEDE UMA COISA DA PÁGINA.
     Todo o conteúdo acima do rodapé tem de estar dentro de um invólucro:

         <body>
           <div class="curt-pagina">
             ... hero, todas as dobras, tudo ...
           </div>

           <div class="curt-espaco" aria-hidden="true"></div>
           <footer class="sec-dark curt"> ... </footer>
         </body>

     É esse invólucro que levanta a página acima do painel. Sem ele o painel
     cobre o site inteiro — falha barulhenta de propósito: erro silencioso
     aqui seria pior que erro na cara.

     COMO FUNCIONA. O painel é position:fixed com z-index:0 — está lá desde o
     primeiro pixel de rolagem, atrás de tudo. O .curt-pagina (z-index:1) e
     seus fundos opacos o cobrem. O .curt-espaco é um vazio de 100vh no fim
     do fluxo, FORA do invólucro: é ele que permite rolar além da última
     dobra, e é nesse trecho que o painel aparece.

     Por isso parece parallax e não é: o painel NÃO se move em momento
     nenhum. Quem se move é a página, por cima dele. Medido na referência —
     transform:none em cinco posições de rolagem diferentes.

     SEM data-rv AQUI. O painel está na tela desde o carregamento, só que
     coberto: um IntersectionObserver dispararia no primeiro segundo e a
     entrada seria gasta antes de alguém ver. A revelação é a cortina.
     ========================================================================== -->

<div class="curt-espaco" aria-hidden="true"></div>

<footer class="sec-dark curt">
  <div class="wrap curt-grid">

    <div class="curt-topo">
      <nav class="curt-nav" aria-label="Rodapé">
        <a class="curt-link" href="#inicio">Início</a>
        <a class="curt-link" href="#sobre">Quem somos</a>
        <a class="curt-link" href="#solucoes">Soluções</a>
        <a class="curt-link" href="#socios">Sócios</a>
        <a class="curt-link" href="#contato">Contato</a>
      </nav>

      <a class="btn btn-ghost curt-cta" href="#contato">Falar com um assessor</a>
    </div>

    <span class="curt-linha"></span>

    <!-- A marca ocupa a faixa do meio e é o que faz a cortina valer a tela
         inteira. Texto e não imagem: escala sozinha e não pede asset. Marca
         com logotipo desenhado troca por
         <img class="curt-marca-img" src="..." alt="Nome da marca"> -->
    <p class="curt-marca">Liberta Wealth</p>

    <span class="curt-linha"></span>

    <div class="curt-base">
      <p class="curt-legal">Copyright © 2026</p>
      <a class="curt-credito" href="#creditos">
        Desenvolvido por <span class="curt-credito-marca">Estúdio</span>
      </a>
    </div>

  </div>
</footer>

estilo.css · 168 linhas · 6,6 KB

/* ==========================================================================
   RODAPÉ CORTINA — prefixo curt-
   Painel de tela cheia que fica parado atrás da página e é descoberto
   quando a última dobra sobe.

   Tokens usados:
     --bg --fg --fg-2      painel e tipografia, do escopo de tom da seção
     --rule-2              filetes (via --curt-linha, para o projeto ajustar)
     --display --sans      marca e texto
     --ease                curva do projeto

   Sem JavaScript e sem @keyframes: o efeito são três regras — o painel
   fixed atrás, o invólucro da página por cima e um vazio de 100vh no fim
   do fluxo.
   ========================================================================== */

.curt{
  /* Cor dos dois filetes. Sai de --rule-2 (a "linha divisória forte" do
     contrato) para o tema decidir o quanto ela aparece. A referência usa um
     cinza-sage quase branco, muito mais forte que o nosso padrão em fundo
     escuro; projeto que quiser aquele peso sobe esta variável — não a
     regra. */
  --curt-linha:var(--rule-2);

  /* Corpo da marca do meio. É ela que faz a cortina valer uma tela inteira:
     abaixo de ~90px em desktop o painel fica com cara de sobra de página.

     O valor é calibrado para um nome de ~14 caracteres encher a coluna numa
     linha só, que é o que a referência faz. Nome mais curto sobra espaço,
     nome mais longo cai para duas linhas — as duas coisas continuam de pé,
     mas o ajuste fino é aqui, e é o único que a troca de marca pede. */
  --curt-marca:clamp(34px,9.6vw,140px);

  /* O PAINEL.
     fixed + inset:0 = ele ocupa a viewport inteira e NUNCA se move. Toda a
     sensação de parallax vem daí: quem desliza é a página.

     z-index:0 e não -1. A tentação é usar negativo para o painel ficar
     atrás sem pedir nada à página — e não funciona: elemento com z-index
     negativo pinta ABAIXO da caixa do <body>, e a caixa do body cobre a
     tela inteira. O painel some atrás dela e, pior, os links do rodapé
     ficam inclicáveis, porque o body ganha o teste de acerto no lugar
     deles. Medido com elementFromPoint, não deduzido. */
  position:fixed;
  inset:0;
  z-index:0;

  display:flex;
  align-items:stretch;
  background:var(--bg);
  /* O respiro do painel é vertical e vem daqui; o lateral é do .wrap, que
     continua sendo a única regra da coluna (contrato §4). */
  padding-block:clamp(28px,6vh,80px);
}

/* O INVÓLUCRO DA PÁGINA.
   Envolve tudo o que vem antes do rodapé e é o que levanta a página acima
   do painel. É a única coisa que este componente pede da página, e não há
   como evitá-la: CSS não seleciona irmãos anteriores, então o componente
   não consegue erguer as dobras por conta própria.

   z-index:1 basta — o painel é 0. Como é position:relative (e não
   transform ou filter), um menu fixo lá dentro continua preso à viewport. */
.curt-pagina{position:relative;z-index:1}

/* O VAZIO.
   100vh de nada no fim do fluxo. É ele que dá à página o trecho de rolagem
   em que não há mais dobra por cima — e é nesse trecho que o painel aparece.
   Sem ele, a última dobra termina junto com o documento e a cortina nunca
   chega a ser vista.

   pointer-events:none é obrigatório, não é enfeite: o espaçador é um bloco
   transparente por cima do painel, e sem isto ele engoliria todo clique nos
   links do rodapé. */
.curt-espaco{
  height:100vh;
  pointer-events:none;
}

/* Cinco faixas repartindo a altura por igual — é o que a referência faz, e
   é o que mantém o painel legível em qualquer altura de tela sem clamp
   solto para cada vão. */
.curt-grid{
  display:flex;flex-direction:column;
  justify-content:space-between;
  width:100%;
  min-height:0;
}

/* ---------------------------------------------------------------- topo */
.curt-topo{
  display:flex;align-items:center;justify-content:space-between;
  gap:clamp(20px,4vw,48px);
  flex-wrap:wrap;
}

.curt-nav{display:flex;flex-wrap:wrap;gap:clamp(16px,2.4vw,32px)}

.curt-link{
  font-size:16px;line-height:1.5;
  color:var(--fg-2);
  transition:color .3s var(--ease);
}
.curt-link:hover,
.curt-link:focus-visible{color:var(--fg)}

/* O CTA é a primitiva .btn do core, sem retoque de forma. O único ajuste é
   impedir que ele encolha quando a fila de links cresce. */
.curt-cta{flex:0 0 auto}

/* ---------------------------------------------------------------- filetes */
.curt-linha{display:block;height:1px;background:var(--curt-linha)}

/* ---------------------------------------------------------------- marca */
/* Texto e não imagem: escala sozinha, não pede asset e não some se o SVG
   do cliente ainda não chegou. Tracking negativo porque corpo grande em
   display engorda; entrelinha abaixo de 1 porque a caixa é uma linha só e
   o resto vira ar morto no meio do painel. */
.curt-marca{
  font-family:var(--display);font-weight:700;
  font-size:var(--curt-marca);
  line-height:.86;letter-spacing:-.03em;
  text-transform:uppercase;
  color:var(--fg);
  /* Nome longo em tela estreita não pode empurrar a página para o lado. */
  overflow-wrap:anywhere;
}

/* Alternativa com logotipo desenhado. Mesma faixa, mesma altura óptica. */
.curt-marca-img{width:100%;max-width:none;height:auto}

/* ---------------------------------------------------------------- base */
.curt-base{
  display:flex;align-items:center;justify-content:space-between;
  gap:clamp(12px,3vw,32px);
  flex-wrap:wrap;
}

.curt-legal,
.curt-credito{font-size:16px;line-height:1.5;color:var(--fg-2)}

.curt-credito{transition:color .3s var(--ease)}
.curt-credito:hover,
.curt-credito:focus-visible{color:var(--fg)}
.curt-credito-marca{color:var(--fg)}

/* ---------------------------------------------------------------- movimento reduzido */
/* Não há o que desligar: o painel não anima e não se desloca em nenhum
   momento — ele fica parado e a página passa por cima. O que muda no
   hover é cor, que não é movimento. A regra existe para o próximo a
   passar por aqui não procurar o bloco que falta. */

/* ---------------------------------------------------------------- mobile */
@media(max-width:760px){
  .curt-topo{flex-direction:column;align-items:flex-start;gap:20px}
  .curt-nav{gap:14px 20px}
  /* Em tela de toque a fila de links é o conteúdo do rodapé; o botão
     ganhando a largura toda deixa de ser um alvo de 182px no canto. */
  .curt-cta{width:100%}
  .curt-base{flex-direction:column;align-items:flex-start;gap:10px}
}

@media(max-width:520px){
  .curt{--curt-marca:clamp(34px,16vw,64px)}
  /* Painel de 100vh num aparelho baixo fica apertado: menos ar em cima e
     embaixo é o que impede o filete de baixo de encostar no de cima. */
  .curt{padding-block:24px}
}

Um painel de 100vh que está atrás da página desde o primeiro pixel de rolagem, parado, coberto pelas dobras. Quando a última dobra sobe, ele é descoberto — e como nunca se move, a sensação é de parallax sem que exista parallax nenhum. Dentro dele, cinco faixas repartindo a tela por igual: links e chamada em cima, filete, a marca em corpo gigante no meio, filete, e a linha legal embaixo.

Resolve o fim de página quando o rodapé não é sobra de layout e sim uma dobra com peso próprio. O rodapé comum entra rolando junto com o resto e some da memória; este chega como uma virada — a página se abre e revela algo que estava ali o tempo todo.

Sem JavaScript. O efeito são três regras de CSS.


Quando usar

Quando não usar


Padrão editorial

Slot Regra
Links 4 a 6, uma linha só. É a navegação de repescagem, não o mapa do site.
Chamada Um botão, um verbo. É o último pedido da página.
Marca O nome, escrito normal — a caixa alta é do CSS. Alvo: encher a largura da coluna em uma linha.
Linha legal Copyright de um lado, crédito do outro. Nada mais.

O que mantém o painel de pé é o vazio. Cinco faixas em 100vh deixam muito ar entre elas de propósito: é esse ar que faz a dobra parecer o fim de alguma coisa. Acrescentar uma sexta faixa — endereço, newsletter, selo — fecha o espaço e o rodapé volta a ser um rodapé.

Especificação dos assets


Como usar

<link rel="stylesheet" href="componentes/rodape/cortina-fixa/estilo.css">

Este componente pede uma coisa da página. Todo o conteúdo acima do rodapé tem de estar dentro de um invólucro:

<body>
  <div class="curt-pagina">
    <!-- hero, todas as dobras, tudo -->
  </div>

  <div class="curt-espaco" aria-hidden="true"></div>
  <footer class="sec-dark curt"> ... </footer>
</body>

Ganchos

Gancho Papel
.curt-pagina Invólucro de tudo que vem antes. É ele que levanta a página acima do painel (z-index:1).
.curt-espaco O vazio de 100vh no fim do fluxo, fora do invólucro. É ele que dá o trecho de rolagem em que o painel aparece.
--curt-linha Cor dos dois filetes. var(--rule-2) no padrão.
--curt-marca Corpo da marca do meio. clamp(34px,9.6vw,140px) no padrão.

Variações


Gotchas


Histórico

Projeto Onde Data Diferenças
referência: Rony Meisler https://www.ronymeisler.com.br/investimentos — rodapé 2026-08-31 referência visual, não origem de código

Normalizações aplicadas na tradução: a referência é Framer — classes hash, sem licença declarada, e nada foi copiado (§11). Medido nela e reproduzido: painel position:fixed de 1425×900 com z-index:1 sobre um div vazio de 900px (100vh) no fim do fluxo, com as dobras da página em z-index:3; miolo de 1265×740 com padding 80 e justify-content:space-between, o que dá quatro vãos iguais de 106; linha de topo de 48 com cinco links 16/24 em gap 32 e botão pílula de 182×48 com raio 100px; dois filetes de 1px; faixa central de 1265×242 para o logotipo; linha de base de 24. E o que mais importava confirmar: transform:none em cinco posições de rolagem diferentes — o painel nunca se move, e é daí que vem a sensação de parallax.

O que é nosso: o padding lateral saiu para o .wrap, que continua sendo a única regra da coluna (§4); preto cravado e o cinza-sage dos filetes viraram --bg, --fg, --fg-2 e --rule-2 pelo escopo de tom; o botão é a primitiva .btn/.btn-ghost do core, sem retoque de forma; a nav do rodapé virou <nav> com rótulo; o espaçador ganhou aria-hidden e pointer-events:none.

Divergências conhecidas vs. a referência: o painel lê --dark (#0a0a0a) e não preto puro — é a superfície escura do projeto, e o §3 do contrato pede tons vizinhos. Os filetes saem de --rule-2 e ficam bem mais discretos que o rgb(186,191,186) quase branco do original; quem quiser aquele peso sobe --curt-linha, que existe para isso. A faixa central do original é um canvas Rive com o logotipo animado — uma lib inteira para um logotipo que se mexe; aqui é texto em --display, que escala sozinho, não pede asset e não some se o SVG do cliente não chegou. O corpo da marca é calibrado para um nome de ~14 caracteres encher a coluna numa linha: nome muito diferente disso pede ajuste em --curt-marca, e é o único ajuste que a troca de marca pede.