FloatSidebar.js icon indicating copy to clipboard operation
FloatSidebar.js copied to clipboard

Fix long sidebar jumping issue with custom viewports

Open Copilot opened this issue 5 months ago • 0 comments

Problem

Long sidebars were jumping when using a custom scrollable element as the viewport instead of the default window viewport. This issue occurred specifically when scrolling down and the sidebar transitioned to bottom-fixed positioning.

The problem was demonstrated in the provided JSFiddle examples:

  • ✅ Default viewport (window/document): worked correctly
  • ❌ Custom viewport (scrollable element): sidebar jumped during transitions

Root Cause

The issue was in the computeElementDimensions function in src/dimension-observer.js. The function calculated element positions by adding viewportTop to getBoundingClientRect() values, but this approach had a coordinate system mismatch:

  • getBoundingClientRect() always returns positions relative to the browser window
  • For window viewport: viewportTop is pageYOffset (document scroll) ✅
  • For custom viewport: viewportTop is element.scrollTop (internal scroll) ❌

This mismatch caused incorrect position calculations, leading to the jumping behavior.

Solution

Modified computeElementDimensions to handle custom viewports correctly:

Window viewport (unchanged):

return {
  top: rect.top + viewportTop,  // rect.top + pageYOffset
  bottom: rect.bottom + viewportTop,
  height: rect.height
}

Custom viewport (fixed):

return {
  top: rect.top + documentScrollTop,  // rect.top + document scroll
  bottom: rect.bottom + documentScrollTop,
  height: rect.height
}

Changes

  • Updated computeElementDimensions to accept $viewport parameter and differentiate between window and custom element viewports
  • Updated all function calls to pass the viewport parameter
  • Added comprehensive tests in test/custom-viewport.test.js to validate the fix and prevent regressions

Testing

The fix has been validated with:

  • New tests that reproduce the jumping issue and verify it's resolved
  • Existing tests continue to pass (no regressions for window viewport usage)
  • Tests cover various scroll positions and sidebar state transitions

This resolves the coordinate system mismatch that caused the jumping behavior described in the issue.

[!WARNING]

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • accounts.google.com
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3504 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,1838967325958793765,12419158326437385471,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
    • Triggering command: /opt/google/chrome/chrome --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation --export-tagged-pdf --force-color-profile=srgb --generate-pdf-document-outline --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,RenderDocument,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes --enable-features=PdfOopif --headless=new --hide-scrollbars --mute-audio --disable-extensions --remote-debugging-port=0 --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl about:blank (dns block)
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=4083 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,9800445507747328728,9185029744226650521,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
  • android.clients.google.com
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=4083 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,9800445507747328728,9185029744226650521,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
    • Triggering command: /opt/google/chrome/chrome --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation --export-tagged-pdf --force-color-profile=srgb --generate-pdf-document-outline --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,RenderDocument,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes --enable-features=PdfOopif --headless=new --hide-scrollbars --mute-audio --disable-extensions --remote-debugging-port=0 --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl about:blank (dns block)
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5589 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-ZPS97y --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,2102261624699585542,8829259679314052806,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
  • clients2.google.com
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3504 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,1838967325958793765,12419158326437385471,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
    • Triggering command: /opt/google/chrome/chrome --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation --export-tagged-pdf --force-color-profile=srgb --generate-pdf-document-outline --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,RenderDocument,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes --enable-features=PdfOopif --headless=new --hide-scrollbars --mute-audio --disable-extensions --remote-debugging-port=0 --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl about:blank (dns block)
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=4083 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,9800445507747328728,9185029744226650521,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
  • safebrowsingohttpgateway.googleapis.com
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3504 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,1838967325958793765,12419158326437385471,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
    • Triggering command: /opt/google/chrome/chrome --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation --export-tagged-pdf --force-color-profile=srgb --generate-pdf-document-outline --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,RenderDocument,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes --enable-features=PdfOopif --headless=new --hide-scrollbars --mute-audio --disable-extensions --remote-debugging-port=0 --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl about:blank (dns block)
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=4083 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,9800445507747328728,9185029744226650521,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
  • www.google.com
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3504 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,1838967325958793765,12419158326437385471,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)
    • Triggering command: /opt/google/chrome/chrome --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation --export-tagged-pdf --force-color-profile=srgb --generate-pdf-document-outline --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,RenderDocument,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes --enable-features=PdfOopif --headless=new --hide-scrollbars --mute-audio --disable-extensions --remote-debugging-port=0 --user-data-dir=/tmp/puppeteer_dev_chrome_profile-MJK2ap --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl about:blank (dns block)
    • Triggering command: /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=4083 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-f9li5D --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,9800445507747328728,9185029744226650521,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Long sidebar jumping issue</issue_title> <issue_description>Hello, thank you for creating this plugin, it's worked smoothly for the most part when the viewport is the window/document. However, long sidebars create a jump when the viewport is a specified element.

Please note that in the following demos, the top bar's height is 100px and the top gap is 20px.


[1.] Default viewport (window/document), working great ✅ : jsfiddle.net/glenthemes/p3ejo8u1/

https://github.com/user-attachments/assets/12159918-4610-451f-b58c-07c184ba1904


[2.] Specified viewport (custom scrollable element), has a jump ❌ :

jsfiddle.net/glenthemes/qhjpfs52

https://github.com/user-attachments/assets/20b39457-3072-4cc9-836e-50c3fa610a02


Interestingly, scrolling down and sticking to the bottom seems to trigger this issue, and scrolling up has no issue.

Any help or advice is greatly appreciated, thank you! :relaxed: </issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes vursen/FloatSidebar.js#17

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot avatar Sep 29 '25 05:09 Copilot