mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
451 lines
13 KiB
HTML
451 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="./resources/utils.js"></script>
|
|
<div id=outer>
|
|
<div id=div></div>
|
|
</div>
|
|
<script>
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@keyframes test {
|
|
from { ${name}: 100px; }
|
|
to { ${name}: 200px; }
|
|
}
|
|
#div { animation: test 100s -50s linear; }
|
|
`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '150px');
|
|
});
|
|
}, '@keyframes works with @property');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@property ${name} {
|
|
syntax: "<color>";
|
|
inherits: false;
|
|
initial-value: black;
|
|
}
|
|
@keyframes test {
|
|
from { ${name}: rgb(100, 100, 100); }
|
|
to { ${name}: rgb(200, 200, 200); }
|
|
}
|
|
#div { animation: test 100s -50s linear; }
|
|
`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(150, 150, 150)');
|
|
});
|
|
}, '@keyframes picks up the latest @property in the document');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
// These keyframes are initially invalid for the declared custom property.
|
|
let animation = div.animate([
|
|
{ [name]: 'rgb(100, 100, 100)'},
|
|
{ [name]: 'rgb(200, 200, 200)'},
|
|
], { duration: 10000, delay: -5000, easing: 'linear' });
|
|
let cs = getComputedStyle(div);
|
|
assert_equals(cs.getPropertyValue(name), '0px');
|
|
|
|
// Redeclare the property as a <color>, effectively making the existing
|
|
// keyframes valid.
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'black'
|
|
}, (name) => {
|
|
assert_equals(cs.getPropertyValue(name), 'rgb(150, 150, 150)');
|
|
});
|
|
|
|
animation.finish();
|
|
}, 'Ongoing animation picks up redeclared custom property');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
// These keyframes are initially invalid for the declared custom property.
|
|
let animation = div.animate([
|
|
{ [name]: 'rgb(100, 100, 100)'},
|
|
{ [name]: 'rgb(200, 200, 200)'},
|
|
], { duration: 10000, delay: -5000, easing: 'linear' });
|
|
let cs = getComputedStyle(div);
|
|
assert_equals(cs.getPropertyValue(name), '0px');
|
|
|
|
// Setting the keyframes to something that matches <length> makes the
|
|
// interpolation valid.
|
|
animation.effect.setKeyframes([
|
|
{[name]: '100px'},
|
|
{[name]: '200px'}
|
|
]);
|
|
assert_equals(cs.getPropertyValue(name), '150px');
|
|
|
|
animation.finish();
|
|
}, 'Ongoing animation matches new keyframes against the current registration');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
let animation = div.animate([
|
|
{ [name]: 'initial'},
|
|
{ [name]: '400px'},
|
|
], { duration: 10000, delay: -5000, easing: 'linear' });
|
|
let cs = getComputedStyle(div);
|
|
assert_equals(cs.getPropertyValue(name), '200px');
|
|
|
|
// Change initial value.
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '100px'
|
|
}, (name) => {
|
|
assert_equals(cs.getPropertyValue(name), '250px');
|
|
});
|
|
|
|
animation.finish();
|
|
}, 'Ongoing animation picks up redeclared intial value');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
try {
|
|
document.body.style = `${name}: 100px`;
|
|
// Note that 'inherit' here refers to #outer, which has the initial
|
|
// value. (#outer did not inherit from body, since the property is not
|
|
// yet declared as inherited).
|
|
let animation = div.animate([
|
|
{ [name]: 'inherit'},
|
|
{ [name]: '400px'},
|
|
], { duration: 10000, delay: -5000, easing: 'linear' });
|
|
let cs = getComputedStyle(div);
|
|
assert_equals(cs.getPropertyValue(name), '200px');
|
|
|
|
// Change inherits to 'true'. The value should now propagate from body
|
|
// to #outer.
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<length>"',
|
|
inherits: true,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
assert_equals(cs.getPropertyValue(name), '250px');
|
|
});
|
|
|
|
animation.finish();
|
|
} finally {
|
|
document.body.style = '';
|
|
}
|
|
}, 'Ongoing animation picks up redeclared inherits flag');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
try {
|
|
outer.style = `${name}: 100px`;
|
|
// 'unset' should take the initial value (not the value from #outer), since
|
|
// the property is not declared as inherited.
|
|
let animation = div.animate([
|
|
{ [name]: 'unset'},
|
|
{ [name]: '400px'},
|
|
], { duration: 10000, delay: -5000, easing: 'linear' });
|
|
let cs = getComputedStyle(div);
|
|
assert_equals(cs.getPropertyValue(name), '200px');
|
|
|
|
// Change inherits to 'true'. 'unset' now refers to #outer's value.
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<length>"',
|
|
inherits: true,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
assert_equals(cs.getPropertyValue(name), '250px');
|
|
});
|
|
|
|
animation.finish();
|
|
} finally {
|
|
outer.style = '';
|
|
}
|
|
}, 'Ongoing animation picks up redeclared meaning of \'unset\'');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'red'
|
|
}, (name) => {
|
|
try {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(255, 0, 0)');
|
|
div.style = `transition: ${name} steps(2, start) 100s; ${name}: blue`;
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(128, 0, 128)');
|
|
} finally {
|
|
div.style = '';
|
|
}
|
|
}, 'Transitioning from initial value');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'red'
|
|
}, (name) => {
|
|
try {
|
|
div.style = `${name}: blue;`;
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(0, 0, 255)');
|
|
div.style = `transition: ${name} steps(2, start) 100s; ${name}: green`;
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(0, 64, 128)');
|
|
} finally {
|
|
div.style = '';
|
|
}
|
|
}, 'Transitioning from specified value');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '100px'
|
|
}, (name) => {
|
|
with_style_node(`div { transition: ${name} steps(2, start) 100s; }`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '100px');
|
|
// Re-declaring the property with a different initial value effectively
|
|
// means the computed value has changed. This means we should transition
|
|
// from the old initial value to the new initial value.
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '200px'
|
|
}, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '150px');
|
|
});
|
|
});
|
|
}, 'Transition triggered by initial value change');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '100px'
|
|
}, (name) => {
|
|
with_style_node(`div { transition: ${name} steps(2, start) 100s; }`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '100px');
|
|
with_at_property({
|
|
name: name,
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'green'
|
|
}, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(0, 128, 0)');
|
|
});
|
|
});
|
|
}, 'No transition when changing types');
|
|
|
|
test(() => {
|
|
let name = generate_name();
|
|
with_style_node(`div { ${name}: 100px; transition: ${name} steps(2, start) 100s; }`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '100px');
|
|
|
|
let style1 = document.createElement('style');
|
|
style1.textContent = `
|
|
@property ${name} {
|
|
syntax: "<length>";
|
|
inherits: false;
|
|
initial-value: 200px;
|
|
}
|
|
`;
|
|
|
|
let style2 = document.createElement('style');
|
|
style2.textContent = `div { ${name}: 400px; }`;
|
|
|
|
try {
|
|
// Register the property:
|
|
document.body.append(style1);
|
|
// The token sequence ' 100px' is now interpreted as a length '100px'.
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '100px');
|
|
|
|
// Change the computed value:
|
|
document.body.append(style2);
|
|
// This should cause an interpolation between 100px and 400px:
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '250px');
|
|
|
|
// In the middle of the transition above, remove the @property rule
|
|
// (making the computed value a token sequence again). We should snap
|
|
// to the new token sequence.
|
|
style1.remove();
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '400px');
|
|
} finally {
|
|
style1.remove();
|
|
style2.remove();
|
|
}
|
|
});
|
|
}, 'No transition when removing @property rule');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@keyframes test {
|
|
from { ${name}: 100px; }
|
|
to { ${name}: 200px; }
|
|
}
|
|
#div {
|
|
animation: test 100s -50s linear;
|
|
--unregistered: var(${name});
|
|
}
|
|
`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue('--unregistered'), '150px');
|
|
});
|
|
}, 'Unregistered properties referencing animated properties update correctly.');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@keyframes test {
|
|
from { ${name}: 100px; }
|
|
to { ${name}: 200px; }
|
|
}
|
|
@property --registered {
|
|
syntax: "<length>";
|
|
inherits: false;
|
|
initialValue: 0px;
|
|
}
|
|
#div {
|
|
animation: test 100s -50s linear;
|
|
--registered: var(${name});
|
|
}
|
|
`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue('--registered'), '150px');
|
|
});
|
|
}, 'Registered properties referencing animated properties update correctly.');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@keyframes test {
|
|
from { ${name}: inherit; }
|
|
to { ${name}: 300px; }
|
|
}
|
|
#outer {
|
|
${name}: 100px;
|
|
}
|
|
#div {
|
|
animation: test 100s -50s linear paused;
|
|
}
|
|
`, () => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '200px');
|
|
|
|
outer.style.setProperty(name, '200px');
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '250px');
|
|
|
|
outer.style.setProperty(name, '0px');
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '150px');
|
|
|
|
outer.style.removeProperty(name);
|
|
});
|
|
}, 'CSS animation setting "inherit" for a custom property on a keyframe is responsive to changing that custom property on the parent.');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<length>"',
|
|
inherits: false,
|
|
initialValue: '0px'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
#outer {
|
|
${name}: 100px;
|
|
}
|
|
`, () => {
|
|
const animation = div.animate({ [name]: ["inherit", "300px"]}, 1000);
|
|
animation.currentTime = 500;
|
|
animation.pause();
|
|
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '200px');
|
|
|
|
outer.style.setProperty(name, '200px');
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '250px');
|
|
|
|
outer.style.setProperty(name, '0px');
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), '150px');
|
|
|
|
outer.style.removeProperty(name);
|
|
});
|
|
}, 'JS-originated animation setting "inherit" for a custom property on a keyframe is responsive to changing that custom property on the parent.');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'black'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
@keyframes test {
|
|
from { ${name}: currentcolor; }
|
|
to { ${name}: rgb(200, 200, 200); }
|
|
}
|
|
#outer {
|
|
color: rgb(100, 100, 100);
|
|
}
|
|
#div {
|
|
animation: test 100s -50s linear paused;
|
|
}
|
|
`, (style) => {
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(150, 150, 150)');
|
|
|
|
outer.style.color = 'rgb(50, 50, 50)';
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(125, 125, 125)');
|
|
|
|
outer.style.color = 'rgb(150, 150, 150)';
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(175, 175, 175)');
|
|
|
|
outer.style.removeProperty("color");
|
|
});
|
|
}, 'CSS animation setting "currentColor" for a custom property on a keyframe is responsive to changing "color" on the parent.');
|
|
|
|
test_with_at_property({
|
|
syntax: '"<color>"',
|
|
inherits: false,
|
|
initialValue: 'black'
|
|
}, (name) => {
|
|
with_style_node(`
|
|
#outer {
|
|
color: rgb(100, 100, 100);
|
|
}
|
|
`, () => {
|
|
const animation = div.animate({ [name]: ["currentcolor", "rgb(200, 200, 200)"]}, 1000);
|
|
animation.currentTime = 500;
|
|
animation.pause();
|
|
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(150, 150, 150)');
|
|
|
|
outer.style.color = 'rgb(50, 50, 50)';
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(125, 125, 125)');
|
|
|
|
outer.style.color = 'rgb(150, 150, 150)';
|
|
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(175, 175, 175)');
|
|
|
|
outer.style.removeProperty("color");
|
|
});
|
|
}, 'JS-originated animation setting "currentColor" for a custom property on a keyframe is responsive to changing "color" on the parent.');
|
|
|
|
</script>
|