SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/full-page-sections

7 CSS Full Page Sections

5 Pure CSS2 with JSPublished 2026-10-05Free · no sign-up

Seven full-screen patterns: chapters that snap into place, a hero sized with dynamic viewport units, a full-bleed call to action band, a background video section with a pause button, section dots navigation, a split welcome screen and a footer that is uncovered as the page scrolls away.

01. Full-Height Sections with Scroll Snap

Full pageScroll snap

Each section fills the scroll area and scrolling snaps to the next one, the presentation-style page, with scroll-snap-type: y mandatory on the container and scroll-snap-align: start on each section. Keyboard and screen reader users can still move through it normally.

View code
<div class="fps1" tabindex="0" role="region" aria-label="Story, scroll"><section style="--c:#1e3a8a"><h3>Chapter one</h3></section><section style="--c:#6d28d9"><h3>Chapter two</h3></section><section style="--c:#be185d"><h3>Chapter three</h3></section></div>
.fps1 { width: 280px; max-width: 100%; height: 280px; overflow-y: auto; scroll-snap-type: y mandatory; border-radius: 16px; font-family: Inter, system-ui, sans-serif; }
.fps1:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.fps1 section { display: grid; place-items: center; height: 100%; background: var(--c); scroll-snap-align: start; }
.fps1 h3 { margin: 0; color: #fff; font-size: 24px; }

02. Hero Sized with Dynamic Viewport Units

Full pagedvh

100vh on phones includes the space under the browser's address bar, so a full-height hero gets cut off. 100dvh follows the visible area as the bar shows and hides, and svh and lvh give the smallest and largest values. This hero uses min-height: 100dvh with a vh fallback.

View code
<section class="fps2"><h3>Room to breathe</h3><p>min-height: 100dvh keeps this hero exactly one screen tall on phones.</p><a href="#more">Scroll down</a></section>
.fps2 { display: grid; align-content: center; justify-items: center; gap: 10px; min-height: 100vh; min-height: 100dvh; padding: 24px; box-sizing: border-box; background: linear-gradient(160deg, #ecfdf3, #a6f4c5); text-align: center; font: 14px Inter, system-ui, sans-serif; }
.fps2 h3 { margin: 0; color: #054f31; font-size: 28px; } .fps2 p { margin: 0; max-width: 30ch; color: #067647; }
.fps2 a { padding: 9px 14px; border-radius: 8px; background: #054f31; color: #fff; font-weight: 700; text-decoration: none; }
.fps2 a:focus-visible { outline: 3px solid #067647; outline-offset: 2px; }

03. Full-Width Call to Action Band

Full pageCTA

A bold band that ends a long page with one question and one button. It breaks out of a narrow content column to the full width with negative margins calculated from the viewport, so the content above can stay at a readable width.

View code
<div class="fps3"><div class="col"><p>Content column</p></div><section class="band"><h3>Ready to start?</h3><a href="#signup">Create a free account</a></section></div>
.fps3 { width: 100%; font: 14px Inter, system-ui, sans-serif; overflow: hidden; }
.fps3 .col { width: min(240px, 100% - 32px); margin: 0 auto 14px; padding: 18px; box-sizing: border-box; border-radius: 10px; background: #1e293b; color: #94a3b8; text-align: center; }
.fps3 .band { display: grid; justify-items: center; gap: 12px; padding: 30px 16px; background: linear-gradient(135deg, #4338ca, #be185d); text-align: center; }
.fps3 h3 { margin: 0; color: #fff; font-size: 24px; }
.fps3 a { padding: 11px 18px; border-radius: 10px; background: #fff; color: #1e1b4b; font-weight: 800; text-decoration: none; }
.fps3 a:focus-visible { outline: 3px solid #fde68a; outline-offset: 3px; }

04. Background Video Section

Full pageVideo

A full-bleed section with a looping background video, muted and playsinline so it can autoplay on phones. A Pause button is included because autoplaying motion must be stoppable, and the poster colour shows if the video cannot play. A gradient stands in for the video here.

View code
<section class="fps4"><div class="vid" aria-hidden="true"></div><div class="tx"><h3>Made by the sea</h3><button aria-pressed="false">Pause background</button></div></section>
.fps4 { position: relative; display: grid; place-items: center; width: 100%; height: 260px; overflow: hidden; border-radius: 14px; font-family: Inter, system-ui, sans-serif; }
.fps4 .vid { position: absolute; inset: -20%; background: radial-gradient(circle at 30% 40%, #22d3ee, transparent 40%), radial-gradient(circle at 70% 60%, #1d4ed8, transparent 45%), #0c4a6e; animation: fps4 12s ease-in-out infinite alternate; }
.fps4.paused .vid { animation-play-state: paused; }
.fps4 .tx { position: relative; display: grid; justify-items: center; gap: 12px; }
.fps4 h3 { margin: 0; color: #fff; font-size: 26px; text-shadow: 0 2px 10px rgba(0,0,0,.4); }
.fps4 button { padding: 8px 14px; border: 1px solid rgba(255,255,255,.6); border-radius: 999px; background: rgba(0,0,0,.35); color: #fff; font: 600 13px Inter, system-ui, sans-serif; cursor: pointer; }
.fps4 button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@keyframes fps4 { to { transform: translate(8%, -6%) scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .fps4 .vid { animation: none; } }
var s = document.querySelector('.fps4'), b = s.querySelector('button');
b.onclick = function () { var p = s.classList.toggle('paused'); b.setAttribute('aria-pressed', p); b.textContent = p ? 'Play background' : 'Pause background'; };

05. Section Dots Navigation

Full pageNavigation

Full-height sections with a column of dots on the side, one per section, that show where you are and jump to a section when clicked. The dots are links named after their sections, and an IntersectionObserver keeps aria-current on the visible one.

View code
<div class="fps5"><div class="sc" tabindex="0" role="region" aria-label="Sections, scroll"><section id="fps5a" style="--c:#fef3c7"><h3>Intro</h3></section><section id="fps5b" style="--c:#dbeafe"><h3>Features</h3></section><section id="fps5c" style="--c:#fce7f3"><h3>Pricing</h3></section></div><nav aria-label="Sections"><a href="#fps5a" aria-current="true"><span class="sr">Intro</span></a><a href="#fps5b"><span class="sr">Features</span></a><a href="#fps5c"><span class="sr">Pricing</span></a></nav></div>
.fps5 { position: relative; width: 280px; max-width: 100%; font-family: Inter, system-ui, sans-serif; }
.fps5 .sc { height: 260px; overflow-y: auto; scroll-snap-type: y mandatory; border-radius: 16px; }
.fps5 .sc:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
.fps5 section { display: grid; place-items: center; height: 100%; background: var(--c); scroll-snap-align: start; }
.fps5 h3 { margin: 0; color: #101828; font-size: 22px; }
.fps5 nav { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); display: grid; gap: 8px; }
.fps5 nav a { display: block; width: 12px; height: 12px; border: 2px solid #101828; border-radius: 50%; }
.fps5 nav a[aria-current] { background: #101828; }
.fps5 nav a:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.fps5 .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
var sc = document.querySelector('.fps5 .sc'), links = document.querySelectorAll('.fps5 nav a');
var io = new IntersectionObserver(function (es) { es.forEach(function (e) { if (e.isIntersecting) links.forEach(function (l) { if (l.getAttribute('href') === '#' + e.target.id) l.setAttribute('aria-current', 'true'); else l.removeAttribute('aria-current'); }); }); }, { root: sc, threshold: .6 });
sc.querySelectorAll('section').forEach(function (s) { io.observe(s); });
links.forEach(function (l) { l.onclick = function (e) { e.preventDefault(); sc.querySelector(l.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }; });

06. Full-Height Split Welcome

Full pageSplit

A welcome screen split into a message half and an action half, both at least the full height of the view. On small containers the halves stack and each takes its natural height, because forcing two full screens on a phone wastes a whole scroll.

View code
<section class="fps6"><div class="in"><div class="a"><h3>Welcome back</h3><p>Pick up where you left off.</p></div><div class="b"><a href="#continue">Continue editing</a><a href="#new">Start something new</a></div></div></section>
.fps6 { width: 100%; container-type: inline-size; font: 14px Inter, system-ui, sans-serif; }
.fps6 .in { display: grid; border-radius: 14px; overflow: hidden; }
.fps6 .a { padding: 26px 20px; background: #111827; } .fps6 h3 { margin: 0 0 4px; color: #fff; font-size: 24px; } .fps6 p { margin: 0; color: #9ca3af; }
.fps6 .b { display: grid; gap: 8px; align-content: center; padding: 20px; background: #f9fafb; }
.fps6 .b a { padding: 11px; border-radius: 10px; background: #111827; color: #fff; font-weight: 700; text-align: center; text-decoration: none; }
.fps6 .b a + a { background: #fff; color: #111827; border: 1px solid #d1d5db; }
.fps6 a:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
@container (min-width: 440px) { .fps6 .in { grid-template-columns: 1fr 1fr; min-height: 260px; } .fps6 .a { display: grid; align-content: center; } }

07. Footer Revealed Under the Page

Full pageFooter

The page content slides up to uncover a footer that seems to sit underneath it, a curtain effect. The footer is position: sticky at the bottom of the scroll area and the content above has a higher stacking order and its own background.

View code
<div class="fps7" tabindex="0" role="region" aria-label="Page, scroll"><main><h3>Page content</h3><p>Scroll to the end to uncover the footer.</p><p>More content.</p><p>Almost there.</p></main><footer><b>Studio Fern</b><span>hello@example.com</span></footer></div>
.fps7 { width: 280px; max-width: 100%; height: 280px; overflow-y: auto; border-radius: 16px; background: #101828; font: 14px Inter, system-ui, sans-serif; }
.fps7:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
.fps7 main { position: relative; z-index: 1; padding: 20px; background: #fff; border-radius: 0 0 20px 20px; box-shadow: 0 12px 24px -12px rgba(0,0,0,.5); }
.fps7 h3 { margin: 0 0 6px; color: #101828; } .fps7 p { margin: 0 0 80px; color: #475467; } .fps7 p:last-child { margin-bottom: 20px; }
.fps7 footer { position: sticky; bottom: 0; display: grid; gap: 2px; padding: 26px 20px; color: #98a2b3; }
.fps7 footer b { color: #fff; font-size: 18px; }

About these CSS Full Page Sections

Use dvh, not vh, on phones

On mobile, 100vh includes the area behind the address bar, so full-height sections get cut off. 100dvh follows the visible area; keep a 100vh line before it as a fallback.

Snap gently

scroll-snap-type: y mandatory makes each section land neatly, but sections taller than the screen become hard to read. Use proximity or avoid snapping when content length varies.

Autoplaying video needs a pause

Background video must be muted, playsinline and stoppable. A visible Pause button satisfies WCAG and helps people on slow connections.

Navigation that tracks position

Dots or progress navigation should be real links with names, mark the current one with aria-current, and keep working with the keyboard.

Frequently asked questions

Are full-page sections good for SEO?

They are fine as long as the content is real HTML text, not only images or video.

Should every section be full height?

No. Use full height for heroes and key moments; let ordinary content take its natural height.

How do I stop sections looking empty on wide screens?

Limit the content width with max-width and centre it.