Title: Motion Path Module Level 1 Shortname: motion Level: 1 Status: ED Prepare for TR: no Issue Tracking: GitHub https://github.com/w3c/fxtf-drafts/labels/motion-1 Work Status: Refining ED: https://drafts.csswg.org/motion-1/ TR: https://www.w3.org/TR/motion-1/ Group: csswg Editor: Dirk Schulze, Adobe Inc., dschulze@adobe.com, w3cid 51803 Editor: Jihye Hong, Igalia, jihye@igalia.com, w3cid 79168 Editor: Tab Atkins-Bittner, Google, http://xanthir.com/contact/, w3cid 42199 Former Editor: Shane Stephens, Google, shanestephens@google.com, w3cid 47691 Former Editor: Eric Willigers, then Google, ericwilligers@google.com, w3cid 67534 Test Suite: https://github.com/web-platform-tests/wpt/tree/master/css/motion Abstract: Motion path allows authors to position any graphical object and animate it along an author specified path. WPT Path Prefix: css/motion/ WPT Display: closed
spec:css-transforms-1; type:dfn;
text:local coordinate system
spec:svg2; type:dfn;
text: segment-completing close path
spec: css-backgrounds-3; type:property;
text: border-radius
spec:motion-1; type:value;
text:path()
spec:css-shapes-1; type:dfn;
text:shape()
Introduction {#intro}
=====================
This section is not normative.
The 'transform' property and its related properties
allow a [=box=] to be arbitrarily repositioned
(and rotated, scaled, etc)
relative to its laid out position,
without disrupting the layout of any other elements on the page.
These positions can be animated or transitioned with CSS,
but only in relatively simple ways:
moving a box in a straight line from its starting position to its ending position.
This specification introduces the 'offset' shorthand,
and its suite of associated longhand properties,
which define an offset transform:
a transform which aligns a particular point on an element
('offset-anchor')
to an offset position on a path
('offset-path' and 'offset-distance'),
and optionally rotates it to follow the path direction
('offset-rotate').
This allows a number of powerful new transform possibilities,
such as positioning using polar coordinates
(with the ''ray()'' function)
rather than the standard rectangular coordinates
used by the ''translate()'' function,
or animating an element along a defined path,
making it easy to define complex and beautiful 2d spatial transitions.
The plane is shown at different 'offset-distance' values: ''0%'', ''50%'', and ''100%''.
Name: offset-path Value: none | <Specifies the offset path, a geometrical path the box gets positioned on.> || < > Initial: none Applies to: [=transformable elements=] Inherited: no Percentages: n/a Computed value: as specified Media: visual Animation type: by computed value
<offset-path> = <Values have the following meanings:> | < > | < >
ray() = ray( <Its arguments are:> && < >? && contain? && [at < >]? ) <ray-size> = < > | sides
<style>
body {
transform-style: preserve-3d;
width: 200px;
height: 200px;
}
.box {
width: 50px;
height: 50px;
offset-position: 50% 50%;
offset-distance: 100%;
offset-rotate: 0deg;
}
#redBox {
background-color: red;
offset-path: ray(45deg closest-side);
}
#blueBox {
background-color: blue;
offset-path: ray(180deg closest-side);
}
</style>
<body>
<div class="box" id="redBox"></div>
<div class="box" id="blueBox"></div>
</body>
<style>
body {
transform-style: preserve-3d;
width: 200px;
height: 200px;
}
.box {
width: 50px;
height: 50px;
offset-position: 50% 50%;
offset-distance: 100%;
offset-rotate: 0deg;
}
#redBox {
background-color: red;
offset-path: ray(45deg closest-side contain);
}
#blueBox {
background-color: blue;
offset-path: ray(180deg closest-side contain);
}
</style>
<body>
<div class="box" id="redBox"></div>
<div class="box" id="blueBox"></div>
</body>
<style>
body {
transform-style: preserve-3d;
width: 250px;
height: 250px;
}
.box {
width: 60%;
height: 10%;
offset-position: 20% 20%;
offset-distance: 0%;
offset-rotate: 0deg;
offset-anchor: 200% -300%;
}
#blueBox {
background-color: blue;
offset-path: ray(-90deg closest-side contain);
}
</style>
<body>
<div class="box" id="blueBox"></div>
</body>
<style>
#container {
transform-style: preserve-3d;
width: 200px;
height: 200px;
}
.box {
width: 20%;
height: 20%;
offset-position: 140% 70%;
offset-distance: 100%;
}
#redBox {
background-color: red;
offset-path: ray(-90deg sides);
}
#blueBox {
background-color: blue;
offset-path: ray(180deg closest-side);
}
</style>
<div id="container">
<div class="box" id="redBox"></div>
<div class="box" id="blueBox"></div>
</div>
<style>
body {
width: 323px;
height: 131px;
margin: 0px;
border: 2px solid black;
padding: 8px;
transform-style: preserve-3d;
}
.item {
width: 90px;
height: 40px;
background-color: violet;
}
#middle {
offset-position: auto;
offset-path: circle(60%) margin-box;
offset-distance: 25%;
offset-anchor: left top;
}
</style>
<body>
<div class="item"></div>
<div class="item" id="middle"></div>
<div class="item"></div>
</body>
<style>
body {
width: 500px;
height: 300px;
border-radius: 80px;
border: dashed aqua;
margin: 0;
}
#blueBox {
width: 40px;
height: 20px;
background-color: blue;
offset-path: margin-box;
}
</style>
<body>
<div id="blueBox"></div>
</body>
Name: offset-distance Value: <Specifies where along the [=offset path=] the [=offset position=] is.> Initial: 0 Applies to: [=transformable elements=] Inherited: no Percentages: relative to the [=offset path=] length Computed value: a computed < > value Media: visual Animation type: by computed value
<style>
.item {
width: 100px;
height: 40px;
offset-position: 0% 0%;
offset-path: path('m 0 0 h 200 v 150');
}
#box1 {
background-color: red;
offset-distance: -280%;
}
#box2 {
background-color: green;
offset-distance: 190%;
}
</style>
<body>
<div class="item" id="box1"></div>
<div class="item" id="box2"></div>
</body>
<style>
.item {
width: 100px;
height: 40px;
offset-position: 0% 0%;
offset-path: path('m 0 0 h 200 v 150 z');
}
#box1 {
background-color: red;
offset-distance: -280%;
}
#box2 {
background-color: green;
offset-distance: 190%;
}
</style>
<body>
<div class="item" id="box1"></div>
<div class="item" id="box2"></div>
</body>
<style>
body {
transform-style: preserve-3d;
width: 300px;
height: 300px;
border: dashed gray;
border-radius: 50%;
}
.circleBox {
position: absolute;
left: 50%;
top: 50%;
width: 40px;
height: 40px;
background-color: red;
border-radius: 50%;
}
#circle1 {
offset-path: ray(0deg farthest-side);
offset-distance: 50%;
}
#circle2 {
offset-path: ray(90deg farthest-side);
offset-distance: 20%;
}
#circle3 {
offset-path: ray(225deg farthest-side);
offset-distance: 100%;
}
</style>
<body>
<div class="circleBox" id="circle1"></div>
<div class="circleBox" id="circle2"></div>
<div class="circleBox" id="circle3"></div>
</body>
Name: offset-position Value: normal | auto | <Specifies the offset starting position that is used by the <> Initial: normal Media: visual Inherited: no Applies to: [=transformable elements=] Percentages: Refer to the size of containing block Computed value: The ''offset-position/normal'' or ''offset-position/auto'' keywords, or a computed < > Animation type: by computed value
<style>
#wrap {
position: relative;
width: 300px;
height: 300px;
border: 1px solid black;
}
#box {
width: 100px;
height: 100px;
background-color: green;
position: absolute;
top: 100px;
left: 80px;
offset-position: auto;
offset-anchor: center;
offset-path: ray(45deg);
}
</style>
<body>
<div id="wrap">
<div id="box"></div>
</div>
</body>
<style>
#wrap {
transform-style: preserve-3d;
width: 400px;
height: 350px;
}
.item {
position: absolute;
left: 200px;
top: 0px;
offset-position: 200px 100px; /* translates by 0px,100px */
offset-anchor: left top;
transform-origin: left top;
width: 130px;
height: 80px;
border-top-right-radius: 23px;
}
#box1 {
background-color: tomato;
offset-position: auto;
}
#box2 {
background-color: green;
}
#box3 {
background-color: navy;
rotate: 90deg; /* applied before motion path transform */
}
#box4 {
background-color: gold;
transform: rotate(90deg); /* applied after motion path transform */
}
</style>
<body>
<div id="wrap">
<div class="item" id="box1"></div>
<div class="item" id="box2"></div>
<div class="item" id="box3"></div>
<div class="item" id="box4"></div>
</div>
</body>
<style>
#wrap {
transform-style: preserve-3d;
width: 500px;
height: 250px;
line-height: 0px;
}
span {
position: static;
display: inline-block;
width: 100px;
height: 50px;
border-top-right-radius: 23px;
scale: 2.5 2.5; /* applied before motion path transform */
offset-position: center;
transform: scale(0.4); /* applied after motion path transform */
}
#box1 {
background-color: tomato;
}
#box2 {
background-color: green;
}
#box3 {
background-color: navy;
}
#box4 {
background-color: gold;
}
</style>
<body>
<div id="wrap">
<div>
<span id="box1"></span><span id="box2"></span>
</div>
<div>
<span id="box3"></span><span id="box4"></span>
</div>
</div>
</body>
<style>
#wrap {
transform-style: preserve-3d;
width: 540px;
height: 420px;
}
.item {
position: absolute;
width: 90px;
height: 70px;
border-top-right-radius: 23px;
scale: 0.8 0.8; /* applied before motion path transform */
offset-path: padding-box;
offset-distance: 50%;
offset-rotate: 0deg;
offset-anchor: right bottom;
transform: scale(1.25); /* applied after motion path transform */
}
#box1 {
background-color: tomato;
position: static;
offset-position: auto; /* ignored */
}
#box2 {
background-color: green;
right: 0px;
top: 0px;
offset-position: 23% 45%; /* ignored */
}
#box3 {
background-color: navy;
left: 0px;
bottom: 0px;
offset-position: 34% 56px; /* ignored */
}
#box4 {
background-color: gold;
right: 0px;
bottom: 0px;
offset-position: 45px 67px; /* ignored */
}
</style>
<body>
<div id="wrap">
<div class="item" id="box1"></div>
<div class="item" id="box2"></div>
<div class="item" id="box3"></div>
<div class="item" id="box4"></div>
</div>
</body>
Name: offset-anchor Applies to: [=transformable elements=] Value: auto | <Defines the element's offset anchor point-- the point that is aligned with the [=offset position=] along the [=offset path=]. Values have the following meanings:> Initial: auto Media: visual Inherited: no Percentages: relative to the width and the height of the element's [=reference box=] Computed value: the ''offset-anchor/auto'' keyword or a computed < > Animation type: by computed value
#plane {
offset-anchor: center;
}
The red dot in the middle of the shape indicates the anchor point of the shape.
<style>
body {
transform-style: preserve-3d;
width: 300px;
height: 300px;
border: 2px solid gray;
border-radius: 50%;
}
.box {
width: 50px;
height: 50px;
background-color: orange;
offset-position: 50% 50%;
offset-distance: 100%;
offset-rotate: 0deg;
}
#item1 {
offset-path: ray(45deg closest-side);
offset-anchor: right top;
}
#item2 {
offset-path: ray(135deg closest-side);
offset-anchor: right bottom;
}
#item3 {
offset-path: ray(225deg closest-side);
offset-anchor: left bottom;
}
#item4 {
offset-path: ray(315deg closest-side);
offset-anchor: left top;
}
</style>
<body>
<div class="box" id="item1"></div>
<div class="box" id="item2"></div>
<div class="box" id="item3"></div>
<div class="box" id="item4"></div>
</body>
<style>
body {
width: 500px;
height: 500px;
}
.box {
background-color: mediumpurple;
offset-path: none;
offset-anchor: center;
}
#item1 {
offset-position: 90% 20%;
width: 60%;
height: 20%;
}
#item2 {
offset-position: 100% 100%;
width: 30%;
height: 10%;
}
#item3 {
offset-position: 50% 100%;
width: 20%;
height: 60%;
}
#item4 {
offset-position: 0% 100%;
width: 30%;
height: 90%;
}
</style>
<body>
<div class="box" id="item1"></div>
<div class="box" id="item2"></div>
<div class="box" id="item3"></div>
<div class="box" id="item4"></div>
</body>
<style>
body {
width: 500px;
height: 500px;
}
.box {
background-color: mediumpurple;
offset-path: none;
offset-anchor: auto;
}
#item1 {
offset-position: 90% 20%;
width: 60%;
height: 20%;
}
#item2 {
offset-position: 100% 100%;
width: 30%;
height: 10%;
}
#item3 {
offset-position: 50% 100%;
width: 20%;
height: 60%;
}
#item4 {
offset-position: 0% 100%;
width: 30%;
height: 90%;
}
</style>
<body>
<div class="box" id="item1"></div>
<div class="box" id="item2"></div>
<div class="box" id="item3"></div>
<div class="box" id="item4"></div>
</body>
Name: offset-rotate Value: [ auto | reverse ] || <Defines a rotation component of the [=offset transform=], possibly based on the direction of the [=offset path=] at the [=offset position=]. Values have the following meanings:> Initial: auto Applies to: transformable elements Inherited: no Percentages: n/a Computed value: computed < > value, optionally preceded by auto Media: visual Animation type: by computed value
<style>
body {
width: 300px;
height: 300px;
margin: 0px;
border: solid gray;
border-radius: 50%;
}
.circle {
offset-position: 150px 150px;
offset-distance: 86%;
width: 42px;
height: 42px;
background-color: mediumpurple;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
#item1 {
offset-path: ray(0deg closest-side);
offset-rotate: auto 90deg;
}
#item2 {
offset-path: ray(45deg closest-side);
offset-rotate: auto 90deg;
}
#item3 {
offset-path: ray(135deg closest-side);
offset-rotate: auto -90deg;
}
#item4 {
offset-path: ray(180deg closest-side);
offset-rotate: auto -90deg;
}
#item5 {
offset-path: ray(225deg closest-side);
offset-rotate: reverse 90deg;
}
#item6 {
offset-path: ray(-45deg closest-side);
offset-rotate: reverse -90deg;
}
</style>
<body>
<div class="circle" id="item1">1</div>
<div class="circle" id="item2">2</div>
<div class="circle" id="item3">3</div>
<div class="circle" id="item4">4</div>
<div class="circle" id="item5">5</div>
<div class="circle" id="item6">6</div>
</body>
Name: offset Value: [ <<'offset-position'>>? [ <<'offset-path'>> [ <<'offset-distance'>> || <<'offset-rotate'>> ]? ]? ]![ / <<'offset-anchor'>> ]? Applies to: transformable elements