| <!doctype html> |
| <meta charset=utf-8> |
| <title>Animating CSS logical properties using Web Animations</title> |
| <link rel="help" href="https://drafts.csswg.org/css-logical/#box"> |
| <meta name="assert" content="The specified values of these properties are separate from the specified values of the parallel physical properties, but the flow-relative and physical properties share computed values."> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="../css-animations/support/testcommon.js"></script> |
| <style> |
| :root { |
| --200px: 200px; |
| --300px: 300px; |
| --writingMode: horizontal-tb; |
| } |
| </style> |
| |
| <div id="log"></div> |
| <script> |
| 'use strict'; |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '50px'); |
| }, 'Logical properties can be animated using object notation'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| [{ blockSize: '0px' }, { blockSize: '100px' }], |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '50px'); |
| }, 'Logical properties can be animated using array notation'); |
| |
| test(t => { |
| const anim = addDiv(t).animate({ blockSize: ['0px', '100px'] }, 1000); |
| assert_equals(anim.effect.getKeyframes().length, 2); |
| |
| assert_own_property(anim.effect.getKeyframes()[0], 'blockSize'); |
| assert_false(anim.effect.getKeyframes()[0].hasOwnProperty('height')); |
| |
| assert_own_property(anim.effect.getKeyframes()[1], 'blockSize'); |
| assert_false(anim.effect.getKeyframes()[1].hasOwnProperty('height')); |
| }, 'Logical properties are NOT stored as physical properties'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'writing-mode: vertical-rl' }); |
| const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).width, '50px'); |
| assert_equals(getComputedStyle(div).height, '0px'); |
| }, 'Logical properties in animations respect the writing-mode'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'direction: rtl' }); |
| const anim = div.animate({ marginInlineStart: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).marginLeft, '0px'); |
| assert_equals(getComputedStyle(div).marginRight, '50px'); |
| }, 'Logical properties in animations respect the direction'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| blockSize: ['0px', '100px'], |
| height: ['200px', '300px'], |
| }, |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Physical properties win over logical properties in object notation'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| [ |
| { height: '200px', blockSize: '0px' }, |
| { height: '300px', blockSize: '100px' }, |
| ], |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Physical properties win over logical properties in array notation'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| blockSize: ['0px', '100px'], |
| height: ['var(--200px)', 'var(--300px)'], |
| }, |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Physical properties with variables win over logical properties'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| marginInlineStart: '100px', |
| marginInline: '200px', |
| margin: 'logical 300px', |
| }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).marginLeft, '100px'); |
| assert_equals(getComputedStyle(div).marginRight, '200px'); |
| assert_equals(getComputedStyle(div).marginTop, '300px'); |
| assert_equals(getComputedStyle(div).marginBottom, '300px'); |
| }, 'Logical shorthands follow the usual prioritization based on number of' |
| + ' component longhands'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| marginInline: '100px', |
| marginLeft: '200px', |
| }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).marginLeft, '200px'); |
| assert_equals(getComputedStyle(div).marginRight, '100px'); |
| }, 'Physical longhands win over logical shorthands'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| marginInlineStart: '100px', |
| margin: '200px', |
| }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).marginLeft, '100px'); |
| assert_equals(getComputedStyle(div).marginRight, '200px'); |
| }, 'Logical longhands win over physical shorthands'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| marginInline: '100px', |
| margin: '200px', |
| }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).marginLeft, '200px'); |
| assert_equals(getComputedStyle(div).marginRight, '200px'); |
| }, 'Physical shorthands win over logical shorthands'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| marginInline: '100px', |
| margin: 'var(--200px)', |
| }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).marginLeft, '200px'); |
| assert_equals(getComputedStyle(div).marginRight, '200px'); |
| }, 'Physical shorthands using variables win over logical shorthands'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate([{ blockSize: '200px' }, { height: '300px' }], 1000); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Physical properties and logical properties can be mixed'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| [{ marginInline: '200px' }, { marginRight: '300px' }], |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).marginRight, '250px'); |
| }, 'Physical shorthands and logical shorthands can be mixed'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| [{ blockSize: '100px', height: '200px' }, { height: '300px' }], |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Physical properties win over logical properties even when some keyframes' |
| + ' only have logical properties'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'width: 0px; height: 0px' }); |
| const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| |
| assert_equals(getComputedStyle(div).width, '0px'); |
| assert_equals(getComputedStyle(div).height, '50px'); |
| |
| div.style.writingMode = 'vertical-rl'; |
| assert_equals(getComputedStyle(div).width, '50px'); |
| assert_equals(getComputedStyle(div).height, '0px'); |
| }, 'Animations update when the writing-mode is changed'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'width: 0px; height: 0px' }); |
| const anim = div.animate( |
| { blockSize: ['0px', '100px'] }, |
| { |
| duration: 1000, |
| fill: 'forwards', |
| } |
| ); |
| anim.finish(); |
| |
| assert_equals(getComputedStyle(div).width, '0px'); |
| assert_equals(getComputedStyle(div).height, '100px'); |
| |
| div.style.writingMode = 'vertical-rl'; |
| assert_equals(getComputedStyle(div).width, '100px'); |
| assert_equals(getComputedStyle(div).height, '0px'); |
| }, 'Filling animations update when the writing-mode is changed'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'width: 100px; height: 200px' }); |
| const anim = div.animate({ blockSize: '300px' }, 1000); |
| anim.currentTime = 500; |
| |
| // Initially we are animating height from 200px -> 300px |
| assert_equals(getComputedStyle(div).width, '100px'); |
| assert_equals(getComputedStyle(div).height, '250px'); |
| |
| // After the change we are animating width from 100px -> 300px |
| div.style.writingMode = 'vertical-rl'; |
| assert_equals(getComputedStyle(div).width, '200px'); |
| assert_equals(getComputedStyle(div).height, '200px'); |
| }, 'Animations with implicit from values update when the writing-mode' |
| + ' is changed'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'width: 0px; height: 0px' }); |
| const anim = div.animate( |
| [ |
| { height: '200px', blockSize: '0px' }, |
| { height: '300px', blockSize: '100px' }, |
| ], |
| 1000 |
| ); |
| anim.currentTime = 500; |
| |
| // Initially writing-mode is horizontal-tb so the 'block-size' values are |
| // clobbered by the 'height' values. |
| |
| assert_equals(getComputedStyle(div).width, '0px'); |
| assert_equals(getComputedStyle(div).height, '250px'); |
| |
| // After updating the writing-mode to vertical-rl the 'block-size' values |
| // should no longer be overridden and should apply to the height. |
| |
| div.style.writingMode = 'vertical-rl'; |
| assert_equals(getComputedStyle(div).width, '50px'); |
| assert_equals(getComputedStyle(div).height, '250px'); |
| }, 'Animations with overlapping physical and logical properties update' |
| + ' when the writing-mode is changed'); |
| |
| test(t => { |
| const div = addDiv(t, { style: 'width: 0px; height: 0px' }); |
| div.style.writingMode = 'var(--writingMode)'; |
| const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| |
| assert_equals(getComputedStyle(div).width, '0px'); |
| assert_equals(getComputedStyle(div).height, '50px'); |
| |
| div.style.setProperty('--writingMode', 'vertical-rl'); |
| assert_equals(getComputedStyle(div).width, '50px'); |
| assert_equals(getComputedStyle(div).height, '0px'); |
| }, 'Animations update when the writing-mode is changed through a CSS variable'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate({ marginInlineStart: ['0px', '100px'] }, 1000); |
| anim.currentTime = 500; |
| |
| assert_equals(getComputedStyle(div).marginLeft, '50px'); |
| assert_equals(getComputedStyle(div).marginRight, '0px'); |
| |
| div.style.direction = 'rtl'; |
| assert_equals(getComputedStyle(div).marginLeft, '0px'); |
| assert_equals(getComputedStyle(div).marginRight, '50px'); |
| }, 'Animations update when the direction is changed'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { |
| insetBlock: ['var(--200px)', 'var(--300px)'], |
| }, |
| 1000 |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).insetBlockStart, '250px'); |
| }, 'Logical shorthand with variable references animates correctly'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { writingMode: 'vertical-rl' }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| assert_equals(getComputedStyle(div).writingMode, 'horizontal-tb'); |
| assert_equals(anim.effect.getKeyframes().length, 0); |
| }, 'writing-mode is not animatable'); |
| |
| test(t => { |
| const div = addDiv(t); |
| const anim = div.animate( |
| { writingMode: 'rtl' }, |
| { duration: 1, easing: 'step-start' } |
| ); |
| anim.currentTime = 500; |
| assert_equals(getComputedStyle(div).direction, 'ltr'); |
| assert_equals(anim.effect.getKeyframes().length, 0); |
| }, 'direction is not animatable'); |
| |
| </script> |