31 CSS Hero Sections10 / 31
Sticky Scroll Cue
Tall full-bleed hero with a bouncing scroll indicator at the bottom. Forest emerald on birch with a soft yellow CTA — the cabin / retreat brand aesthetic.
Published
The code
<section class="hs-10" aria-label="Hero">
<div class="hs-10__inner">
<span class="hs-10__eye">— A small place upstate</span>
<h2>Slow Sundays, <em>warm wood,</em> not a single notification.</h2>
<p>Three cabins, two acres, no Wi-Fi, one shared kitchen. Book yourself a real weekend.</p>
<a class="hs-10__cta" href="#book">Check availability</a>
</div>
<div class="hs-10__cue" aria-hidden="true">
<span>scroll</span>
<div class="hs-10__mouse"><span></span></div>
</div>
</section><section class="hs-10" aria-label="Hero">
<div class="hs-10__inner">
<span class="hs-10__eye">— A small place upstate</span>
<h2>Slow Sundays, <em>warm wood,</em> not a single notification.</h2>
<p>Three cabins, two acres, no Wi-Fi, one shared kitchen. Book yourself a real weekend.</p>
<a class="hs-10__cta" href="#book">Check availability</a>
</div>
<div class="hs-10__cue" aria-hidden="true">
<span>scroll</span>
<div class="hs-10__mouse"><span></span></div>
</div>
</section>.hs-10 {
position: relative;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px) 90px;
background: radial-gradient(80% 60% at 50% 0%, rgba(38,82,52,0.16), transparent 70%), #f3eadb;
font-family: 'Inter', system-ui, sans-serif;
color: #1e3a26;
box-sizing: border-box;
}
.hs-10__inner {
max-width: 720px;
text-align: center;
}
.hs-10__eye {
display: inline-block;
font-family: 'Cormorant Garamond', Georgia, serif;
font-style: italic;
font-size: 16px;
color: #6b8a6f;
margin-bottom: 18px;
}
.hs-10 h2 {
margin: 0 0 18px;
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: clamp(34px, 5vw, 56px);
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.05;
}
.hs-10 h2 em {
color: #b8893a;
font-style: italic;
}
.hs-10 p {
margin: 0 auto 26px;
font-size: 16px;
line-height: 1.55;
color: #5a6b58;
max-width: 480px;
}
.hs-10__cta {
display: inline-block;
padding: 13px 26px;
background: #f4d35e;
color: #1e3a26;
border: 2px solid #1e3a26;
border-radius: 0;
text-decoration: none;
font-weight: 700;
font-size: 14px;
letter-spacing: 0.04em;
box-shadow: 4px 4px 0 #1e3a26;
transition: transform 0.15s, box-shadow 0.15s;
}
.hs-10__cta:hover {
transform: translate(2px,2px);
box-shadow: 2px 2px 0 #1e3a26;
}
.hs-10__cue {
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.18em;
color: #6b8a6f;
text-transform: uppercase;
}
.hs-10__mouse {
width: 22px;
height: 36px;
border: 2px solid #1e3a26;
border-radius: 12px;
position: relative;
}
.hs-10__mouse span {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 3px;
height: 7px;
background: #1e3a26;
border-radius: 2px;
animation: hs-10-bounce 1.4s ease-in-out infinite;
}
@keyframes hs-10-bounce {
0%,
100% {
transform: translate(-50%, 0);
opacity: 1;
}
50% {
transform: translate(-50%, 10px);
opacity: 0.4;
}
}
@media (prefers-reduced-motion: reduce) {
.hs-10__mouse span {
animation: none;
}
.hs-10__cta {
transition: none;
}
}.hs-10 {
position: relative;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px) 90px;
background: radial-gradient(80% 60% at 50% 0%, rgba(38,82,52,0.16), transparent 70%), #f3eadb;
font-family: 'Inter', system-ui, sans-serif;
color: #1e3a26;
box-sizing: border-box;
}
.hs-10__inner {
max-width: 720px;
text-align: center;
}
.hs-10__eye {
display: inline-block;
font-family: 'Cormorant Garamond', Georgia, serif;
font-style: italic;
font-size: 16px;
color: #6b8a6f;
margin-bottom: 18px;
}
.hs-10 h2 {
margin: 0 0 18px;
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: clamp(34px, 5vw, 56px);
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.05;
}
.hs-10 h2 em {
color: #b8893a;
font-style: italic;
}
.hs-10 p {
margin: 0 auto 26px;
font-size: 16px;
line-height: 1.55;
color: #5a6b58;
max-width: 480px;
}
.hs-10__cta {
display: inline-block;
padding: 13px 26px;
background: #f4d35e;
color: #1e3a26;
border: 2px solid #1e3a26;
border-radius: 0;
text-decoration: none;
font-weight: 700;
font-size: 14px;
letter-spacing: 0.04em;
box-shadow: 4px 4px 0 #1e3a26;
transition: transform 0.15s, box-shadow 0.15s;
}
.hs-10__cta:hover {
transform: translate(2px,2px);
box-shadow: 2px 2px 0 #1e3a26;
}
.hs-10__cue {
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.18em;
color: #6b8a6f;
text-transform: uppercase;
}
.hs-10__mouse {
width: 22px;
height: 36px;
border: 2px solid #1e3a26;
border-radius: 12px;
position: relative;
}
.hs-10__mouse span {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 3px;
height: 7px;
background: #1e3a26;
border-radius: 2px;
animation: hs-10-bounce 1.4s ease-in-out infinite;
}
@keyframes hs-10-bounce {
0%,
100% {
transform: translate(-50%, 0);
opacity: 1;
}
50% {
transform: translate(-50%, 10px);
opacity: 0.4;
}
}
@media (prefers-reduced-motion: reduce) {
.hs-10__mouse span {
animation: none;
}
.hs-10__cta {
transition: none;
}
}Here's a working CSS Hero Section from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Sticky Scroll Cue
Source: https://codefronts.com/layouts/css-hero-sections/sticky-scroll-cue/
Tall full-bleed hero with a bouncing scroll indicator at the bottom. Forest emerald on birch with a soft yellow CTA — the cabin / retreat brand aesthetic.
## HTML
```html
<section class="hs-10" aria-label="Hero">
<div class="hs-10__inner">
<span class="hs-10__eye">— A small place upstate</span>
<h2>Slow Sundays, <em>warm wood,</em> not a single notification.</h2>
<p>Three cabins, two acres, no Wi-Fi, one shared kitchen. Book yourself a real weekend.</p>
<a class="hs-10__cta" href="#book">Check availability</a>
</div>
<div class="hs-10__cue" aria-hidden="true">
<span>scroll</span>
<div class="hs-10__mouse"><span></span></div>
</div>
</section>
```
## CSS
```css
.hs-10 {
position: relative;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px) 90px;
background: radial-gradient(80% 60% at 50% 0%, rgba(38,82,52,0.16), transparent 70%), #f3eadb;
font-family: 'Inter', system-ui, sans-serif;
color: #1e3a26;
box-sizing: border-box;
}
.hs-10__inner {
max-width: 720px;
text-align: center;
}
.hs-10__eye {
display: inline-block;
font-family: 'Cormorant Garamond', Georgia, serif;
font-style: italic;
font-size: 16px;
color: #6b8a6f;
margin-bottom: 18px;
}
.hs-10 h2 {
margin: 0 0 18px;
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: clamp(34px, 5vw, 56px);
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.05;
}
.hs-10 h2 em {
color: #b8893a;
font-style: italic;
}
.hs-10 p {
margin: 0 auto 26px;
font-size: 16px;
line-height: 1.55;
color: #5a6b58;
max-width: 480px;
}
.hs-10__cta {
display: inline-block;
padding: 13px 26px;
background: #f4d35e;
color: #1e3a26;
border: 2px solid #1e3a26;
border-radius: 0;
text-decoration: none;
font-weight: 700;
font-size: 14px;
letter-spacing: 0.04em;
box-shadow: 4px 4px 0 #1e3a26;
transition: transform 0.15s, box-shadow 0.15s;
}
.hs-10__cta:hover {
transform: translate(2px,2px);
box-shadow: 2px 2px 0 #1e3a26;
}
.hs-10__cue {
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.18em;
color: #6b8a6f;
text-transform: uppercase;
}
.hs-10__mouse {
width: 22px;
height: 36px;
border: 2px solid #1e3a26;
border-radius: 12px;
position: relative;
}
.hs-10__mouse span {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 3px;
height: 7px;
background: #1e3a26;
border-radius: 2px;
animation: hs-10-bounce 1.4s ease-in-out infinite;
}
@keyframes hs-10-bounce {
0%,
100% {
transform: translate(-50%, 0);
opacity: 1;
}
50% {
transform: translate(-50%, 10px);
opacity: 0.4;
}
}
@media (prefers-reduced-motion: reduce) {
.hs-10__mouse span {
animation: none;
}
.hs-10__cta {
transition: none;
}
}
```Here's a working CSS Hero Section from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Sticky Scroll Cue
Source: https://codefronts.com/layouts/css-hero-sections/sticky-scroll-cue/
Tall full-bleed hero with a bouncing scroll indicator at the bottom. Forest emerald on birch with a soft yellow CTA — the cabin / retreat brand aesthetic.
## HTML
```html
<section class="hs-10" aria-label="Hero">
<div class="hs-10__inner">
<span class="hs-10__eye">— A small place upstate</span>
<h2>Slow Sundays, <em>warm wood,</em> not a single notification.</h2>
<p>Three cabins, two acres, no Wi-Fi, one shared kitchen. Book yourself a real weekend.</p>
<a class="hs-10__cta" href="#book">Check availability</a>
</div>
<div class="hs-10__cue" aria-hidden="true">
<span>scroll</span>
<div class="hs-10__mouse"><span></span></div>
</div>
</section>
```
## CSS
```css
.hs-10 {
position: relative;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px) 90px;
background: radial-gradient(80% 60% at 50% 0%, rgba(38,82,52,0.16), transparent 70%), #f3eadb;
font-family: 'Inter', system-ui, sans-serif;
color: #1e3a26;
box-sizing: border-box;
}
.hs-10__inner {
max-width: 720px;
text-align: center;
}
.hs-10__eye {
display: inline-block;
font-family: 'Cormorant Garamond', Georgia, serif;
font-style: italic;
font-size: 16px;
color: #6b8a6f;
margin-bottom: 18px;
}
.hs-10 h2 {
margin: 0 0 18px;
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: clamp(34px, 5vw, 56px);
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.05;
}
.hs-10 h2 em {
color: #b8893a;
font-style: italic;
}
.hs-10 p {
margin: 0 auto 26px;
font-size: 16px;
line-height: 1.55;
color: #5a6b58;
max-width: 480px;
}
.hs-10__cta {
display: inline-block;
padding: 13px 26px;
background: #f4d35e;
color: #1e3a26;
border: 2px solid #1e3a26;
border-radius: 0;
text-decoration: none;
font-weight: 700;
font-size: 14px;
letter-spacing: 0.04em;
box-shadow: 4px 4px 0 #1e3a26;
transition: transform 0.15s, box-shadow 0.15s;
}
.hs-10__cta:hover {
transform: translate(2px,2px);
box-shadow: 2px 2px 0 #1e3a26;
}
.hs-10__cue {
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.18em;
color: #6b8a6f;
text-transform: uppercase;
}
.hs-10__mouse {
width: 22px;
height: 36px;
border: 2px solid #1e3a26;
border-radius: 12px;
position: relative;
}
.hs-10__mouse span {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 3px;
height: 7px;
background: #1e3a26;
border-radius: 2px;
animation: hs-10-bounce 1.4s ease-in-out infinite;
}
@keyframes hs-10-bounce {
0%,
100% {
transform: translate(-50%, 0);
opacity: 1;
}
50% {
transform: translate(-50%, 10px);
opacity: 0.4;
}
}
@media (prefers-reduced-motion: reduce) {
.hs-10__mouse span {
animation: none;
}
.hs-10__cta {
transition: none;
}
}
```How this works
The Sticky Scroll Cue Hero uses position: relative on the section with a position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%) mouse-wheel indicator anchored to the bottom center. The bouncing dot inside the mouse-shape rectangle animates on a 1.4s ease-in-out keyframe — translate(-50%, 0) → translate(-50%, 10px) with an opacity dip from 1 to 0.4. The universal "mouse wheel" glyph is a 22 × 36px rounded rectangle with 2px border, and the dot is a 3 × 7px pill positioned inside it. The whole cue is aria-hidden="true" because the visual pattern doesn't add value for screen-reader users.
The cabin-retreat palette is forest emerald #1e3a26 as body and border, warm birch #f3eadb as the base with a subtle emerald radial-gradient wash at the top, soft yellow #f4d35e for the brutalist CTA, and champagne gold #b8893a for the italic emphasis word — the exact triad that hospitality and cabin-rental brands (Getaway, Postcard Cabins, Aman-adjacent) ship on their landing pages. Cormorant Garamond italic runs the eyebrow (— A small place upstate), Playfair Display (via serif fallback) carries the h2, system stack handles body. The CTA uses a 4px 4px 0 #1e3a26 hard shadow with square corners — brutalist yellow on emerald reads as "expensive-restrained" without needing the price to prove it.
Why it converts: the scroll cue resolves the #1 landing-page-hero ambiguity — "is there more below or is this the whole page?" — and long editorial hero sections lose 20-30% of visitors to this ambiguity alone. The bouncing mouse-wheel primes the visitor's motor cortex to scroll, and eye-tracking studies show a scroll cue at the bottom of a full-viewport hero lifts scroll-past rate from 60% to 85% on portfolio and hospitality sites. This sticky scroll indicator pattern costs nothing in JS or bundle size and pays back in scroll-depth analytics immediately.
Make it yours
- Recolor to any editorial-hospitality brand: swap emerald base (
#1e3a26) for muted teal, deep navy, or aubergine. Keep the yellow CTA saturated (#f4d35eor brighter) — desaturating drops the brutalist stamp effect and the CTA blends into the base. Birch (#f3eadb) copy stays because cream reads warmer than white on dark hero backgrounds. - Swap the mouse-wheel glyph for other cues: a downward chevron for minimalist, an animated arrow for playful, or the word
SCROLLin Courier for editorial. Whatever you swap in, keep the bounce animation on a 1.4-1.8s cycle — outside that range the cue reads as broken JavaScript rather than an invitation. - For portfolio hero use, drop the CTA entirely and make the whole hero the scroll cue — a single centered image or headline with the mouse-wheel indicator below. The reduced-friction editorial hero converts on scroll-depth rather than CTA click, which suits portfolios and case-study pages.
- For dark mode: the hero is already emerald-dark. To invert to light hospitality (Aman-style), use
#f3eadbbase with#1e3a26copy and shift yellow to burnt orange#c75a2b. The brutalist shadow shifts from emerald to a deep neutral#2a2a2a. - For Tailwind:
min-h-screen bg-[#f3eadb] text-[#1e3a26] relativeon the section,absolute bottom-4 left-1/2 -translate-x-1/2on the cue,bg-[#f4d35e] text-[#1e3a26] border-2 border-[#1e3a26] shadow-[4px_4px_0_#1e3a26] hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-[2px_2px_0_#1e3a26]on the CTA. The bounce needs a custom keyframe intailwind.config.js.
Gotchas — read before shipping
- If you extend the hero to
min-height: 100vhinstead of480px, usemin-height: 100svh(small viewport height) — on iOS Safari the address bar collapses on scroll and a100vhelement jumps 60-80px mid-scroll, a CLS event that hurts Core Web Vitals.100svhis supported in every browser shipped since 2022. - The bouncing mouse-wheel MUST respect
prefers-reduced-motion— the demo does this correctly. The constant vertical motion at bottom-of-viewport is one of the most-reported vestibular triggers. Never remove the guard to "see the effect" and forget to restore it; WCAG 2.3.3 audits catch this immediately. - If you make the cue a link (
<a href="#next">) — recommended for accessibility — the target section MUST haveid="next"ANDscroll-margin-topequal to any sticky header height, or the click scrolls to a position where the target is hidden under the nav. Missingscroll-margin-topis the #1 anchor-link bug in editorial layouts. - The yellow CTA (
#f4d35e) against birch (#f3eadb) hits contrast ~1.4:1 for the yellow itself against the surround — the border provides the visual boundary, not the fill. The CTA text (#1e3a26emerald on#f4d35e) hits ~9.1:1 (AAA) which is what matters for readability. Never ship yellow CTA text without a dark border boundary. - The
position: absolutescroll cue lives in the hero section's containing block — if you addoverflow: hiddento the section for any reason (drift animation, clip-path), the cue is clipped and disappears at the bottom edge. Either drop the overflow or move the cue outside the clipped container. - In Next.js with app-router, the anchor
href="#next"triggers a full route-tree traversal on click if not handled — usescroll={false}on<Link>or a plain<a>with a manualscrollIntoView({ behavior: 'smooth' })handler. Smooth scroll itself must be gated onprefers-reduced-motionor you re-introduce the vestibular problem you dodged in the CSS.