← Biblioteca componentes/conversao/cta-fechamento-foto/ficha.md CódigoTela cheia
conversao/cta-fechamento-foto

CTA de fechamento com foto

🟢 estavel complexidade baixa prefixo end- cta conversao fechamento assinatura imagem css-puro split sem javascript

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

<link rel="stylesheet" href="componentes/conversao/cta-fechamento-foto/estilo.css">

markup.html · 33 linhas · 1,5 KB

<!-- ==========================================================================
     FECHAMENTO — assinatura sobre foto sangrada
     Prefixo: end-
     Requer: core/tokens.css, core/base.css, core/motion.css, core/motion.js
              + este estilo.css. Sem script próprio.

     É o eco do hero antes do rodapé: a mesma foto sangrada, o mesmo escuro,
     uma frase e um botão. Vai como ÚLTIMA seção antes do rodapé, e com pelo
     menos uma dobra entre ele e o CTA de verdade da página.

     Não tem olho, não tem título de seção, não tem lista. Se você sentir
     falta de um dos três, a seção que você quer é outra.
     ========================================================================== -->

<section class="end-sec sec-dark sec-pad">
  <div class="end-media">
    <img class="end-img" src="../../../showroom/demo/ph-wide-4.webp" alt="" loading="lazy" decoding="async">
  </div>
  <div class="grain"></div>

  <div class="wrap end-body">
    <!-- data-split revela palavra a palavra e preserva o <br>: onde a frase
         quebra é decisão editorial, não sobra de largura de tela. -->
    <h2 class="end-sign" data-split>A promessa da marca,<br>dita uma última vez.</h2>

    <div class="end-cta" data-rv data-d="1">
      <a href="#contato" class="btn btn-primary">
        Comece a conversa
        <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 7H12M8 3L12 7L8 11"/></svg>
      </a>
    </div>
  </div>
</section>

estilo.css · 76 linhas · 3,2 KB

/* ==========================================================================
   FECHAMENTO — assinatura sobre foto sangrada
   Prefixo: end-
   Tokens usados: --dark-rgb --fg --sans

   Três tokens e nenhuma linha de JS. É o componente mais barato da
   biblioteca: uma foto, um gradiente, uma frase e um botão. Tudo que ele
   faz de interessante está no gradiente — que é o que costura a seção nas
   duas vizinhas sem deixar emenda.
   ========================================================================== */

.end-sec{position:relative;overflow:hidden}

/* ---- mídia ----
   A foto é atmosfera, não assunto. Entra rebaixada e meio dessaturada:
   quem olhar de perto reconhece o lugar, quem passar lê só textura. Se a
   foto ainda for legível como cena, ela está clara demais. */
.end-media{position:absolute;inset:0;z-index:0}
/* --end-veu e' o unico numero que se mexe ao trocar a foto. O valor certo
   depende do brilho dela: .3 serve para foto clara; com fotografia escura
   (que e' a regra em site de fundo preto) some tudo, e ai' sobe para .5.
   A ficha traz como medir. */
.end-img{width:100%;height:100%;object-fit:cover;
  opacity:var(--end-veu,.5);filter:grayscale(.5)}

/* Gradiente de três paradas, não véu chapado (contrato §6). As duas pontas
   fecham em --dark SÓLIDO e só o meio abre até .62:

     topo sólido  = emenda invisível com a seção anterior
     meio aberto  = a única faixa onde a foto existe
     base sólida  = emenda invisível com o rodapé

   O componente não tem borda nem corte: ele dissolve nos dois vizinhos.
   Trocar por um overlay de opacidade única devolve as duas linhas retas
   que este gradiente existe para apagar. */
.end-media::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to bottom,
    rgb(var(--dark-rgb)) 0%,
    rgba(var(--dark-rgb),.62) 42%,
    rgb(var(--dark-rgb)) 100%);
}

/* ---- corpo ----
   Segunda classe no .wrap: o componente empilha e centraliza, mas não
   encosta em padding-inline nem em max-width — a coluna continua sendo
   assunto do core (contrato §4). O z-index sobe acima do .grain, que é 1. */
.end-body{position:relative;z-index:2;text-align:center}

/* A assinatura usa a fonte de TEXTO em itálico, como a citação do
   manifesto: ela é fala, não rótulo. Display bold aqui viraria mais um
   título de seção, e a página já teve todos os que precisava.

   20ch é o teto de verdade, não um chute: acima disso a frase vira
   parágrafo centralizado e perde o peso de assinatura. */
.end-sign{
  font-family:var(--sans);font-style:italic;font-weight:300;
  font-size:clamp(26px,4vw,46px);line-height:1.34;
  max-width:20ch;margin-inline:auto;color:var(--fg);
}

/* Flex, não bloco: assim cabe um segundo botão (um fantasma ao lado do
   primário) sem refazer nada, e a quebra no mobile já vem resolvida. */
.end-cta{
  display:flex;justify-content:center;flex-wrap:wrap;gap:14px;
  margin-top:36px;
}

/* ---- mobile ----
   Uma coluna centrada quase não tem o que reorganizar, e o clamp já
   resolve o corpo do texto. Sobram duas medidas que foram calibradas no
   tamanho grande e ficam frouxas no piso de 26px. */
@media(max-width:640px){
  .end-sign{line-height:1.28}
  .end-cta{margin-top:28px}
}

A última dobra antes do rodapé. Uma foto sangrada quase apagada, um gradiente de três paradas que fecha em preto sólido em cima e embaixo, grão por cima, e no centro só duas coisas: a frase que a marca assinaria, em itálico grande, e um botão.

É o eco do hero: mesma foto, mesmo escuro, mesma promessa — dita agora por quem já leu a página inteira. Não tem olho, não tem título de seção, não tem lista, não tem formulário. Essa pobreza é o componente: se ele tivesse mais uma coisa, seria mais uma seção, e a página não precisa de mais uma seção nesse ponto.

Sem script. Três tokens. É a peça mais barata da biblioteca e provavelmente a mais reutilizável: toda página institucional precisa acabar, e quase toda acaba desta forma.


Este ou o cta-formulario-lead?

A categoria conversão tem duas peças de dobra inteira, e elas não competem: fazem trabalhos diferentes em momentos diferentes da página.

cta-fechamento-foto cta-formulario-lead
Pede ao visitante um clique 4 campos preenchidos
Onde vive último bloco antes do rodapé onde a conversão realmente acontece — meio ou fim
O que entrega intenção: leva a pessoa até a oferta o lead, com nome, contato e qualificação
Complexidade baixa, CSS puro alta, com script, validação e select composto
Precisa de backend não sim — sem endpoint ele perde lead em silêncio
Custo de montar copiar dois arquivos copiar quatro, mais o select-custom, mais ligar o envio

A regra prática: se a página tem um momento de conversão, ele é o cta-formulario-lead, e este aqui não substitui. Se a página tem um momento de conversão e ainda continua — FAQ, prova social, mais um bloco editorial —, este componente é o que fecha a conta no fim.

Os dois na mesma página é o uso certo, não o excesso. O botão daqui aponta para a âncora do formulário (href="#contato"), então o fechamento não é um segundo pedido: é o mesmo pedido, repetido a quem chegou até o fim. Foi assim na origem.

Ponha pelo menos uma dobra entre os dois. Formulário e fechamento colados leem como insistência, e o segundo cancela o primeiro. Na origem havia o FAQ inteiro no meio.


Quando usar

Quando não usar


Padrão editorial

Slot Regra
.end-sign 6 a 10 palavras, duas linhas — não três. A promessa da marca, não uma oferta: sem número, sem prazo, sem "clique aqui". Duas cláusulas que se espelham em torno de uma vírgula é o ritmo que faz a frase soar assinada. Acima de 10 palavras o max-width:20ch já a quebra em três linhas e ela vira parágrafo.
Quebra da frase A <br> é sua, não do navegador. Escolha onde a frase respira e marque; data-split preserva a tag. O max-width:20ch é a rede de segurança, não o plano.
Rótulo do botão 2 a 4 palavras, a mesma ação do CTA principal. Se lá em cima está "Agende seu diagnóstico", aqui não vire "Fale conosco": rótulo diferente lê como oferta diferente.
Destino do botão A âncora da seção de conversão da própria página. Link para outra página aqui desperdiça a única intenção que a peça produz.

Não use <em> na assinatura. A linha inteira já é itálico; o <em> do h2.sec-title existe para destacar uma palavra dentro de um título reto, e aqui não há reto contra o qual destacar. Se precisar de ênfase, ela vem da quebra de linha.

A frase não repete o título do hero, mas rima com ele. Se o hero diz "Segurança no presente, liberdade no futuro", o fechamento pode fechar o mesmo par por outro lado. Repetir literalmente lê como falta de assunto.


Especificação da imagem

Proporção paisagem, mínimo 1600×900
Peso até 250 KB — é a última imagem da página, não vale mais que isso
Assunto horizonte, cidade, paisagem, mar. Nada com rosto, texto ou detalhe fino
Enquadramento object-fit:cover num bloco largo e baixo: o assunto tem de sobreviver a corte em cima e embaixo
Tratamento já entra em opacity:.3 e grayscale(.5), e o gradiente come as duas pontas. Escolha por atmosfera, não por conteúdo

O teste: se, no preview, você consegue dizer o que está na foto, ela está clara demais para este componente. A foto certa aqui parece um vinco de luz no preto.

loading="lazy" e decoding="async" estão no markup de propósito — é a última imagem da página e ela é puramente decorativa. Se o seu público chega por scroll rápido até o rodapé e você vê a foto entrando, tire o lazy: o custo é um request adiantado, o ganho é não piscar.


Como usar

<link rel="stylesheet" href="componentes/conversao/cta-fechamento-foto/estilo.css">

Só isso. Não há script.js — o movimento inteiro vem do core/motion.js, que a página já carrega.

Ganchos

Gancho O quê
[data-split] na .end-sign reveal palavra a palavra, do core. Preserva <br>
[data-rv][data-d="1"] no .end-cta o botão entra depois da frase terminar de se montar
.grain primitiva do core, irmã da .end-media — precisa ficar fora dela para não passar por baixo do gradiente

Variações

Variação Como Quando
Sem foto apagar .end-media e o .grain Página que já tem foto demais, ou projeto sem banco de imagem
Botão fantasma .btn-ghost no lugar de .btn-primary O CTA de verdade está poucas dobras acima e este é só o eco
Dois botões um .btn-primary e um .btn-ghost dentro do mesmo .end-cta Duas saídas legítimas: agendar e falar no WhatsApp
Sem botão apagar o .end-cta inteiro Fechamento puramente editorial, com a conversão morando no rodapé

O .end-cta é flex com justify-content:center e flex-wrap:wrap — o segundo botão entra e quebra no mobile sem nenhuma regra a mais.


Gotchas

Como medir antes de calibrar:

python from PIL import Image, ImageStat print(ImageStat.Stat(Image.open("foto.jpg").convert("L")).mean[0])

Abaixo de ~90 (numa escala de 0 a 255) a foto é escura: suba --end-veu para .5–.6. Acima de ~140, desça para .3, senão a imagem briga com a assinatura. Este gotcha foi descoberto no próprio preview: a primeira foto escolhida tinha média 78 e a dobra ficou indistinguível de um fundo liso.


Histórico

Projeto Onde Data O quê
Liberta Wealth site/index.html, .close-sec (entre o FAQ e o rodapé) 2026-08 Origem. Classes .close-, seletores de elemento (.close-media img, .close-sec h2), alcance nas primitivas (.close-sec > .wrap, .close-sec .btn) e a assinatura em var(--serif).

Normalizações aplicadas na extração:

Na origem Aqui Por quê
prefixo close- end- close é verbo em inglês e vai colidir com o primeiro modal, drawer ou toast da categoria sobreposições — a biblioteca já tem .fold-close e [data-fold-close] querendo dizer "fechar". end- é substantivo: o fim da página
.close-media img .end-img seletor de elemento (contrato §6.3)
.close-sec h2 .end-sign idem
.close-sec > .wrap .end-body, segunda classe no .wrap componente não estiliza primitiva do core por descendência
.close-sec .btn{margin-top:36px} .end-cta, wrapper flex mesmo motivo, e de quebra o segundo botão passou a caber sem regra nova
text-align:center na seção na .end-body a centralização era herdada por qualquer coisa colada dentro
font-family:var(--serif) var(--sans) em itálico a biblioteca não tem --serif. A citação do conteudo/manifesto-citacao veio do mesmo site com o mesmo --serif e foi mapeada para --sans itálico, com o argumento de que citação é fala, não rótulo. A assinatura é a mesma voz e recebe o mesmo tratamento — duas peças com a mesma função tipográfica não podem divergir
font-weight:500 300 consequência da troca acima: 500 era o peso do serif; o --sans em 300 é o que casa com a .man-quote
seta diagonal no SVG do botão seta horizontal, a mesma do hero e do cta-formulario-lead o .btn:hover svg do core faz translateX(4px) — uma seta diagonal deslizando na horizontal lê torto
<h2 class="ttl"> <h2 class="end-sign" data-split> reveal palavra a palavra, que é o ritmo de assinatura
<img src alt=""> mais loading="lazy" e decoding="async" é a última imagem da página e é decorativa

Calibragem no primeiro uso. O código é da própria Liberta Wealth, sem autor externo nem licença a creditar. Uma ressalva de proveniência: a pasta do projeto tem duas cópias do site — github-repo/, a versão confirmada de onde saíram os 18 componentes da varredura, e site/, uma composição cuja ida ao ar não está confirmada. A seção .close-sec existe somente na site/, então o que está aqui foi lido de uma composição, não de uma página publicada.

O que esperar no primeiro uso real: o opacity:.3 da foto e o .62 do meio do gradiente foram calibrados numa foto específica, escura e de horizonte. Foto mais clara vai pedir .22/.55; foto muito escura, .4/.7. Ajuste os dois juntos — mexer só num deixa a foto ou chapada ou fantasma.