Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

On This Page
Master CSS position: sticky with real-world examples. Ensure cross browser compatibility and elevate your web design with ease.

Aakash Rao
February 10, 2026
Have you ever come across the famous saying, The journey is just as important as the destination? This saying holds a profound truth in the world of web development. As the digital world evolves, it becomes crucial to ensure that the website is not merely a destination but also a delightful journey, emphasizing the importance of the entire user experience.
Crafting an engaging and dynamic interface is not just a matter of choice but a fundamental necessity. In this evolving landscape, where every scroll and click weaves a narrative, the significance of CSS position: sticky, emerges as a crucial property.
This feature can significantly enhance user experience and engagement from a business standpoint, contributing to the website’s more polished and professional appearance. Additionally, it keeps important information on the screen at all times, increasing the click-through rate (CTR) on those links.
In this blog about CSS position: sticky, we will explore the potential of sticky positioning in modern web design, step-by-step, with real-world examples.
We will also learn about accessibility with WCAG guidelines and best practices when implementing sticky elements to make sticky elements accessible, ensuring that the website remains inclusive and user-friendly for all.
CSS position: sticky is a property that gives a simple way to control the position of an element as we scroll down a page.
It allows developers to set the rules for stickiness by defining a point – it could be the top or bottom. When the user scrolls to that point, the element becomes sticky and stays fixed in that position until we scroll past it. This is particularly useful when we want things to move with the flow of the page but also stick around when needed.

The above output is shown on the LT Browser.
LT Browser is a dev-friendly browser built on Chromium that helps developers and testers test websites for responsiveness across various device viewports. It offers a comprehensive, responsive testing environment with over 50 pre-installed viewports, including mobile, tablet, desktop, and laptop.
We will also use LT Browser to render outputs for other examples in upcoming sections.
Some real-world use cases of position sticky include navigation menu bars, sticky sidebars, table headers, and advertisement or alert banner components that must remain visible as users scroll through content. Let’s explore the behavior of position: sticky with an example.
HTML:
<section>
<div class="tile"></div>
<div class="tile sticky">I am going to be sticky when you scroll</div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</section>
CSS:
* {
margin: 0;
padding: 0;
font-family: 'Open Sans', sans-serif;
}
.tile {
background: #adf0f5;
height: 200px;
margin: 20px;
border-radius: 10px;
}
@media (width < 600px) {
.tile {
height: 150px;
}
}
.sticky {
position: sticky;
top: 0;
background-color: #0ebac5;
color: white;
text-transform: capitalize;
text-align: center;
font-size: 1.2rem;
display: grid;
place-content: center;
}
Preview:
This example shows the default behavior of CSS position: sticky. The top: 0 sets the sticky element to stick to the top edge of its containing block (which is the nearest scrolling ancestor).
CSS position: sticky is a powerful way to create sticky element behavior on a webpage. It has become the standard approach due to its simplicity and efficiency, while JavaScript offers an alternative method for developers to achieve the same sticky element effect.
CSS native solution is often preferred for several reasons. Firstly, using CSS for sticky positioning is more straightforward and requires less code than the JavaScript alternative.
Using JavaScript, we leverage scroll event handlers to track the page’s offset. By dynamically calculating these offsets, we can implement logic that triggers the element to become sticky once a specific threshold is reached by the user. Let’s try to implement this and explore the behavior in action.
HTML:
CSS:
* {
margin: 0;
padding: 0;
font-family: 'Open Sans', sans-serif;
}
.tile {
background: #adf0f5;
height: 200px;
margin: 20px;
border-radius: 10px;
}
@media (width < 600px) {
.tile {
height: 150px;
}
}
.tile.sticky {
position: relative;
top: 0;
background-color: #0ebac5;
color: white;
text-transform: capitalize;
text-align: center;
font-size: 1.2rem;
display: grid;
place-content: center;
}
JavaScript:
document.addEventListener('DOMContentLoaded', function () {
let stickyElement = document.querySelector('.tile.sticky');
let initialOffset = stickyElement.offsetTop;
function handleScroll() {
let scrollY = window.scrollY || window.pageYOffset;
if (scrollY >= initialOffset) {
stickyElement.style.top = scrollY - initialOffset + 'px';
} else {
stickyElement.style.top = '0';
}
}
window.addEventListener('scroll', handleScroll);
});
Preview:
The disadvantage of using JavaScript scroll handling is it leads to performance issues, especially on mobile devices. Another problem it brings is scroll jank, which is noticeable from the above example and refers to a disjointed or stuttered scrolling experience. This can be especially noticeable during rapid scrolling on less powerful mobile devices.
Additionally, if any user has JavaScript disabled or has errors in the JavaScript code, the sticky behavior will not work. Meanwhile, relying on CSS brings more efficiency. This is why websites implementing a sticky element through JavaScript may experience quicker UI degradation than those using CSS.
Yes, the CSS position: sticky is commonly used when we want to set an element to stick at a particular position for a while and then acts like a normal element in most cases, flowing with the document’s layout.
Talking about its usage—it depends on what the website needs. If you have a long page with lots of content, having a sticky navigation bar can make it easy for users to access important links without scrolling all the way back up. It’s also handy for elements like headers or sidebars you want to keep visible while users explore the content.
However, not every website needs a sticky element. Some designs may work better without sticking elements, and that’s perfectly fine. It’s about finding the balance between functionality and aesthetics, tailoring the use of CSS position: sticky to enhance the user experience without unnecessary additions.
So, in a nutshell, CSS position: sticky is a useful property, but its frequency of use depends on each website’s specific needs and style.
Both the position: sticky and position: fixed are CSS positioning properties commonly used in web development for creating layouts and UI designs for making elements stick on the webpage.
While they may appear similar initially, a closer look reveals important differences in how they operate, each serving a distinct role in creating visually appealing and functional websites.
Let’s dive into the details of each with an example, discussing their roles, use cases, and how CSS position: sticky can be considered a better option in certain scenarios.
HTML:
<div class="container">
<div class="content one"></div>
<div class="content">
<div class="box fixed">I'm Fixed</div>
</div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</div>
<div class="container">
<div class="content one"></div>
<div class="content">
<div class="box sticky">I'm Sticky</div>
</div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</div>
CSS:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
font-family: 'Open Sans', sans-serif;
background-color: #eef5ff;
}
.container {
width: 50%;
}
.content {
background: #adf0f5;
height: 400px;
margin: 1em;
}
.content.one {
height: 100px;
}
.box {
width: 180px;
height: 100px;
font-size: clamp(16px, 4vw, 32px);
background-color: #0ebac5;
display: grid;
place-content: center;
}
.fixed {
position: fixed;
}
.sticky {
position: sticky;
top: 0;
}
Preview:
In the first container, we have a fixed element with the .fixed class. The CSS rule .fixed applies for position: fixed to this box, meaning it stays fixed in its position regardless of scrolling. While in the second container, we’ve got a sticky element with the .sticky class. The CSS rule .sticky applies for the position: sticky and sets top: 0.
From the above example, we can highlight some key differences:
| CSS position: sticky | CSS position: fixed |
|---|---|
| Initially part of the normal viewport flow. | Remains fixed relative to the viewport. |
| Sticks when it reaches the top of its container during scrolling. | Overlaps other content in the container. |
| Interacts with the flow of other elements until it becomes sticky. | It doesn't interact with the flow of other elements. |
These behaviors showcase the fundamental differences between position: fixed and position: sticky and demonstrate how each can be applied to create distinct effects in a web page layout.
CSS position: sticky is ideal when you want an element to be temporarily fixed within a container but still be part of the document flow. It’s useful when you want a header, sidebar, or other call-to-action (CTA) element to stay visible during scrolling but not necessarily fixed to the entire viewport.
CSS position: fixed can be used in scenarios such as when an element needs to be fixed relative to the viewport, regardless of its parent container’s scrolling. It’s ideal for things like navigation bars you want visible at all times, no matter how much the user scrolls. And when the element shouldn’t be affected by the scrolling of its parent container.
The only disadvantage with CSS position: fixed is that it can lead to issues on smaller screens or in responsive designs, as the fixed position covers the content area of the viewport.
Now that we’ve understood the fundamentals of CSS position: sticky, let’s dive into some real-world examples to see it in action and explore its applications.
A sticky table header is a design technique that keeps the header of a table fixed at the top of the viewport while the rest of the table content can be scrolled.
This is particularly useful when dealing with tables that have a large number of rows, allowing users to view column headers even as they scroll through the data.
Let’s create a sticky table header and see how CSS position: sticky works with an example.
HTML:
<body>
<h1>Sticky Table Header Example</h1>
<table class="table">
<thead class="table-header table-header-sticky">
<tr class="table-row">
<th class="table-cell" scope="col">
<p class="title">Compare All Features</p>
</th>
<th class="table-cell" scope="col">
<p class="title">Live</p>
<h2 class="pricing">₹499</h2>
<p class="info">Per month billed annually</p>
<select title="concurrency dropdown" class="custom-select">
<option>1 Parallel Test</option>
<option>2 Parallel Test</option>
<option>3 Parallel Test</option>
<option>4 Parallel Test</option>
<option>5 Parallel Test</option>
<option>6 Parallel Test</option>
<option>7 Parallel Test</option>
<option>8 Parallel Test</option>
<option>9 Parallel Test</option>
<option>10 Parallel Test</option>
<option>15 Parallel Test</option>
<option>20 Parallel Test</option>
<option>25 Parallel Test</option>
<option>> 25 Parallel Test</option>
</select>
<button>
<a href="https://billing.lambdatest.com/billing/plans">Buy Now</a>
</button>
</th>
<th class="table-cell" scope="col">
<p class="title">Real Device</p>
<h2 class="pricing">₹2,000</h2>
<p class="info">Per month billed annually</p>
<select title="concurrency dropdown" class="custom-select">
<option>1 Parallel Test</option>
<option>2 Parallel Test</option>
<option>3 Parallel Test</option>
<option>4 Parallel Test</option>
<option>5 Parallel Test</option>
<option>6 Parallel Test</option>
<option>7 Parallel Test</option>
<option>8 Parallel Test</option>
<option>9 Parallel Test</option>
<option>10 Parallel Test</option>
<option>15 Parallel Test</option>
<option>20 Parallel Test</option>
<option>25 Parallel Test</option>
<option>> 25 Parallel Test</option>
</select>
<button>
<a href="https://billing.lambdatest.com/billing/plans">Buy Now</a>
</button>
</th>
<th class="table-cell" scope="col">
<p class="title">Enterprise</p>
<span class="special-info"
>With LambdaTest Enterprise, your organization has access to
solutions built on Enterprise Grade Security, Privacy, and
Compliances</span
>
<p>ㅤ</p>
<span>25+ Parallel Tests</span>
<button>
<a href="https://billing.lambdatest.com/billing/plans"
>Contact Sales</a
>
</button>
</th>
</tr>
</thead>
<tbody class="table-body">
<tr class="table-row">
<td class="table-cell">Live Interactive testing time</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">Screenshot testing time</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">Responsive testing time</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">Emulators and Simulators</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">Access to 3000+ browsers & OS</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">Real mobile devices</td>
<td class="table-cell">✖️</td>
<td class="table-cell">Unlimited</td>
<td class="table-cell">Unlimited</td>
</tr>
<tr class="table-row">
<td class="table-cell">WCAG Compliant Accessibility Testing</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">
Network Throttling For Real World Test Scenarios
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">IP-based Geolocation Testing</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">GPS-based Geolocation Testing</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Automated Screenshot Testing</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">24x7 Support</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Premium support options</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Dedicated Solutions Engineer</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Dedicated Customer Success Manager</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Private Slack Channel</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Dedicated Training and Onboarding</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">
Localhost, Staging, and Private website testing
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Advanced Local Testing</td>
<td class="table-cell">✖️</td>
<td class="table-cell">✖️</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Browser’s Native Developer Tools</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
<tr class="table-row">
<td class="table-cell">Proprietary Mobile DevTools</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
<td class="table-cell">
<i class="fa fa-check" aria-hidden="true"></i>
</td>
</tr>
</tbody>
</table>
</body>
CSS:
/* STICKY TABLE HEADER */
.table-header-sticky {
position: sticky;
top: 0;
}
/* RESETS */
select,
button {
display: block;
width: 100%;
font-family: inherit;
}
/* OTHER STYLES */
body {
font-family: 'Inter', sans-serif;
padding: 2rem;
display: grid;
place-content: center;
background-color: #c9c9c9;
}
h1 {
text-align: center;
font-size: clamp(32px, 3vw, 52px);
margin: 0 0 2rem 0;
}
.table {
width: 100%;
max-width: 1200px;
border-collapse: collapse;
margin-bottom: 20px;
font-weight: 400;
background-color: #fdfdfd;
}
th,
tr {
font-weight: inherit;
}
.table-header .table-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
width: 100%;
}
.table-header button {
background-color: #bd4c00;
border: none;
outline: none;
color: #f2f2f2;
cursor: pointer;
border-radius: 6px;
margin-top: 0.5rem;
}
.table-header a {
color: inherit;
text-decoration: none;
}
.table-header a:visited,
.table-header a:active {
color: #f2f2f2;
}
.table-header button:focus {
outline: 2px solid #1d1d1d;
}
.table-header .table-row .table-cell {
padding: 1rem;
border: 1px solid #dddddd;
display: grid;
grid-template-rows: repeat(5, minmax(50px, auto));
gap: 5px;
background-color: #f2f2f2;
}
.table-body .table-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.table-body .table-row .table-cell {
border: 1px solid #dddddd;
padding: 1.2rem;
font-size: 14px;
}
.fa-check {
color: #0ab40a;
font-size: 1.3rem;
}
select {
padding: 5px;
border-radius: 6px;
margin-top: 0.5rem;
}
In this example, the .form-header-sticky class represents the styling for the form header to make it sticky. The position: sticky property is applied, and top: 0 ensures that the header remains at the top of the table.
We’ve already covered some basic yet important use cases of CSS position: sticky. However, the position: sticky property can also be used creatively for storytelling with modern CSS.
This involves creating an engaging and interactive narrative on a webpage. We can use earlier techniques, such as revealing hidden elements and sticky images with sidebars. Let’s understand how we can build this with an example.
HTML:
<body>
<div class="intro">
<p class="intro-1">Under the morning sun,</p>
<p class="intro-2">A cup of warmth awaits,</p>
<p class="intro-3">Brewed to perfection!</p>
</div>
<div class="coffee-story">
<p class="brewing-method">Brewing creativity with CSS</p>
<div class="story-content">
<p>Join me on a journey where code becomes a canvas!</p>
<div class="coffee-images">
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-1.avif"
/>
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-2.avif"
/>
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-3.avif"
/>
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-4.avif"
/>
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-5.avif"
/>
<img
src="https://raw.githubusercontent.com/AakashRao-dev/css-position-sticky-tuts-with-examples/main/7--storytelling/images/trail-6.avif"
/>
<p class="surprise-text">
Just like the perfect blend, coding can be a delightful surprise!
</p>
</div>
</div>
</div>
<div class="types-of-coffee">
<div class="coffee coffee-1">
<div class="img-container">
<img
src="https://github.com/AakashRao-dev/css-position-sticky-tuts-with-examples/blob/main/7--storytelling/images/Latte.png?raw=true"
alt=""
/>
</div>
<div class="content-text">
<h2>Latte</h2>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
</div>
</div>
<div class="coffee coffee-2">
<div class="img-container">
<img
src="https://github.com/AakashRao-dev/css-position-sticky-tuts-with-examples/blob/main/7--storytelling/images/Americano.png?raw=true"
/>
</div>
<div class="content-text">
<h2>Americano</h2>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
</div>
</div>
<div class="coffee coffee-3">
<div class="img-container">
<img
src="https://github.com/AakashRao-dev/css-position-sticky-tuts-with-examples/blob/main/7--storytelling/images/Cappuccino.png?raw=true"
/>
</div>
<div class="content-text">
<h2>Cappuccino</h2>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
<p>
<!-- Some Text -->
</p>
</div>
</div>
</div>
<div class="more-info">
<p>
Comfort in the presence of a mug of coffee, where each sip is a journey
into a world of imagination, steeped in rich and aromatic blends.
</p>
</div>
<div class="the-end">The End</div>
</body>
CSS:
:root {
--clr-1: #4b3826;
--clr-2: #2c1e18;
--clr-3: #9a7c5b;
--clr-4: #f5e0d3;
--clr-5: #554639;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
font-weight: 300;
background: linear-gradient(var(--clr-1), var(--clr-2));
min-height: 100vh;
color: rgba(0, 0, 0, 0.7);
margin: 0;
font-size: 24px;
}
p {
margin: 0;
}
img {
max-width: 100%;
}
.intro {
font-size: 3.5rem;
display: grid;
grid:
'hello hello' 75vh
'hope-you having-fun' 125vh / max-content 1fr;
gap: 15px;
margin-bottom: 60vh;
color: var(--clr-4);
}
.intro-1 {
grid-area: hello;
align-self: center;
position: sticky;
top: 2em;
margin-bottom: 1.5em;
}
.intro-2 {
grid-area: hope-you;
font-weight: 900;
font-style: italic;
position: sticky;
align-self: center;
top: 3.5em;
}
.intro-3 {
grid-area: having-fun;
align-self: end;
font-weight: 900;
font-style: italic;
}
.brewing-method {
text-align: center;
margin-bottom: 60vh;
}
.story-content {
width: 80%;
margin: 0 auto;
display: grid;
gap: 1em;
grid: 'text thumbnails' 1fr / 1fr 1fr;
margin-bottom: 100vh;
}
.story-content p {
position: sticky;
top: 20vh;
grid-area: text;
align-self: start;
font-size: 2rem;
color: var(--clr-4);
}
.brewing-method {
font-size: 5rem;
color: var(--clr-3);
}
.coffee-images {
grid-area: thumbnails;
margin-top: 60vh;
background: var(--clr-5);
padding: 0.3em;
position: relative;
}
.coffee-images img {
position: relative;
z-index: 3;
}
.coffee-images::after {
content: '';
position: absolute;
background: linear-gradient(var(--clr-5) calc(100% - 5em), transparent 95%);
inset: 0;
z-index: 2;
}
.surprise-text {
position: sticky;
bottom: 100px;
margin-top: 4em;
text-align: center;
line-height: 1.6;
font-weight: 900;
color: white;
font-size: 1.5rem !important;
}
.types-of-coffee {
max-width: 1200px;
background-color: var(--clr-2);
border-radius: 40px;
padding: 4rem 2rem;
margin: auto;
}
.coffee {
position: relative;
height: auto;
display: grid;
grid-template-columns: 1fr 1fr;
}
.coffee:not(:last-child) {
margin-bottom: 20vh;
}
.coffee h2 {
font-size: 4rem;
color: var(--clr-4);
}
.coffee p {
color: var(--clr-3);
font-size: 18px !important;
}
.coffee p:not(:last-child) {
margin-bottom: 1rem;
}
.coffee .img-container {
position: sticky;
top: 0;
align-self: start;
}
.coffee-2 .img-container {
order: 2;
}
.more-info {
background: url('https://github.com/AakashRao-dev/css-position-sticky-tuts-with-examples/blob/main/7--storytelling/images/More-Info.png?raw=true');
padding: 2em;
background-size: cover;
height: 200vh;
font-size: 2rem;
position: relative;
margin-top: 100vh;
}
.more-info p {
position: relative;
z-index: 2;
color: white;
position: sticky;
top: 2em;
}
.more-info::before {
content: '';
position: absolute;
inset: 0;
z-index: 1;
background: linear-gradient(var(--clr-3) 20%, transparent, white 85%);
}
.the-end {
background: white;
text-align: center;
padding: 25vh 0;
font-size: 5rem;
}
This example shows how creatively we can apply position: sticky to create an engaging and dynamic storytelling experience, guiding users through the narrative with visual and navigational elements that respond to their scrolling behavior.
As we built different real-world examples from the previous section, we saw that we could apply position: sticky for either top or bottom property. But now the question arises: what will happen if both top and bottom values are defined for a sticky element? Which one will take precedence for CSS position: sticky?
When CSS sticky encounters conflicting threshold values, it adheres to a precedence rule to prioritize one over the other. The rule works as follows:
These guidelines ensure that conflicting values are resolved in a consistent manner, giving preference to specific directions based on the developer’s specifications. Note that the direction mentioned above refers to writing direction. For example, Arabic is RTL (right to left), while English is LTR (left to right).
You can check out an article on CSS Writing Modes to learn more about the details of different writing directions and how it works.
When working with CSS position: sticky, developers often face a few issues. We will discuss these issues and their fixes in the next section.
CSS position: sticky is undoubtedly a valuable property to make any element stick. However, many beginners made mistakes while implementing it into CSS, leading to issues with CSS position: sticky not working properly.
A common issue is when a child element has the same height and width as its parent element. This gives the child element no room, keeping it in the same position.
As we can notice, the < div > element with class .sticky is wrapped inside an < div > element, which by default tries to take the same height and weight of its child to wrap, meanwhile making the sticky position not work as we want.
To fix this, we need to make the child element have a width and height less than its immediate parent to make it stick to move within the parent container. Another way to solve this issue can be by defining a fixed width and height (greater than the child) to the parent < div > of the sticky element. Doing so gives room for sticky elements to stick to their position inside the parent.
The adoption of position: sticky is not just a matter of trend; it’s about enhancing functionality and accessibility.
Sticky elements offer a smoother navigation experience, reducing the need for users to scroll back to access critical information instantly. This improves user satisfaction and can positively impact business metrics such as reduced bounce rates, longer session durations, and increased click-through rates.

And for the browser support of CSS position: sticky, it is supported by all major browsers as per CanIUse, allowing developers to use its power whenever they want.
Note: Test your websites for CSS across 3000+ environments. Try TestMu AI Today!
Another big issue many developers encounter when implementing CSS position: sticky is when overflow: hidden is set to the parent element of the sticky element.
When we use position: sticky on an element, we tell the browser to make an element stick to a specific position on the page when the user scrolls. However, for this to work, the browser needs to know where to stick it, and it usually looks for the nearest ancestor (parent) with a scrolling ability (like a scrollbar).
The position: sticky property relies on the scroll behavior of the document to trigger its sticky behavior. If an ancestor element of a sticky element has overflow: hidden, it can interfere with the scroll behavior and cause the sticky element not to stick properly.
This is because the ancestor element with overflow: hidden effectively hides the overflow content, and this can disrupt the normal scroll flow that position: sticky relies on.

In the example, the sidebar contains a sticky element. The overflow: hidden on the sidebar, is used to limit its height. However, this can interfere with the sticky positioning of the element inside. As you scroll down, you may notice that the sticky element logo doesn’t stay in its intended position due to the overflow: hidden property on the sidebar.

To fix this problem, we can use the overflow: clip property. This property is similar to overflow: hidden, which hides extra content but with a slight difference. The hidden value allows programmatic scrolling and creates a new block formatting context (BFC). At the same time, the clip completely disables any kind of scrolling and doesn’t establish a new block formatting context.
For an element with position: sticky to work correctly, it must be within a BFC. Setting overflow: hidden on a parent element creates a BFC, but it also prevents any elements inside from sticking to it, as they’re confined to that BFC.
So, when you use overflow: clip, it hides overflowing content just like hidden, but it doesn’t turn the element into a scroll container. In other words, it doesn’t allow the element to scroll programmatically. The window, or viewport, remains the default scroll container.
To put it simply, if you want to hide extra content without allowing any scrolling, use overflow: clip. This ensures that the window remains the main scroll area, and the element won’t become a scroll container.
Sticky positioned elements, such as sticky navigation menus, can enhance the user experience by providing persistent navigation or content that remains visible as the user scrolls.
However, they can also introduce potential accessibility challenges. Let’s learn about some accessibility issues associated with sticky navigation menus or headers and how we can tackle them using simple best practices.
To wrap it up, diving into CSS position: sticky allows developers to create awesome, user-friendly websites. We started by understanding the basics and seeing how CSS position: sticky is special and handy compared to its buddy CSS position fixed.
We explored some real-world examples and tried to build them from scratch. We also discussed the accessibility of the sticky navigation menu, sharing the best ways to handle it. We also learned about its browser support and compatibility across different browsers.
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance