blob: 13d816a062009742ab7db36026e115deb432734f [file] [log] [blame] [edit]
<!DOCTYPE html>
<title>@scroll-timeline element offset invalidation</title>
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#typedef-element-offset">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<style>
#scroller {
overflow: scroll;
width: 100px;
height: 100px;
}
#scroller > div {
height: 50px;
}
@keyframes expand {
from { width: 100px; }
to { width: 200px; }
}
@scroll-timeline timeline {
source: selector(#scroller);
start: selector(#offset1) end;
end: selector(#offset2) end;
}
#element {
width: 0px;
height: 20px;
animation: expand 1000s linear;
animation-timeline: timeline;
}
/* Ensure stable expectations if feature is not supported */
@supports not (animation-timeline:foo) {
#element { animation-play-state: paused; }
}
</style>
<div id=scroller></div>
<div id=element></div>
<p class=sibling1></p>
<p class=sibling2></p>
<script>
function setup() {
while (scroller.firstChild)
scroller.firstChild.remove();
for (let i = 0; i < 10; i++)
scroller.append(document.createElement('div'));
}
// The contents of the scroller look like this:
//
// +-------+
// | 50px | div (0)
// +-------+
// +-------+
// | 50px | div (1)
// +-------+
// +-------+
// | 50px | div (2)
// +-------+
// +-------+
// | 50px | div (3)
// +-------+
// +-------+
// | 50px | div (4)
// +-------+
// +-------+
// | 50px | div (5)
// +-------+
// +-------+
// | 50px | div (6)
// +-------+
// +-------+
// | 50px | div (7)
// +-------+
// +-------+
// | 50px | div (8)
// +-------+
// +-------+
// | 50px | div (9)
// +-------+
//
// The height of the scrollport is 100px.
function invalidation_test(func, description) {
promise_test(async (t) => {
setup();
await func();
}, description);
}
function remove(id) {
let old_element = document.getElementById(id);
if (old_element)
old_element.removeAttribute('id');
}
function reassign(id, element) {
remove(id);
element.setAttribute('id', id);
}
async function assert_element_width_at_scroll(expected_width, scroll) {
scroller.scrollTop = scroll;
await waitForNextFrame();
assert_equals(getComputedStyle(element).width, expected_width);
}
invalidation_test(async () => {
await assert_element_width_at_scroll('0px', 0);
}, 'Offsets missing');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
// [100, 150]
reassign('offset1', scroller.children[4]);
await assert_element_width_at_scroll('100px', 100);
}, 'Change first offset');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
// [50, 250]
reassign('offset2', scroller.children[7]);
await assert_element_width_at_scroll('125px', 100);
}, 'Change second offset');
invalidation_test(async () => {
// [50, 250]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[7]);
await assert_element_width_at_scroll('125px', 100);
// [0, 200]
reassign('offset1', scroller.children[2]);
reassign('offset2', scroller.children[4]);
await assert_element_width_at_scroll('150px', 50);
}, 'Change both offsets');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
remove('offset1');
await assert_element_width_at_scroll('0px', 0);
}, 'Remove first offset');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
remove('offset2');
await assert_element_width_at_scroll('0px', 0);
}, 'Remove second offset');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
remove('offset1');
remove('offset2');
await assert_element_width_at_scroll('0px', 0);
}, 'Remove both offsets');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
reassign('offset1', document.querySelector('.sibling1'));
await assert_element_width_at_scroll('0px', 0);
}, 'Reassign first offset to sibling of scroller');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
reassign('offset2', document.querySelector('.sibling2'));
await assert_element_width_at_scroll('0px', 0);
}, 'Reassign second offset to sibling of scroller');
invalidation_test(async () => {
// [50, 150]
reassign('offset1', scroller.children[3]);
reassign('offset2', scroller.children[5]);
await assert_element_width_at_scroll('150px', 100);
reassign('offset1', document.querySelector('.sibling1'));
reassign('offset2', document.querySelector('.sibling2'));
await assert_element_width_at_scroll('0px', 0);
}, 'Reassign both offsets to sibling of scroller');
</script>