Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 2 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /css/css-overflow/scroll-axis-lock.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<title>CSS Scroll Snap: scroll-axis-lock</title>
<link rel="help"
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/dom/events/scrolling/scroll_support.js"></script>
<style>
#scroller {
margin-left: 200px;
margin-top: 100px;
width: 200px;
height: 200px;
overflow: scroll;
border: 1px solid black;
scroll-axis-lock: none;
}
#content {
width: 1000px;
height: 1000px;
background: linear-gradient(45deg, white, black);
}
</style>
<div id="scroller">
<div id="content"></div>
</div>
<script>
async function run_test(t, input_source) {
await waitForCompositorReady();
const scroller = document.getElementById('scroller');
await waitForScrollReset(t, scroller);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 0);
let received_wheel_event = null;
// Scroll mostly vertically, with a small horizontal component.
// Move left (scroll right) by 2, up (scroll down) by 150.
// This steep angle would normally trigger vertical railing
// (horizontal scroll = 0).
// With scroll-axis-lock: none, it should not rail.
const bounds = scroller.getBoundingClientRect();
const start_x = bounds.left + bounds.width / 2;
const start_y = bounds.top + bounds.height / 2;
const delta_x = 2;
const delta_y = 150;
// We use tolerances because the final scroll offsets might not
// match the input deltas exactly. For touch, the initial gesture movement is
// affected by touch slop (which is platform-dependent), requiring a loose
// tolerance of 30 on the dominant Y axis. Wheel scrolls do not have slop,
// so we use a small tolerance of 1. For the minor X axis in the touch test,
// we also use a small tolerance so that locking (scrollLeft=0) is still
// disallowed.
const tolerance_x = 1;
const tolerance_y = (input_source === 'touch') ? 30 : 1;
const end_x = start_x - delta_x;
const end_y = start_y - delta_y;
const scrollend_promise =
waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller);
if (input_source === 'touch') {
await new test_driver.Actions()
.addPointer("finger", "touch")
.pointerMove(Math.round(start_x), Math.round(start_y))
.pointerDown()
.addTick()
.pause(100)
.pointerMove(Math.round(end_x), Math.round(end_y))
.addTick()
.pause(100) // Pause to avoid fling
.pointerUp()
.send();
} else if (input_source === 'wheel') {
scroller.addEventListener('wheel', (e) => {
received_wheel_event = e;
}, { once: true });
await new test_driver.Actions()
.addWheel("wheel")
.scroll(0, 0, Math.round(delta_x), Math.round(delta_y),
{origin: scroller})
.send();
}
// Wait for scroll to end.
await scrollend_promise;
assert_approx_equals(scroller.scrollTop, delta_y, tolerance_y,
"Should have scrolled vertically");
assert_approx_equals(
scroller.scrollLeft, delta_x, tolerance_x,
"Should have scrolled horizontally (not railed to Y)");
if (input_source === 'wheel') {
// The wheel delta will always be the unlocked value.
// With scroll-axis-lock: none, the wheel delta should match the scroll
// delta.
assert_not_equals(received_wheel_event, null,
"Should have received a wheel event");
assert_equals(received_wheel_event.deltaX, delta_x,
"wheel event deltaX should match sent delta");
assert_equals(received_wheel_event.deltaY, delta_y,
"wheel event deltaY should match sent delta");
}
}
promise_test(async t => {
await run_test(t, 'touch');
}, "scroll-axis-lock: none allows free diagonal touch scroll " +
"even with steep angle (no railing)");
promise_test(async t => {
await run_test(t, 'wheel');
}, "scroll-axis-lock: none allows free diagonal wheel scroll " +
"even with steep angle (no railing)");
</script>