mirror of
https://github.com/servo/servo.git
synced 2025-10-13 23:10:20 +01:00
679 lines
22 KiB
HTML
679 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<title>The animation-timeline: scroll-timeline-name</title>
|
|
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
|
|
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/rewrite#scroll-timelines-named">
|
|
<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/6674">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/web-animations/testcommon.js"></script>
|
|
<script src="support/testcommon.js"></script>
|
|
<style>
|
|
@keyframes anim {
|
|
from { translate: 50px; }
|
|
to { translate: 150px; }
|
|
}
|
|
#target {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
.square {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
.square-container {
|
|
width: 300px;
|
|
height: 300px;
|
|
}
|
|
.scroller {
|
|
overflow: scroll;
|
|
}
|
|
.content {
|
|
inline-size: 100%;
|
|
block-size: 100%;
|
|
padding-inline-end: 100px;
|
|
padding-block-end: 100px;
|
|
}
|
|
</style>
|
|
<body>
|
|
<div id="log"></div>
|
|
<script>
|
|
"use strict";
|
|
|
|
setup(assert_implements_animation_timeline);
|
|
|
|
function createScroller(t, scrollerSizeClass) {
|
|
let scroller = document.createElement('div');
|
|
let className = scrollerSizeClass || 'square';
|
|
scroller.className = `scroller ${className}`;
|
|
let content = document.createElement('div');
|
|
content.className = 'content';
|
|
|
|
scroller.appendChild(content);
|
|
|
|
t.add_cleanup(function() {
|
|
content.remove();
|
|
scroller.remove();
|
|
});
|
|
|
|
return scroller;
|
|
}
|
|
|
|
function createTarget(t) {
|
|
let target = document.createElement('div');
|
|
target.id = 'target';
|
|
|
|
t.add_cleanup(function() {
|
|
target.remove();
|
|
});
|
|
|
|
return target;
|
|
}
|
|
|
|
function createScrollerAndTarget(t, scrollerSizeClass) {
|
|
return [createScroller(t, scrollerSizeClass), createTarget(t)];
|
|
}
|
|
|
|
// -------------------------
|
|
// Test scroll-timeline-name
|
|
// -------------------------
|
|
|
|
promise_test(async t => {
|
|
let target = document.createElement('div');
|
|
target.id = 'target';
|
|
target.className = 'scroller';
|
|
let content = document.createElement('div');
|
|
content.className = 'content';
|
|
|
|
// <div id='target' class='scroller'>
|
|
// <div id='content'></div>
|
|
// </div>
|
|
document.body.appendChild(target);
|
|
target.appendChild(content);
|
|
|
|
target.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
target.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
content.remove();
|
|
target.remove();
|
|
}, 'scroll-timeline-name is referenceable in animation-timeline on the ' +
|
|
'declaring element itself');
|
|
|
|
promise_test(async t => {
|
|
let [parent, target] = createScrollerAndTarget(t, 'square-container');
|
|
|
|
// <div id='parent' class='scroller'>
|
|
// <div id='target'></div>
|
|
// <div id='content'></div>
|
|
// </div>
|
|
document.body.appendChild(parent);
|
|
parent.insertBefore(target, parent.firstElementChild);
|
|
|
|
parent.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
parent.scrollTop = 100; // 50%, in [0, 200].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, "scroll-timeline-name is referenceable in animation-timeline on that " +
|
|
"element's descendants");
|
|
|
|
promise_test(async t => {
|
|
let [sibling, target] = createScrollerAndTarget(t);
|
|
|
|
// <div id='sibling' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
document.body.appendChild(sibling);
|
|
document.body.appendChild(target);
|
|
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
sibling.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, "scroll-timeline-name is referenceable in animation-timeline on that " +
|
|
"element's following siblings");
|
|
|
|
promise_test(async t => {
|
|
let [sibling, target] = createScrollerAndTarget(t);
|
|
let parent = document.createElement('div');
|
|
|
|
// <div id='sibling' class='scroller'> ... </div>
|
|
// <div id='parent'>
|
|
// <div id='target'></div>
|
|
// </div>
|
|
document.body.appendChild(sibling);
|
|
document.body.appendChild(parent);
|
|
parent.appendChild(target);
|
|
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
sibling.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
parent.remove();
|
|
}, "scroll-timeline-name is referenceable in animation-timeline on that " +
|
|
"element's following siblings' descendants");
|
|
|
|
// FIXME: We may use global scope for scroll-timeline-name.
|
|
// See https://github.com/w3c/csswg-drafts/issues/7047
|
|
promise_test(async t => {
|
|
let [sibling, target] = createScrollerAndTarget(t);
|
|
|
|
// <div id='target'></div>
|
|
// <div id='sibling' class='scroller'> ... </div>
|
|
document.body.appendChild(target);
|
|
document.body.appendChild(sibling);
|
|
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
sibling.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '50px',
|
|
'Animation with unknown timeline name holds current time at zero');
|
|
}, "scroll-timeline-name is not referenceable in animation-timeline on that " +
|
|
"element's previous siblings");
|
|
|
|
promise_test(async t => {
|
|
let [sibling, target] = createScrollerAndTarget(t);
|
|
let parent = document.createElement('div');
|
|
parent.className = 'scroller square-container';
|
|
let content = document.createElement('div');
|
|
content.className = 'content';
|
|
|
|
// <div id='parent' class='scroller'>
|
|
// <div id='sibling' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
// <div id='content'></div>
|
|
// </div>
|
|
document.body.appendChild(parent);
|
|
parent.appendChild(sibling);
|
|
parent.appendChild(target);
|
|
parent.appendChild(content);
|
|
|
|
parent.style.scrollTimelineName = 'timeline';
|
|
parent.style.scrollTimelineAxis = 'inline';
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
parent.scrollTop = 50; // 25%, in [0, 200].
|
|
sibling.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
content.remove();
|
|
parent.remove();
|
|
}, 'scroll-timeline-name is matched based on tree order, which considers ' +
|
|
'siblings closer than parents');
|
|
|
|
promise_test(async t => {
|
|
let sibling = document.createElement('div');
|
|
sibling.className = 'square';
|
|
sibling.style.overflowX = 'clip'; // This makes overflow-y be clip as well.
|
|
let target = document.createElement('div');
|
|
target.id = 'target';
|
|
|
|
// <div id='sibling' style='overflow-x: clip'></div>
|
|
// <div id='target'></div>
|
|
document.body.appendChild(sibling);
|
|
document.body.appendChild(target);
|
|
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
sibling.scrollTop = 50; // 50%, in [0, 100].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, 'none',
|
|
'Animation with an unresolved current time');
|
|
|
|
target.remove();
|
|
sibling.remove();
|
|
}, 'scroll-timeline-name on an element which is not a scroll-container');
|
|
|
|
promise_test(async t => {
|
|
let [sibling, target] = createScrollerAndTarget(t);
|
|
let main = document.createElement('div');
|
|
main.id = 'name';
|
|
|
|
// <div id='main'>
|
|
// <div id='sibling' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
// </div>
|
|
document.body.appendChild(main);
|
|
main.appendChild(sibling);
|
|
main.appendChild(target);
|
|
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
sibling.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
|
|
// Unknown animation-timeline, current time held at zero.
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
// Ensure that #main (an ancestor of the scroller) needs style recalc.
|
|
main.style.background = 'lightgray';
|
|
sibling.style.scrollTimelineName = 'timeline';
|
|
await waitForCSSScrollTimelineStyle();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
main.remove();
|
|
}, 'scroll-timeline-name affects subsequent siblings when changed');
|
|
|
|
promise_test(async t => {
|
|
let target = createTarget(t);
|
|
|
|
// <div id='target'></div>
|
|
document.body.appendChild(target);
|
|
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
// Unknown animation-timeline, current time held at zero.
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
let scroller = createScroller(t);
|
|
// <div class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
document.body.insertBefore(scroller, target);
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
// Ensure that time is not just held at zero.
|
|
scroller.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-name on inserted element affects subsequent siblings');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
await waitForCSSScrollTimelineStyle();
|
|
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
// This effectively removes the CSS-created ScrollTimeline on this element,
|
|
// thus invoking "setting the timeline of an animation" [1] with a null-
|
|
// timeline on affected elements. This in turn causes the current time to
|
|
// become unresolved [2], ultimately resulting in no effect value.
|
|
//
|
|
// [1] https://drafts.csswg.org/web-animations-1/#setting-the-timeline
|
|
// [2] https://drafts.csswg.org/web-animations-1/#the-current-time-of-an-animation
|
|
scroller.remove();
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, 'none');
|
|
}, 'scroll-timeline-name on removed element affects subsequent siblings');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div class='scroller' style='display:none'> ... </div>
|
|
// <div id='target'></div>
|
|
scroller.style.display = 'none';
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
// Unknown animation-timeline, current time held at zero.
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
scroller.style.display = 'block';
|
|
scroller.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-name on element leaving display:none affects subsequent siblings');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
await waitForCSSScrollTimelineStyle();
|
|
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
// See comment in the test "scroll-timeline-name on removed element ..." for
|
|
// an explantation of this result. (Setting display:none is similar to
|
|
// removing the element).
|
|
scroller.style.display = 'none';
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, 'none');
|
|
}, 'scroll-timeline-name on element becoming display:none affects subsequent siblings');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div id='scroller' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
scroller.style.display = 'none';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
await waitForNextFrame();
|
|
|
|
const anim = target.getAnimations()[0];
|
|
assert_true(!!anim, 'Failed to create animation');
|
|
assert_equals(anim.timeline, null);
|
|
// Hold time of animation is zero.
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
scroller.style.display = 'block';
|
|
scroller.scrollTop = 50;
|
|
await waitForNextFrame();
|
|
|
|
assert_true(!!anim.timeline, 'Failed to create timeline');
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
}, 'scroll-timeline-name on element not resolved until element becomes visible');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div id='scroller' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimelineName = 'timeline-A';
|
|
scroller.scrollTop = 50;
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline-B';
|
|
|
|
await waitForNextFrame();
|
|
|
|
const anim = target.getAnimations()[0];
|
|
assert_true(!!anim, 'Failed to create animation');
|
|
assert_equals(anim.timeline, null);
|
|
// Hold time of animation is zero.
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
scroller.style.scrollTimelineName = 'timeline-B';
|
|
await waitForNextFrame();
|
|
|
|
assert_true(!!anim.timeline, 'Failed to create timeline');
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
}, 'Change in scroll-timeline-name to match animation timeline updates animation.');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
// <div id='scroller' class='scroller'> ... </div>
|
|
// <div id='target'></div>
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimelineName = 'timeline-A';
|
|
scroller.scrollTop = 50;
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline-A';
|
|
|
|
await waitForNextFrame();
|
|
|
|
const anim = target.getAnimations()[0];
|
|
assert_true(!!anim, 'Failed to create animation');
|
|
assert_true(!!anim.timeline, 'Failed to create timeline');
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
scroller.style.scrollTimelineName = 'timeline-B';
|
|
await waitForNextFrame();
|
|
|
|
assert_equals(anim.timeline, null, 'Failed to remove timeline');
|
|
assert_equals(getComputedStyle(target).translate, 'none');
|
|
|
|
}, 'Change in scroll-timeline-name to no longer match animation timeline updates animation.');
|
|
|
|
promise_test(async t => {
|
|
let target = createTarget(t);
|
|
let scroller1 = createScroller(t);
|
|
let scroller2 = createScroller(t);
|
|
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
scroller1.style.scrollTimelineName = 'timeline';
|
|
scroller2.style.scrollTimelineName = 'timeline';
|
|
scroller1.id = 'A';
|
|
scroller2.id = 'B';
|
|
|
|
// <div class='scroller' id='A'> ... </div> (scroller1)
|
|
// <div class='scroller' id="B"> ... </div> (scroller2)
|
|
// <div id='target'></div>
|
|
document.body.appendChild(scroller1);
|
|
document.body.appendChild(scroller2);
|
|
document.body.append(target);
|
|
|
|
scroller1.scrollTop = 10; // 10%, in [50, 150].
|
|
scroller2.scrollTop = 50; // 50%, in [50, 150].
|
|
await waitForNextFrame();
|
|
|
|
|
|
// The named timeline lookup should select scroller2.
|
|
let anim = target.getAnimations()[0];
|
|
assert_true(!!anim, 'Failed to fetch animation');
|
|
assert_equals(anim.timeline.source.id, 'B');
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
scroller2.remove();
|
|
|
|
// Now it should select scroller1.
|
|
anim = target.getAnimations()[0];
|
|
assert_true(!!anim, 'Failed to fetch animation after update');
|
|
assert_true(!!anim.timeline, 'Animation no longer has a timeline');
|
|
assert_equals(anim.timeline.source.id, 'A', 'Timeline not updated');
|
|
assert_equals(getComputedStyle(target).translate, '60px');
|
|
}, 'Timeline lookup finds next candidate when element is removed');
|
|
|
|
promise_test(async t => {
|
|
let target = createTarget(t);
|
|
let scroller1 = createScroller(t);
|
|
|
|
target.style.animation = 'anim 10s linear';
|
|
target.style.animationTimeline = 'timeline';
|
|
scroller1.style.scrollTimelineName = 'timeline';
|
|
scroller1.id = 'A';
|
|
|
|
// <div class='scroller' id='A'> ... </div> (scroller1)
|
|
// <div id='target'></div>
|
|
document.body.appendChild(scroller1);
|
|
document.body.append(target);
|
|
|
|
scroller1.scrollTop = 10; // 10%, in [50, 150].
|
|
|
|
await waitForNextFrame();
|
|
|
|
const anim = target.getAnimations()[0];
|
|
|
|
assert_true(!!anim.timeline, 'Failed to retrieve animation');
|
|
assert_equals(anim.timeline.source.id, 'A');
|
|
assert_equals(getComputedStyle(target).translate, '60px');
|
|
|
|
await waitForNextFrame();
|
|
|
|
let scroller2 = createScroller(t);
|
|
scroller2.style.scrollTimelineName = 'timeline';
|
|
scroller2.id = 'B';
|
|
|
|
// <div class='scroller' id="A"> ... </div> (scroller1)
|
|
// <div class='scroller' id="B"> ... </div> (scroller2)
|
|
// <div id='target'></div>
|
|
document.body.insertBefore(scroller2, target);
|
|
|
|
scroller2.scrollTop = 50; // 50%, in [50, 150].
|
|
|
|
await waitForNextFrame();
|
|
|
|
// The timeline should be updated to scroller2.
|
|
assert_true(!!anim.timeline, 'Animation no longer has a timeline');
|
|
assert_equals(anim.timeline.source.id, 'B', 'Timeline not updated');
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'Timeline lookup updates candidate when closer match available.');
|
|
|
|
promise_test(async t => {
|
|
let target = createTarget(t);
|
|
|
|
// <div id='target'></div>
|
|
document.body.append(target);
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
await waitForNextFrame();
|
|
|
|
// Timeline initially cannot be resolved, resulting in a null
|
|
// timeline. The animation's hold time is zero.
|
|
let anim = document.getAnimations()[0];
|
|
assert_equals(getComputedStyle(target).translate, '50px');
|
|
|
|
await waitForNextFrame();
|
|
|
|
let scroller = createScroller(t);
|
|
scroller.style.scrollTimelineName = 'timeline';
|
|
|
|
// <div class='scroller'> ... </div> (scroller1)
|
|
// <div id='target'></div>
|
|
document.body.insertBefore(scroller, target);
|
|
|
|
scroller.scrollTop = 50; // 50%, in [50, 150].
|
|
|
|
await waitForNextFrame();
|
|
|
|
// The timeline should be updated to scroller.
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'Timeline lookup updates candidate when match becomes available.');
|
|
|
|
// -------------------------
|
|
// Test scroll-timeline-axis
|
|
// -------------------------
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
scroller.style.writingMode = 'vertical-lr';
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimeline = 'timeline block';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
scroller.scrollLeft = 50;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-axis is block');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
scroller.style.writingMode = 'vertical-lr';
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimeline = 'timeline inline';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
scroller.scrollTop = 50;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-axis is inline');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
scroller.style.writingMode = 'vertical-lr';
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimeline = 'timeline horizontal';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
scroller.scrollLeft = 50;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-axis is horizontal');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
scroller.style.writingMode = 'vertical-lr';
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimeline = 'timeline vertical';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
scroller.scrollTop = 50;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
}, 'scroll-timeline-axis is vertical');
|
|
|
|
promise_test(async t => {
|
|
let [scroller, target] = createScrollerAndTarget(t);
|
|
|
|
document.body.appendChild(scroller);
|
|
document.body.appendChild(target);
|
|
|
|
scroller.style.scrollTimeline = 'timeline block';
|
|
target.style.animation = "anim 10s linear";
|
|
target.style.animationTimeline = 'timeline';
|
|
|
|
scroller.scrollTop = 50;
|
|
scroller.scrollLeft = 25;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '100px');
|
|
|
|
scroller.style.scrollTimelineAxis = 'inline';
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(target).translate, '75px');
|
|
}, 'scroll-timeline-axis is mutated');
|
|
|
|
</script>
|
|
</body>
|