Fix window repaint on JS scroll events - move to CSS (#63) - #184
Open
wakqasahmed wants to merge 2 commits into
Open
Fix window repaint on JS scroll events - move to CSS (#63)#184wakqasahmed wants to merge 2 commits into
wakqasahmed wants to merge 2 commits into
Conversation
…-com#63) The sticky/compact-header effect was implemented as a $(window).scroll() handler that wrote several inline styles (position, top, display, bottom) and read $(".mainContainer").position() on every single scroll event, forcing a synchronous layout and repaint of the page on every scroll tick (visible as a Long Task dominated by Painting/Rendering in the DevTools Performance panel). Replace it with an IntersectionObserver watching #toolbar, which only fires on the actual threshold crossing, and drive the visual states with a single .header-stuck CSS class instead of per-tick inline style writes. The sidePanel's dynamic left offset is now computed once per state transition (and on resize) via a CSS custom property rather than on every scroll event.
Author
Author
Collaborator
|
@wakqasahmed I tested this locally and it introduced a behavior change. The concept overall is good and thanks for submitting this performance enhancement. However, when you scroll back up to the top of the page, the header remains in its compressed form. Where on the production website, the header correctly expands back to normal when you scroll back up |
…nah-com#184) The IntersectionObserver watched #toolbar, but .header-stuck hides #toolbar via display:none once triggered. A hidden element has no layout box, so it can never re-intersect the viewport, and the observer could only ever add the stuck state, never remove it. Observe a dedicated #header-sentinel marker instead, which the header-stuck CSS never touches, so it keeps crossing the boundary in both directions.
Author
|
Good catch, thanks for testing it locally. The observer was watching #toolbar, but the stuck-state CSS hides #toolbar once triggered, so it could never re-intersect the viewport and the header never un-stuck. Pushed a fix that watches a small dedicated marker instead, which stays in the layout regardless of header state. Let me know if it still doesn't behave right on your end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #63
Problem
The sticky/compact-header effect (shrinking the banner, hiding the toolbar, fixing the header to the top, and repositioning the side panel) was driven by a
$(window).scroll()jQuery handler that ran on every scroll event. On each tick it:position,top,display,bottom) unconditionally, even when the state hadn't changed, and$(".mainContainer").position(), which forces a synchronous layout read.That combination produces a forced synchronous layout + full repaint on every scroll pixel, which is exactly what the attached Chrome DevTools Performance profile in the issue shows: a Long Task dominated by
Painting/Renderingtime while scrollingsunnah.com/riyadussalihin/18.Verified the same
$(window).scroll(...)handler (public/js/sunnah.js, previously lines 462-485) is still present, unchanged, in currentmaster.Fix
IntersectionObserveron#toolbar, which only fires when the header actually crosses the same ~25px threshold the old code polled for on every tick — not on every scroll event..header-stuckCSS class (public/css/all.css) instead of ad-hoc inline style writes.leftoffset (previously recomputed via a layout-forcing.position()call on every scroll event) is now computed once per state transition and on resize, via a CSS custom property (--sidePanel-left).No visual behavior change intended — same thresholds, same classes/styles, same effect — only removed the per-scroll-tick DOM writes and forced layout reads.
Test plan
node --check public/js/sunnah.jspasses (syntax valid)/riyadussalihin/18before merging)