Listening for scrolling events along with a sticky element whose height changes can lead to a glitchy never-ending scroll experience

I am facing an issue with an element positioned at the top of the screen using position:sticky;. I have implemented a JS scroll eventlistener to add a stuck class when the element becomes stuck (scroll Y is greater than 0).

The presence of the stuck class causes an element inside the sticky element, which has CSS transition, to decrease in height.

However, scrolling very slowly results in the height change causing the scrollY to suddenly jump back to zero, removing the stuck class. This creates a jolty scrolling loop that continues infinitely until you scroll faster and outscroll the problem.

I am seeking advice on how to achieve smooth scrolling when using position: sticky. You can view the issue live here:

https://jsfiddle.net/27rzba5v/

Answer №1

To address this issue, consider modifying the element's height with a transform on .wrap instead of transitioning directly. This approach leverages the GPU for smoother animations without causing the browser to repaint unnecessarily.

var lastScrollY = 0;
var ticking = false;

window.addEventListener('scroll', function(e) {
lastScrollY = window.scrollY;
if ( ! ticking ) {
window.requestAnimationFrame(function() {
console.log( lastScrollY );
if ( lastScrollY > 0 ) {
document.body.classList.add('stuck');
} else {
document.body.classList.remove('stuck');
}
ticking = false;
});
ticking = true;
}
} );
body {
margin: 0;
}
.wrap {
background: #666;
text-align: center;
position: sticky;
top: 0;
  transition: 0.5s; /* Move transition here */
  transform-origin: top left; /* Ensure proper transformation origin */
}
.block {
width: 80px;
height: 80px;
background: red;
display: block;
}
.stuck .wrap { /* Apply transformation to wrap instead of block */
transform: scaleY(.5); /* Adjust scale instead of height */
}
<div class="wrap">
<span class="block"></span>
</div>

Lorem ipsum dolor sit amet, consectetur adipiscing elit...
<!-- Additional content can be included as needed -->

If transitioning the element's height is necessary, you can mitigate dimension changes by using a buffer container for offsetting effects.

var lastScrollY = 0;
var ticking = false;

window.addEventListener('scroll', function(e) {
lastScrollY = window.scrollY;
if ( ! ticking ) {
window.requestAnimationFrame(function() {
console.log( lastScrollY );
if ( lastScrollY > 0 ) {
document.body.classList.add('stuck');
} else {
document.body.classList.remove('stuck');
}
ticking = false;
});
ticking = true;
}
} );
body {
margin: 0;
}
.wrapoffset { /* Introduce new sticky element for containment */
  height: 80px;
  position: sticky;
  top: 0;
  width: 100%;
}
.wrap {
background: #666;
text-align: center;
  width: 100%;
}
.block {
  height: 80px;
width: 80px;
background: red;
display: block;
transition: 0.5s;
}
.stuck .block {
height: 40px;
}
<div class="wrapoffset"> 
  <div class="wrap">
    <span class="block"></span>
  </div>
</div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit...
<!-- Additional content can be included as needed -->

To further optimize performance, explore using IntersectionObserver with a polyfill rather than relying solely on scroll events.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Send information and showcase it on the following screen using ReactJS

Having recently started using ReactJS for a front-end development project, I encountered a challenge that I need help with. I want to prompt the user for their name using an input field after a question like "What is your name?". Once the user inputs their ...

Can I inform the interpreter that my function in TypeScript specifically handles undefined and null values?

Consider a scenario where there is a method isEmpty that verifies if a value is empty, null, or undefined, and returns true accordingly. In TypeScript, this method may not effectively communicate to the interpreter, leading to a red underline in IDEs like ...

Using *ngFor index value results in an error message saying "The call stack size has reached its maximum limit."

Check out this StackBlitz demo I have a simple view where I'm looping over HTML using Angular's *ngFor directive. To show more or less content, I'm using the ngx-bootstrap collapse component. The problem is that when I collapse one button, ...

The Discord.js script fails to send embedded messages as intended

Issue with sending embedded messages using Discord.js code Embed code not functioning properly: Error code received: ...

Learn how to troubleshoot and resolve a bug in the mobile Chrome browser that pertains to the position fixed feature

On the mobile version of Firefox, everything works perfectly. However, there seems to be a bug in Chrome with the fixed positioning. When scrolling, the header should change from absolute to fixed and the height should go from 65 to 35 pixels. Unfortunatel ...

Adjusting the spaces between the grid elements in Bootstrap 3 to improve the

Can you help me figure out a way to increase the spacing between grid elements while keeping the style of .col-md-4 and .col-md-8 intact? <div class="row" > <div class="col-md-4" style="height:250px;">grid1</div> <div class= ...

Detecting changes to DOM elements without using jQueryResponding to DOM element

Suppose I have the following HTML structure: <div id='content'></div> I want to receive an alert when there are height mutations on this element. I thought about using the MutationObserver class for this, but I encountered a specifi ...

Displaying content on the <div> element

Looking for recommendations for a jQuery plugin or JavaScript solution that allows me to load a full "view" into a <div> when a user clicks on a link. The challenge I'm facing is that I have 8 pages, with the Homepage consisting of 3 divisions: ...

Unable to load page redirection

I am experiencing an issue with this page not redirecting to the appropriate mobile or desktop page when accessed. Below is the code snippet in question: <html> <head> <title>Loading...</title> </head> < ...

"Using the fetch Prototype.json() method can lead to the alteration or corruption of the

For the past week, I've been struggling with a seemingly impossible issue in my Javascript code: The problem arises when trying to retrieve data from the server using fetch: fetch(this.props.url, { method: 'POST', b ...

Cut off a string from the start

I'm using the text-overflow: ellipsis property in a div to shorten lengthy text values. Since there is no white space in the URL, I want to prevent the overflow from increasing the width of the div. What I want to achieve is to display the following: ...

Mirror the input text to another input within a for loop

I have a list of questions displayed, each with an input field for entering a phone number. How can I use jQuery or JavaScript in a for-loop to mirror the text entered in the first phone input box to all subsequent phone input boxes? ..Enter your phone... ...

limit mongoose search results to a specific year

Would it be possible to add an option for the api user to filter the wine query by year? However, if no year is specified, mongoose should not return an empty array. The same applies to the price property. For example, http://localhost:1234/api/wine?year= ...

Leveraging Vue js components while utilizing it from a content delivery network (CDN

I'm attempting to utilize the ButtonCounter component as a demonstration (source: https://vuejs.org/guide/essentials/component-basics.html#defining-a-component), but I am facing difficulties in getting it to function properly. I am utilizing Vue.js 3 ...

The persistent presence of the Dropup Bootstrap class ensures that it remains active and visible at all

The dropdown-item class functions correctly only when used with the dropdown class, but does not work with the dropup class. The dropup feature fails to function after clicking on all submenu items. This is because all dropdown-items become active and v ...

What is the best way to locate the position of an element within an Array with underscore.js?

I need assistance with finding the index of a specific value within an array using underscore.js. Here is the scenario I am facing: var array = [{'id': 1, 'name': 'xxx'}, {'id': 2, 'name': &a ...

What are some solutions for managing SubPixel Handling issues on an iPhone?

Issue: I am currently in the process of developing a PhoneGap/Cordova app for both iOS and Android using jQuery Mobile. To incorporate a calendar feature into my app, I decided to create my own rather than use existing plugins due to not finding any that m ...

Utilizing HTML5 to showcase the techniques of character creation in writing

Hello there, I am a newcomer to HTML5 and have a project in mind to showcase how a character is written by hand in the correct order. I currently have this code to generate a Chinese character using canvas. However, I am wondering if there is a way to dra ...

Tips for exchanging JavaScript variables with PHP using AJAX

Hey there, I'm new to JavaScript and I've hit a roadblock with passing variables to PHP using Ajax. <script> $date = "123"; $.ajax({ url: './record.php', type: "POST", ...

Create custom dynamic asset tags in AngularJS inspired by Mixture.io's features for seamless HTML templating

Curious about the potential for creating dynamic asset tags within Angular and, if so, the method to achieve this. Here's the backstory: I've been utilizing Mixture.io for templating and have become accustomed to its seamless and adaptable natur ...