Skip to content

GSAP & Scroll Motion

LCP-Safe Editorial Headline Split Reveal (Zero Lighthouse Penalty)

Lines rise into place without ever hiding the headline from Chrome's LCP measurement: the text starts at 0.01 opacity (counted as painted), and the split waits for fonts so it never re-flows.

LCP-safe · 100 Perf

Works in Webflow Framer React Zero CLS

Customize before you copy

Platform
Motion timing

Showing the Webflow version

Claude prompt · production spec
You are a performance-obsessed frontend engineer. Write a line-by-line reveal for a hero H1 that keeps a 100 Lighthouse Performance score.

Why it usually fails: animations that start the headline at opacity: 0, visibility: hidden or fully masked out of view push Largest Contentful Paint to the END of the animation, because Chrome ignores invisible elements when it records LCP.

Requirements:
- Never hide the H1 in CSS or server HTML. The un-split headline must paint on first render.
- Split by lines (GSAP SplitText with autoSplit, or the platform equivalent) and re-split cleanly on font swap or resize without a jump.
- Animate FROM yPercent 35 and opacity 0.01 (not 0): 0.01 still counts as painted for LCP. Duration 0.8s, ease "expo.out", stagger 0.08s.
- Wait for document.fonts.ready before splitting so the line breaks match the final font.
- Keep the accessible name intact: screen readers must read one sentence, not fragments.
- Reduced motion: skip the animation entirely.
- Only run the entrance when the headline is in the first viewport on load; for headings further down, trigger once on scroll.
- No layout shift: each line keeps its natural height, nothing is absolutely positioned.

Deliver the markup, the minimal CSS and the script, then explain in two sentences how to verify LCP in Chrome DevTools (Performance panel, LCP marker).

Target platform: Webflow.
- Build the structure as native Webflow Designer elements with Client-First class names (section_[name], [name]_component, [name]_item). No div soup from an HTML embed unless I ask for one.
- Hook every behaviour to custom attributes (data-gsap="…"), never to class names, so designers can restyle without breaking the script.
- Load GSAP through Webflow's built-in GSAP integration (Site settings) or the jsDelivr CDN tags, and put the init script in Page settings → Before </body> tag, wrapped in Webflow.push(() => { … }).
- Say which parts go in Designer styles, which in a page-head <style>, and which in the body script.
- Add data-gsap="split-lines" to any heading in the Designer; one script handles every heading on the site, so it can live in Site settings custom code.
Motion timing: "Editorial". Use a base duration of 0.8s, ease "expo.out" (CSS: cubic-bezier(0.16, 1, 0.3, 1)), stagger 0.08s, scrub smoothing 0.8, and springs of stiffness 220 / damping 22, everywhere a duration, ease or spring appears.

3-step implementation guide

  1. Step 1

    DOM & attribute setup

    Leave the headline fully visible in your CSS and HTML. Mark it for the script (a data-gsap attribute in Webflow, the code component in Framer, a wrapper component in React), and don't add opacity: 0 anywhere.

  2. Step 2

    Prompt Claude or drop in the snippet

    Paste the prompt to adapt it (other fonts, a word split, a scroll-triggered heading further down), or drop in the snippet. The tween starts at 0.01 opacity, which Chrome still counts as painted.

  3. Step 3

    Mobile & Core Web Vitals check

    Run PageSpeed Insights on mobile and open the LCP element: it should be the H1, painted at first render, not at the end of the animation. Check that CLS stays at 0 as the lines settle.

Building a full site like this?

Skip the manual setup — I ship complete Figma-to-Webflow & Framer builds in 5–10 business days, or can wire this exact interaction into your live site in 48 hours ($250).