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:
- Adding additional transitions to the elements below the title element.
- changing the initial position of the title to 'absolute'
- Instead of adding in a class with position:sticky, I tried using position:absolute and top:0px.
- I have seen this post, but not sure how to apply it to mu issue.
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' >TITLE</div>
<div id='topTitleMarker' ></div>
<div >TEST</div>
CodePudding user response:
Problems
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.
Changes
JavaScript
- Removed
scrollTop
-- it wasn't being used - Moved and consolidated
getPosition()
over to the event handler - Also changed the reference element for
.getBoundingClientRect().top
from.topTitleMarker
to<h1>
(in OP it's.title
)
CSS
- Removed
transition
from<h1>
- Added
animation: grow 1s forwards ease-out;
to<h1>
- Added
animation: shrink 1s forwards ease-out;
to.header
- For smoother animation
animation
and@keyframes
are used for shrinking and growing of<h1>
HTML
- Removed everything from OP and added a
<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>