Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/scss/tabulator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ $rangeHeaderTextHighlightBackground: #000000 !default; //header text color when
width:100%;
white-space: nowrap;
overflow:auto;
overflow-anchor: none;
-webkit-overflow-scrolling: touch;

&:focus{
Expand Down
21 changes: 21 additions & 0 deletions test/e2e/overflow-anchor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test, expect } from "@playwright/test";
import { join } from "path";

// Regression coverage for disabling browser scroll anchoring on the table
// holder. The virtual renderer manages scrollTop/padding itself; Chrome's
// scroll anchoring double-compensates when rows are inserted above the
// viewport, causing drift on scroll-up. The fix sets overflow-anchor:none on
// .tabulator-tableholder. This guards that the rule survives in the built CSS
// and is applied by the browser.
test.describe("table holder disables browser scroll anchoring", () => {
test("computed overflow-anchor is none", async ({ page }) => {
await page.goto(`file://${join(__dirname, "scroll-jump.html")}`);
await page.waitForSelector(".tabulator-tableholder");

const value = await page
.locator(".tabulator-tableholder")
.evaluate((el) => getComputedStyle(el).overflowAnchor);

expect(value).toBe("none");
});
});
28 changes: 17 additions & 11 deletions test/e2e/scroll-jump.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ import { join } from "path";
// HOW THE JUMP IS MEASURED
// When you scroll up by D pixels the visible content must move DOWN by exactly
// D. We track one identifiable row element across a scroll-up step and compare
// how far it moved on screen ("moved") with how far the holder actually
// scrolled ("scrolled"). For a correct virtual DOM the row is glued to the
// content so moved === scrolled; "jump = moved - scrolled" is therefore the
// number of pixels the content shifted underneath the scroll position. This
// metric is independent of whether scrollTop itself is trustworthy (it isn't,
// once the bug fires).
// how far it moved on screen ("moved") with the D we asked for, so
// "jump = moved - requested" is the number of pixels the content shifted that
// the user did not ask for.
//
// We deliberately do NOT compare against the holder's own scrollTop delta.
// A virtual renderer revises its total scrollHeight as it measures real row
// heights, and scrollTop is measured from the top of that changing document, so
// it shifts by the height correction while nothing on screen moves at all. That
// makes "moved - scrolled" report a jump for a view that is perfectly steady.
// The requested delta has no such term.
//
// The companion "gentle scrolling" test below demonstrates that this metric
// reads ~0 for well-behaved scrolling, so a large reading is a real jump.
Expand Down Expand Up @@ -133,7 +137,7 @@ async function scrollUpAndMeasure(
id: beforeScrolling.id,
moved: Math.round(moved),
scrolled: Math.round(scrolled),
jump: Math.round(moved - scrolled),
jump: Math.round(moved - delta),
});
}
}
Expand Down Expand Up @@ -169,9 +173,8 @@ test.describe("Vertical scroll jumping with variable height rows (#3654)", () =>
// Sanity: the scroll-up actually moved content.
expect(jumps.length).toBeGreaterThan(0);

// The tracked row should stay glued to the content (move by exactly the
// scroll distance, give or take sub-pixel rounding). A larger reading
// is the #3654 jump.
// The tracked row should move by exactly the distance we scrolled up,
// give or take sub-pixel rounding. A larger reading is the #3654 jump.
expect(worstJump).toBeLessThanOrEqual(20);
});

Expand Down Expand Up @@ -218,9 +221,12 @@ test.describe("Vertical scroll jumping with grouped variable height rows (#3654)
await page.waitForTimeout(50);

// Track data rows only, never the group header rows.
// The step must stay well under the ~275px viewport: a step that turns
// over the whole rendered window leaves no row present both before and
// after the scroll, so nothing can be measured.
const jumps = await scrollUpAndMeasure(
page,
250,
80,
40,
".tabulator-row:not(.tabulator-group)",
);
Expand Down
Loading