JSFiddle - React, Tailwind, and code Playground
Sticky header and footer with shadow when above content.
by Travis Almand
HTML
<header></header>
<main>
<div class="top-buffer"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="bottom-buffer"></div>
</main>
<footer></footer>
SCSS
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html,
body {
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
header {
background-color: rgba(255, 255, 255, 0.5);
border-bottom: 1px solid gainsboro;
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.5);
height: 64px;
left: 0;
position: fixed;
top: 0;
transition: box-shadow 250ms;
width: 100%;
&.shadow {
box-shadow: 0 0 16px 0 rgba(0, 0, 0, 0.5);
}
}
main {
flex-grow: 1;
.top-buffer {
height: 64px;
}
.content {
background-color: gainsboro;
height: 300px;
margin: 20px;
}
.bottom-buffer {
height: 64px;
}
}
footer {
background-color: rgba(255, 255, 255, 0.5);
border-top: 1px solid gainsboro;
bottom: 0;
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.5);
height: 64px;
left: 0;
position: fixed;
transition: box-shadow 250ms;
width: 100%;
&.shadow {
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
}
}
.bottom-buffer {
margin-bottom: 1px;
}
JavaScript
const header = document.querySelector('header');
const footer = document.querySelector('footer');
const topBuffer = document.querySelector('.top-buffer');
const bottomBuffer = document.querySelector('.bottom-buffer');
const options = {
root: null,
rootMargin: '0px',
threshold: 1
}
const observer = new IntersectionObserver(callback, options);
observer.observe(topBuffer);
observer.observe(bottomBuffer);
function callback (entries, observer) {
entries.forEach(entry => {
const target = entry.target;
if (entry.target === topBuffer) {
header.classList.toggle('shadow', !entry.isIntersecting);
}
if (entry.target === bottomBuffer) {
console.log(entry);
footer.classList.toggle('shadow', !entry.isIntersecting);
}
});
}