hubeiqiao/skills · Archived

framer-motion-sticky-scroll-layout

Fix Framer Motion sticky scroll sections where absolute-positioned children don't render correctly. Use when: (1) console warning "Please ensure that the container has a non-static position", (2) sticky scroll pillar/slide transitions show content at wrong positions or invisible, (3) absolute-positioned motion.div children overflow or stack incorrectly inside a sticky viewport. Solution: wrap with relative container inside the sticky element.

First seen Apr 16, 2026

Installation

$ npx skills add hubeiqiao/skills --skill framer-motion-sticky-scroll-layout

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from hubeiqiao/skills · top by installs.

npx skills add hubeiqiao/skills

Browse all from hubeiqiao/skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0
Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 3,900 B
  • docs SUMMARY.md 488 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Framer Motion Sticky Scroll Section Layout

Problem

When building scroll-driven sections with CSS position: sticky and Framer Motion animated slides (absolute-positioned children that fade in/out based on scroll progress), the children render incorrectly — often stacking, overflowing, or appearing at wrong positions. Framer Motion logs: "Please ensure that the container has a non-static position."

Context / Trigger Conditions

  • Building a scroll-pinned section with multiple "slides" that transition as user scrolls
  • Using position: sticky with a tall scroll runway (e.g., height: 300vh)
  • Child slides use position: absolute; inset: 0 to stack on top of each other
  • Framer Motion animate toggles opacity and y based on useScroll + useTransform
  • Console warning about non-static position on the container

Solution

Correct structure:

<div ref={scrollRef} className="relative" style={{ height: '300vh' }}>
  {/* Sticky viewport */}
  <div className="sticky top-0 h-screen overflow-hidden">
    {/* CRITICAL: This relative wrapper is the positioning context */}
    <div className="relative w-full h-full">

      {/* Slide 1 */}
      <motion.div
        className="absolute inset-0 flex items-center"
        animate={{ opacity: currentSlide === 0 ? 1 : 0 }}
      >
        <div className="max-w-6xl mx-auto w-full px-8">
          {/* Content */}
        </div>
      </motion.div>

      {/* Slide 2 */}
      <motion.div
        className="absolute inset-0 flex items-center justify-center"
        animate={{ opacity: currentSlide === 1 ? 1 : 0 }}
      >
        {/* Content */}
      </motion.div>

    </div>
  </div>
</div>

Key rules:

  1. The relative w-full h-full div MUST be a direct child of the sticky container
  2. All slides use absolute inset-0 to fill this relative container
  3. Content padding (px-8, max-w-6xl) goes INSIDE each slide, not on the container
  4. Use flex items-center on each absolute slide for vertical centering
  5. Each slide gets its own layout (grid, flex, centered) — they don't share a parent layout

Common mistake — putting content wrapper between sticky and slides:

// WRONG: max-w-6xl wrapper between sticky and absolute slides
<div className="sticky top-0 h-screen">
  <div className="max-w-6xl mx-auto w-full px-8">
    <motion.div style={{ position: 'absolute', inset: 0 }}>
      {/* This breaks because absolute child escapes the static parent */}
    </motion.div>
  </div>
</div>

Verification

  • Console warning about non-static position disappears
  • All slides render centered vertically in the viewport
  • Slides transition smoothly as scroll progresses through the runway
  • Content has proper padding from viewport edges on all slides

Notes

  • The overflow-hidden on the sticky div prevents scroll-driven content from bleeding
  • For useScroll with target, the ref goes on the outer runway div, not the sticky div
  • Map scroll progress to slide index: useTransform(scrollYProgress, [0, 0.33, 0.34, 0.66, 0.67, 1], [0, 0, 1, 1, 2, 2])
  • On mobile, skip sticky entirely — use a simple stacked layout with whileInView animations instead
  • Use useState + useEffect with motionValue.on('change') to convert Framer Motion values to React state for conditional rendering