Reputation: 226
Problem: I have a title container element that starts off as 100vh to act as a landing page. When the user scrolls it should reduce the title container element to 15vh and stick it to the top of the window. I've essentially done that but the transition isn't very smooth and jumps around when the user doesn't scroll heaps.
Intended outcome: When the user scrolls at all, it should trigger the title element to reduce in size to 15vh and stick to the top of the window with a smooth transition.
Things tried:
I have tried to give an example below with the minimum amount of code.
window.addEventListener(
'scroll',
function() {
let scrollTop =
window.pageYOffset ||
(document.documentElement || document.body.parentNode || document.body)
.scrollTop;
getPosition();
console.log(getPosition());
if (getPosition() <= 0) {
this.document.getElementById('title').classList.add('header');
} else {
this.document.getElementById('title').classList.remove('header');
}
},
false
);
function getPosition() {
element = document.getElementById('topTitleMarker');
var clientRect = element.getBoundingClientRect();
return clientRect.top;
}
.title {
padding: 0;
margin: 0;
height: 100vh;
font-weight: bold;
font-family: 'Titillium Web', sans-serif;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
background-color: black;
-webkit-transition: all 1s linear;
-moz-transition: all 1s linear;
-o-transition: all 1s linear;
transition: all 1s linear;
color: white;
}
.header {
top: 0px;
height: 15vh;
position: sticky;
}
body {
background-color: white;
height: 500vh;
-ms-overflow-style: none;
scrollbar-width: none;
border-bottom: 5px solid white;
/* overflow: hidden; */
}
.topTitleMarker {
top: 1px;
position: absolute;
}
.test {
margin-top: 15vh;
}
<div id='title' class="title">TITLE</div>
<div id='topTitleMarker' class="topTitleMarker"></div>
<div class="test">TEST</div>
Upvotes: 4
Views: 2334
Reputation: 43880
I think the jerkiness in the scrolling was because of the .topTitleMarker
was referenced as the top of scrolling element with .getBoundingClientRect().top
and the transition
was based on the height of .title
when it increases at 100vh but there isn't a transition for when .title
shrinks. Moreover, transition
is a process heavy animation, but your animation is a simple one so no worries there.
JavaScript
scrollTop
-- it wasn't being usedgetPosition()
over to the event handler.getBoundingClientRect().top
from
.topTitleMarker
to <h1>
(in OP it's .title
)CSS
transition
from <h1>
animation: grow 1s forwards ease-out;
to <h1>
animation: shrink 1s forwards ease-out;
to .header
animation
and @keyframes
are used for shrinking and growing of <h1>
HTML
<h1>
window.addEventListener('scroll', headerHeight);
function headerHeight(event) {
const title = document.querySelector('h1');
if (title.getBoundingClientRect().top <= 0) {
title.classList.add('header');
} else {
title.classList.remove('header');
}
};
@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:wght@300;700&display=swap');
html {
font: 300 2ch/1.25 'Titillium Web';
}
body {
height: 500vh;
}
h1 {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
font-weight: 700;
color: white;
background-color: black;
animation: grow 1s forwards ease-out;
}
.header {
position: sticky;
top: 0px;
height: 15vh;
animation: shrink 1s forwards ease-out;
}
@keyframes grow {
0% {
height: 15vh
}
100% {
height: 100vh
}
}
@keyframes shrink {
0% {
height: 100vh
}
100% {
height: 15vh
}
}
<h1>TITLE</h1>
Upvotes: 3