<pre class='metadata'>
Title: Motion Path Module Level 1
Shortname: motion
Level: 1
Status: ED
Work Status: Refining
ED: https://drafts.fxtf.org/motion-1/
TR: https://www.w3.org/TR/motion-1/
Previous Version: https://www.w3.org/TR/2017/WD-motion-1-20170711/
Previous Version: https://www.w3.org/TR/2015/WD-motion-1-20150409/
Group: fxtf
Editor: Dirk Schulze, Adobe Inc., dschulze@adobe.com, w3cid 51803
Editor: Shane Stephens, Google, shanestephens@google.com, w3cid 47691
Editor: Jihye Hong, LG Electronics, jh.hong@lge.com, w3cid 79168
Editor: Eric Willigers, 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.
</pre>
<pre class=link-defaults>
spec:css-transforms-1; type:dfn;
    text:local coordinate system
</pre>

<style>
    /* Style for bikeshed variant of switch/case <dl>s */
    div.switch dl > dd > ol.only {
        margin-left: 0;
    }

    div.switch dl > dd > ol.algorithm {
        margin-left: -2em;
    }

    div.switch dl {
        padding-left: 2em;
    }
editors
    div.switch dl > dt {
        text-indent: -1.5em;
        margin-top: 1em;
    }

    div.switch dl > dt + dt {
        margin-top: 0;
    }

    div.switch dl > dt > p {
        display: inline;
    }

    div.switch dl > dt:before {
        content: '\21AA';
        padding: 0 0.5em 0 0;
        display: inline-block;
        width: 1em;
        text-align: right;
        line-height: 0.5em;
    }
</style>

Introduction {#intro}
=====================

<em>This section is not normative.</em>

Authors have possibilities to position objects like boxes or containers relative to each other or absolutely in their own coordinate system. CSS Transforms extends these possibilities with a set of transform functions allowing authors to mutate the object's <a>local coordinate system</a>. With CSS Animations and CSS Transitions, these static placements can change over a given period of time. Both kind of animations are powerful to express transitions in time but not suitable to describe transitions of location of an object over time.

This specification allows authors to specify a path. The object can be positioned, transitioned and animated along this path over a given period of time. The time may be static if no animation was specified.

<div class=example>
In the following example, a schematic of an air plane is animated along a path. The plane faces in the direction of the path at each position on the path.

<figure>
    <img src="images/motion-path.svg" width="470" height="120" alt="Example Path">
    <p class=caption>A black plane at different positions on a blue dotted path, rotated in the direction of the path.</p>
</figure>
</div>


Module interactions {#placement}
================================

This specification defines a set of CSS properties that affect the visual rendering of elements to which those properties are applied. These effects are applied after <a href="https://www.w3.org/TR/css-display-3/#box">box</a>es have been sized and positioned according to the <a href="https://www.w3.org/TR/CSS2/visuren.html" lt="Visual formatting model">Visual formatting model</a> from [[!CSS21]]. Some values of 'offset-path' and 'offset-position' result in the creation of a <a>stacking context</a> and <a href="https://www.w3.org/TR/CSS2/visuren.html#containing-block">containing block</a>.

Some CSS properties in this specification manipulate the user coordinate system of the element by transformations. These transformations are pre-multiplied to transformations specified by the 'transform' property or deriving properties defined in CSS Transform Module Level 1 [[!CSS-TRANSFORMS-1]], and post-multiplied to transformations specified by the individual transform properties 'translate', 'scale', and 'rotate', as <a href="https://drafts.csswg.org/css-transforms-2/#ctm">explained</a> in <a href="https://drafts.csswg.org/css-transforms-2/">CSS Transform Module Level 2</a>.


Values {#values}
================

This specification follows the <a href="https://www.w3.org/TR/CSS21/about.html#property-defs">CSS property definition conventions</a> from [[!CSS21]]. Basic shapes are defined in CSS Shapes Module Level 1 [[!CSS-SHAPES]]. Value types not defined in these specifications are defined in CSS Values and Units Module Level 3 [[!CSS3VAL]].

In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept CSS-wide keywords such as <a href="https://drafts.csswg.org/css-cascade-4/#valdef-all-initial">initial</a> and <a href="https://drafts.csswg.org/css-cascade-4/#valdef-all-inherit">inherit</a> as their property value [[!CSS3VAL]]. For readability it has not been repeated explicitly.


Motion Paths {#motion-paths-overview}
=====================================

The Motion Path module allows specifying the position of a box as the distance ('offset-distance') of the box's <a>anchor point</a> ('offset-anchor') along a geometrical path ('offset-path') defined against the coordinates ('offset-position') of its containing block. The box's orientation can optionally be specified as a rotation ('offset-rotate') with respect to the direction of the path at that point.

Define a path: The 'offset-path' property {#offset-path-property}
-----------------------------------------------------------------

<pre class=propdef>
Name: offset-path
Value: none | ''ray()'' | <a href="#offsetpath-pathfunc">path()</a> | <<url>> | [ <<basic-shape>> && <<coord-box>>? ] | <<coord-box>>
Initial: none
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Inherited: no
Percentages: n/a
Computed value: as specified
Media: visual
Animation type: by computed value
</pre>

Specifies the <dfn export>offset path</dfn>, 
a geometrical path the box gets positioned on, 
the <dfn export for="offset path">initial position</dfn> 
(where on the [=offset path=] the element is positioned at ''offset-distance: 0%''),
and the <dfn export for="offset path">initial direction</dfn>
(the initial orientation of the box (per 'offset-rotate') at the [=initial position=]).

Values have the following meanings:

<dl dfn-for=offset-path dfn-type=value>
    : <dfn>ray()</dfn> = ray( [ <<angle>> && <<size>> && contain? ] )
    ::
        : <<angle>>
        ::
            The <a>offset path</a> is a line segment that starts from the position of the box and proceeds in the direction defined by the specified <<angle>>. As with <a href="https://www.w3.org/TR/css3-images/#gradients">CSS gradients</a>, <<angle>> values are interpreted as bearing angles, with ''0deg'' pointing up and positive angles representing clockwise rotation.

        : <dfn for=offsetpath>&lt;size></dfn>
        :: 
            Decides the path length used when 'offset-distance' is expressed as a percentage, using the distance to the containing box. For <<size>> values other than <a href="#size-sides">sides</a>, the path length is independent of <<angle>>.

            It is defined as:

            &nbsp;<b>&lt;size&gt;</b> = [ closest-side | closest-corner | farthest-side | farthest-corner | sides ]

            <dl dfn-for="<size>">
                : <dfn for="<size>" id=size-closest-side>closest-side</dfn>
                :: The perpendicular distance is measured between the initial position and the closest side of the box from it.
                : <dfn for="<size>" id=size-closest-corner>closest-corner</dfn>
                :: The distance is measured between the initial position and the closest corner of the box from it.
                : <dfn for="<size>" id=size-farthest-side>farthest-side</dfn>
                :: The perpendicular distance is measured between the initial position and the farthest side of the box from it.
                : <dfn for="<size>" id=size-farthest-corner>farthest-corner</dfn>
                :: The distance is measured between the initial position and the farthest corner of the box from it.
                : <dfn for="<size>" id=size-sides>sides</dfn>
                :: The distance is measured between the initial position and the intersection of the ray with the box. If the initial position is not within the box, the distance is 0.
            </dl>

            Note: When the initial position is on one of the edges of the containing block, the closest side takes the edge that the initial position is on, and thus the path length used for percentage 'offset-distance' values is 0.

            Note: When <a href="#size-closest-side">closest-side</a> or <a href="#size-farthest-side">farthest-side</a> are used, and the initial position is outside the box, the sides are considered to extend indefinitely.

        : <dfn>contain</dfn>
        ::
            The used value of 'offset-distance' is clamped so that the box is entirely contained within the path.

            If no 'offset-distance' would lead to the box being enclosed by the path, the path size is minimally increased so that such an 'offset-distance' exists.

        

    : <<basic-shape>> && <<coord-box>>?
    ::
        The <a>offset path</a> is a basic shape as specified in CSS Shapes [[!CSS-SHAPES]].

        'offset-position' is ignored for circle and ellipse basic shapes with explicit center positions, and for other types of basic shapes. If a circle or ellipse basic shape has no explicit center position, the shape is centered at the ''initial position'' of the path, as described in 'offset-position'.

        The ''initial position'' for basic shapes are defined as follows:

        : <<circle()>>
        : <<ellipse()>>
        ::
            The ''initial position'' is defined by the point where a horizontal tangent to the circle/ellipse would reach the top vertical position.
        : <<inset()>>
        ::
            The ''initial position'' is the left end of the top horizontal line, immediately to the right of any 'border-radius' arc.
        : <<polygon()>>
        ::
            The ''initial position'' is defined by the first coordinate pair of the polygon.

            The ''initial direction'' is defined by the vector connecting.

            the ''initial position'' with the next following coordinate pair that isn't equal to the ''initial position''.

        The <<coord-box>> specified in combination with a <<basic-shape>> provides the reference box for the <<basic-shape>>. If no reference box is specified, it defaults to ''border-box''.

        Apart from polygons with non-zero length, the ''initial direction'' is 90 degrees (i.e. to the right).

        Note: This gives ''0deg'' rotation when 'offset-rotate' is ''auto''.

    : <<coord-box>>
    ::
        The ''initial position'' is the left end of the top horizontal line, immediately to the right of any 'border-radius' arc, and the ''initial direction'' is to the right.

    : <dfn function id=offsetpath-pathfunc>path()</dfn> = path(<<string>>)
    ::
        The <<string>> represents an SVG Path data string.
        The path data string must be conform to the grammar and parsing rules of SVG 1.1 [[!SVG11]].
        The ''initial position'' is defined by the first “move to” argument in the path string. For the ''initial direction'' follow SVG 1.1 [[!SVG11]].

    : <<url>>
    ::
        References an SVG <a>shape element</a> and uses its geometry as <a>offset path</a>.
        See SVG 1.1 for more information about the ''initial position'' and ''initial direction'' [[!SVG11]].

    : <dfn for=offsetpath id=offsetpath-none>none</dfn>
    ::
        No <a>offset path</a> gets created. When 'offset-path' is <a href="#offsetpath-none">none</a>, 'offset-distance' and 'offset-rotate' have no effect.
</dl>

A computed value of other than <a href="#offsetpath-none">none</a> results in the creation of a <a>stacking context</a> [[!CSS21]] and <a href="https://www.w3.org/TR/CSS2/visuren.html#containing-block">containing block</a>, per usual for <a href="https://drafts.csswg.org/css-transforms-1/#propdef-transform">transforms</a>.

A reference that fails to download, is not a reference to an SVG <a>shape element</a>, or is non-existent, is treated as equivalent to <code>path("m 0 0")</code>.

Note: This is a zero length path with <a href="https://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes">directionality</a> aligned with the positive x-axis.</p>

See the section <a href="#calculating-path-transform">“Calculating the path transform”</a> for how to use the <a>offset path</a> to compute the transform.

For SVG <a>shape element</a>s without associated CSS layout box, the <a>used value</a> for <a value for=mask-clip>content-box</a>, <a value for=mask-clip>padding-box</a>, <a value for=mask-clip>border-box</a> and <a value for=mask-clip>margin-box</a> is <a value for=clip-path>fill-box</a>.

For <a>shape element</a>s with associated CSS layout box, the <a>used value</a> for <a value for=clip-path>fill-box</a>, <a value for=clip-path>stroke-box</a> and <a value for=clip-path>view-box</a> is <a value for=mask-clip>border-box</a>.

### Examples Of ''ray()'' Positioning ### {#example-ray}

<div class=example>
    Here are some examples. The first example shows that some parts of boxes are outside of the <a>offset path</a>.
    <pre><code highlight=html>
    &lt;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);
        }
    &lt;/style>
    &lt;body>
        &lt;div class="box" id="redBox">&lt;/div>
        &lt;div class="box" id="blueBox">&lt;/div>
    &lt;/body>
    </code></pre>
    <figure>
        <img alt="An image of boxes positioned without contain" src="images/offset_distance_without_contain.png" style="width: 200px;"/>
        <figcaption>'offset-path' without 'contain'</figcaption>
    </figure>

    In the second example, 'contain' is given to the 'offset-path' value of each box
    to avoid overflowing.
    <pre><code highlight=html>
    &lt;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);
        }
    &lt;/style>
    &lt;body>
        &lt;div class="box" id="redBox">&lt;/div>
        &lt;div class="box" id="blueBox">&lt;/div>
    &lt;/body>
    </code></pre>
    <figure>
        <img alt="An image of boxes positioned with contain" src="images/offset_distance_with_contain.png" style="width: 200px;"/>
        <figcaption>'offset-path' with 'contain'</figcaption>
    </figure>

    In the third example, the path size is increased so that the box can be contained. The <a>used offset distance</a> is negative.
    <pre><code highlight=html>
    &lt;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);
        }
    &lt;/style>
    &lt;body>
        &lt;div class="box" id="blueBox">&lt;/div>
    &lt;/body>
    </code></pre>
    <figure>
        <img alt="An image of an increased path size" src="images/increase-size.svg" style="width: 400px; height: 335;"/>
        <figcaption>'offset-path' with path size increased</figcaption>
    </figure>

    In the fourth example, the initial position is outside the containing block.
    <pre><code highlight=html>
    &lt;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);
        }
    &lt;/style>
    &lt;div id="container">
        &lt;div class="box" id="redBox">&lt;/div>
        &lt;div class="box" id="blueBox">&lt;/div>
    &lt;/div>
    </code></pre>
    <figure>
        <img alt="An image with initial position outside the containing block" src="images/initial-outside.svg" style="width: 700px;" />
        <figcaption>Initial position outside the containing block</figcaption>
    </figure>
</div>

### Examples Of <<basic-shape>> Positioning ### {#example-shape}

<div class=example>
    This example uses a circle with implicit center position.
    <pre><code highlight=html>
    &lt;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;
        }
    &lt;/style>
    &lt;body>
        &lt;div class="item">&lt;/div>
        &lt;div class="item" id="middle">&lt;/div>
        &lt;div class="item">&lt;/div>
    &lt;/body>
    </code></pre>
    <figure>
        <img src="images/normal-flow.svg" width="505" height="324" alt="Normal flow determining circle center">
        <figcaption>The circle center is determined by normal flow.</figcaption>
    </figure>
</div>

### Examples of <<coord-box>> Positioning ### {#example-coord}

<div class=example>
    This example shows how <<coord-box>> <a>offset path</a> works in combination with 'border-radius'.

    <pre><code highlight=html>
    &lt;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;
        }
    &lt;/style>
    &lt;body>
        &lt;div id="blueBox">&lt;/div>
    &lt;/body>
    </code></pre>
    <figure>
        <img alt="An image of example for geometry-box with border-radius" src="images/geometry-box.svg" style="width: 470px; text-align: center"/>
        <figcaption>The [=initial position=] is the left end of the top horizontal line.</figcaption>
    </figure>
</div>


Position on the path: The 'offset-distance' property {#offset-distance-property}
--------------------------------------------------------------------------------

<pre class=propdef>
Name: offset-distance
Value: <<length-percentage>>
Initial: 0
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Inherited: no
Percentages: refer to the total path length
Computed value: a computed <<length-percentage>> value
Media: visual
Animation type: by computed value
</pre>

Specifies the position of the box as a distance along the <a>offset path</a>.

<dl dfn-for="offset-distance" dfn-type="value">
    : <<length-percentage>>
    ::
        Specifies the distance from the ''initial position'' of the <a>offset path</a> to the position of the box’s <a>anchor point</a>.

        Percentages are relative to the length of the <a>offset path</a>-- that is, the distance between the ''initial position'' and the end position of the <a>offset path</a>.
</dl>

### Calculating the computed distance along a path ### {#calculating-the-computed-distance-along-a-path}

Processing the distance along an <a>offset path</a> operates differently depending upon the nature of the <a>offset path</a>:

* References to <<angle>> <a>offset path</a>s with contain are unclosed intervals.
* References to <<angle>> <a>offset path</a>s without contain are unbounded rays.
* All basic CSS shapes are closed loops.
* <a>Offset path</a>s (including references to SVG Paths) are closed loops only if the final command in the path list is a closepath command ("z" or "Z"), otherwise they are unclosed intervals.
* References to SVG circles, ellipses, images, polygons and rects are closed loops.
* References to SVG lines and polylines are unclosed intervals.

To determine the <dfn>used offset distance</dfn> for a given <a>offset path</a> and <dfn>offset distance</dfn>:

1. Let the <dfn>total length</dfn> be the total length of <a>offset path</a> with all sub-paths.
2. Convert <a>offset distance</a> to pixels, with 100% being converted to <a>total length</a>.
3. <dl class=switch>
        : If <a>offset path</a> is an unbounded ray:
        :: Let <a>used offset distance</a> be equal to <a>offset distance</a>.
        : Otherwise if <a>offset path</a> is an <<angle>> path with contain:
        :: Let <a>used offset distance</a> be equal to <a>offset distance</a>, clamped so that the box lies entirely within the path.
        : If <a>offset path</a> is any other unclosed interval:
        :: Let <a>used offset distance</a> be equal to <a>offset distance</a> clamped by 0 and the total length of the path.
        : Otherwise <a>offset path</a> is a closed loop:
        :: Let <a>used offset distance</a> be equal to <a>offset distance</a> modulo the total length of the path. If the total length of the path is 0, <a>used offset distance</a> is also 0.

            Note: “Modulo” here uses the traditional mathematical definition,
            where the output is always non-negative.
    </dl>



<div class=example>
This example shows boxes placed along an unclosed interval.

<pre><code highlight=html>
&lt;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%;
    }
&lt;/style>
&lt;body>
    &lt;div class="item" id="box1">&lt;/div>
    &lt;div class="item" id="box2">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img src="images/offset-distance-unclosed.svg" style="width: 700px;"
         alt="An example of boxes placed along an unclosed interval"/>
    <figcaption>An example of boxes placed along an unclosed interval</figcaption>
</figure>
</div>

<div class=example>
This example shows boxes placed along a closed interval.

<pre><code highlight=html>
&lt;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%;
    }
&lt;/style>
&lt;body>
    &lt;div class="item" id="box1">&lt;/div>
    &lt;div class="item" id="box2">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img src="images/offset-distance-closed.svg" style="width: 700px;"
         alt="An example of boxes placed along a closed interval"/>
    <figcaption>An example of boxes placed along a closed interval</figcaption>
</figure>
</div>

<div class=example>
This example shows a way to align boxes within the polar coordinate system using 'offset-path', 'offset-distance'.

<pre><code highlight=html>
&lt;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%;
    }
&lt;/style>
&lt;body>
    &lt;div class="circleBox" id="circle1">&lt;/div>
    &lt;div class="circleBox" id="circle2">&lt;/div>
    &lt;div class="circleBox" id="circle3">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An image of three boxes positioned to polar coordinates" src="images/simple_offset_position.png" style="width: 300px;"/>
    <figcaption>An example of positioning box in polar coordinates</figcaption>
</figure>
</div>


Define the starting point of the path: The 'offset-position' property {#offset-position-property}
-------------------------------------------------------------------------------------------------

<pre class=propdef>
Name: offset-position
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Value: auto | <<position>>
Initial: auto
Media: visual
Inherited: no
Percentages: Refer to the size of containing block
Computed value: For <<length>> the absolute value, otherwise a percentage.
Animation type: by computed value
</pre>

Specifies the ''initial position'' of the <a>offset path</a>. If 'position' is specified with ''static'', 'offset-position' would be ignored.

Values are defined as follows:
<dl dfn-for="offset-position" dfn-type="value">
    : <var>auto</var>
    ::
        Indicates the ''initial position'' is the position of the box specified with 'position' property.

        Note: When 'position' is ''static'' and 'offset-position' is ''auto'' (and not ignored due to 'offset-path'), we have positioning relative to <a href="https://drafts.csswg.org/css-position-3/#normal-flow">normal flow</a>.

    : <<position>>
    ::
        Specifies the ''initial position'', with the the containing block as the positioning area and a dimensionless point (zero-sized box) as the object area.

        Note: This is similar to absolute positioning, except that 'offset-position' does not prevent boxes from impacting the layout of later siblings.
</dl>

A computed value of other than ''auto'' results in the creation of a <a>stacking context</a> [[!CSS21]] and <a href="https://www.w3.org/TR/CSS2/visuren.html#containing-block">containing block</a>, per usual for <a href="https://drafts.csswg.org/css-transforms-1/#propdef-transform">transforms</a>.

'offset-position' is ignored if 'offset-path' is a geometry-box, or a basic shape (other than a circle or ellipse with implicit center). In these cases, the geometry-box or basic shape specifies the ''initial position''.

<div class=example>
This example shows positioning a box with 'offset-position'.

<pre><code highlight=html>
&lt;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);
    }
&lt;/style>
&lt;body>
    &lt;div id="wrap">
        &lt;div id="box">&lt;/div>
    &lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An image of offset-position: auto" src="images/offset_position_auto.png" width="300"/>
    <figcaption>An example when ''auto'' is given to 'offset-position'</figcaption>
</figure>
</div>

<div class=example>
This example shows the interaction with the 'transform' property, and with an individual transform property ('rotate'). The motion path transform is a vertical translation moving ('left', 'top') to 'offset-position'.

<pre><code highlight=html>
&lt;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 */
    }
&lt;/style>
&lt;body>
    &lt;div id="wrap">
        &lt;div class="item" id="box1">&lt;/div>
        &lt;div class="item" id="box2">&lt;/div>
        &lt;div class="item" id="box3">&lt;/div>
        &lt;div class="item" id="box4">&lt;/div>
    &lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An example when motion path and other transforms interact" src="images/position-transform.svg" width="400" height="350"/>
    <figcaption>An example when motion path and other transforms interact</figcaption>
</figure>
</div>

<div class=example>
This example uses 'position' ''static'', so 'offset-position' generates translations from the <a href="https://drafts.csswg.org/css-position/#normal-flow">normal flow</a> positions. By amplifying these translations using 'scale', the normal flow is rotated 180 degrees around the 'offset-position', and the boxes are exploded away from each other.

<pre><code highlight=html>
&lt;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;
    }
&lt;/style>
&lt;body>
    &lt;div id="wrap">
        &lt;div>
            &lt;span id="box1">&lt;/span>&lt;span id="box2">&lt;/span>
        &lt;/div>
        &lt;div>
            &lt;span id="box3">&lt;/span>&lt;span id="box4">&lt;/span>
        &lt;/div>
    &lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An example when motion path and scale interact" src="images/position-scale.svg" width="604" height="304"/>
    <figcaption>An example when motion path and scale interact</figcaption>
</figure>
</div>

<div class=example>
In this example, each 'offset-position' value is ignored as 'offset-path' is a <<geometry-box>>, but the other offset properties combine to have an effect equivalent to that for 'offset-position' 'right bottom'.

<pre><code highlight=html>
&lt;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 */
    }
&lt;/style>
&lt;body>
    &lt;div id="wrap">
        &lt;div class="item" id="box1">&lt;/div>
        &lt;div class="item" id="box2">&lt;/div>
        &lt;div class="item" id="box3">&lt;/div>
        &lt;div class="item" id="box4">&lt;/div>
    &lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An example when offset-position is ignored" src="images/position-absolute.svg" width="550" height="430"/>
    <figcaption>An example when offset-position is ignored</figcaption>
</figure>
</div>


Define an anchor point: The 'offset-anchor' property {#offset-anchor-property}
------------------------------------------------------------------------------

<pre class=propdef>
Name: offset-anchor
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Value: auto | <<position>>
Initial: auto
Media: visual
Inherited: no
Percentages: Relative to the width and the height of a box
Computed value: For <<length>> the absolute value, otherwise a percentage.
Animation type: by computed value
</pre>

Defines an <a>anchor point</a> of the box positioned along the <a>offset path</a>. The <dfn>anchor point</dfn> specifies the point of the box which is to be considered as the point that is moved along the <a>offset path</a>.

Values have the following meanings:
<dl dfn-for="offset-anchor" dfn-type="value">
    : <var>auto</var>
    ::
        Computes to the value from 'offset-position', provided 'offset-path' is <a href="#offsetpath-none">none</a> and 'offset-position' is not ''auto''. Otherwise, computes to the value from 'transform-origin'. When ''auto'' is given to 'offset-anchor', and 'offset-path' is <a href="#offsetpath-none">none</a>, 'offset-position' behaves similar to 'background-position'.
    : <<position>>
    ::
        : <<percentage>>
        ::
            A percentage for the horizontal offset is relative to width of content area. A percentage for the vertical offset is relative to the height of the content area. For example, with a value pair of '100%, 0%', an <a>anchor point</a> is on the upper right corner of the box.
        : <<length>>
        :: A length value gives a length offset from the upper left corner of the box's content area.
</dl>

<div class=example>
The following explains how to set the <a>anchor point</a> of the box.

<pre><code highlight=html>
#plane {
    offset-anchor: center;
}
</code></pre>

The red dot in the middle of the shape indicates the <a>anchor point</a> of the shape.
<figure>
    <img src="images/plane.svg" width="160" height="140" alt="Shape with its anchor point">
    <figcaption>A red dot in the middle of a plane shape indicates the shape's <a>anchor point</a>.</figcaption>
</figure>
</div>

<div class=example>
This example shows an alignment of four boxes with different <a>anchor point</a>s.

<pre><code highlight=html>
&lt;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;
    }
&lt;/style>
&lt;body>
    &lt;div class="box" id="item1">&lt;/div>
    &lt;div class="box" id="item2">&lt;/div>
    &lt;div class="box" id="item3">&lt;/div>
    &lt;div class="box" id="item4">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img src="images/offset_anchor.png" alt="An example of offset-anchor" style="width: 300px;">
    <figcaption>An example of 'offset-anchor'</figcaption>
</figure>
</div>

<div class=example>
This example shows boxes centered at their offset-position.

<pre><code highlight=html>
&lt;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%;
    }
&lt;/style>
&lt;body>
    &lt;div class="box" id="item1">&lt;/div>
    &lt;div class="box" id="item2">&lt;/div>
    &lt;div class="box" id="item3">&lt;/div>
    &lt;div class="box" id="item4">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img src="images/offset_anchor_center.svg" alt="An example of offset-anchor: center">
    <figcaption>An example of 'offset-anchor: center'</figcaption>
</figure>
</div>

<div class=example>
This example shows how offset-anchor computes to their offset-position.

<pre><code highlight=html>
&lt;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%;
    }
&lt;/style>
&lt;body>
    &lt;div class="box" id="item1">&lt;/div>
    &lt;div class="box" id="item2">&lt;/div>
    &lt;div class="box" id="item3">&lt;/div>
    &lt;div class="box" id="item4">&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img src="images/offset_anchor_auto.svg" alt="An example of offset-anchor: auto">
    <figcaption>An example of 'offset-anchor: auto'</figcaption>
</figure>
</div>


Rotation at point: The 'offset-rotate' property {#offset-rotate-property}
-------------------------------------------------------------------------

<pre class=propdef>
Name: offset-rotate
Value: [ auto | reverse ] || <<angle>>
Initial: auto
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Inherited: no
Percentages: n/a
Computed value: computed <<angle>> value, optionally preceded by auto
Media: visual
Animation type: by computed value
</pre>

Defines the orientation of the box while positioning along the <a>offset path</a>.

Values have the following meanings:

<dl dfn-for="offset-rotate" dfn-type="value">
    : <dfn>auto</dfn>
    ::
        Indicates that the object is rotated (over time if 'offset-distance' is animated) by the angle of the direction (i.e., directional tangent vector) of the <a>offset path</a>, relative to the positive x-axis. If specified in combination with <<angle>>, the computed value of <<angle>> is added to the computed value of ''auto''.

        Note: For ray paths, the rotation implied by ''auto'' is 90 degrees less than the ray's bearing <<angle>>.

    : <dfn>reverse</dfn>
    ::
        Indicates that the object is rotated (over time if 'offset-distance' is animated) by the angle of the direction (i.e., directional tangent vector) of the <a>offset path</a>, relative to the positive x-axis, plus 180 degrees. If specified in combination with <<angle>>, the computed value of <<angle>> is added to the computed value of ''reverse''.

        Note: This is the same as specifying ''auto 180deg''.
    : <<angle>>
    ::
        Indicates that the box has a constant clockwise rotation transformation applied to it by the specified rotation angle. See definitions of ''auto'' or ''reverse'' if specified in combination with either one of the keywords.
</dl>

When the <a>offset path</a> is a zero length path, the value of 'offset-rotate' is 0 degree, the direction of the positive x-axis.

If the <a>offset path</a> is composed of multiple line segments, the orientation at the connection between the segments is the direction of the "later" segment. 
(This matches SVG's notion of <l spec=svg2>[=direction of a path=]</l>.)

Note: The rotation described here does not override or replace any rotation defined by the 'transform' property.

<div class=example>
The following examples use the shape of a plane. The red dot in the middle of the shape indicates the <a>anchor point</a> of the shape. When no offset properties are set, the shape is not translated or rotated along the path.

<figure>
    <img src="images/offset-initial.svg" width="470" height="120" alt="Path without offset">
    <figcaption>A black plane at the beginning of the path, with no offset properties set.</figcaption>
</figure>

When the shape's <a>anchor point</a> is placed at different positions along the path and 'offset-rotate' is ''0deg'', the shape is not rotated.

<figure>
    <img src="images/offset-rotate-none.svg" width="470" height="120" alt="Path without rotation">
    <figcaption>A black plane at different positions on a blue dotted path without
    rotation transforms.</figcaption>
</figure>

If the 'offset-rotate' property is set to ''auto'', and the shape's <a>anchor point</a> is placed at different positions along the path, the shape is rotated based on the gradient at the current position and faces the direction of the path at this position.

<figure>
    <img src="images/offset-rotate-auto.svg" width="470" height="120" alt="Path with auto rotation">
    <figcaption>A black plane at different positions on a blue dotted path,
    rotated in the direction of the path.</figcaption>
</figure>

In this example, the 'offset-rotate' property is set to ''reverse''. The plane faces the opposite direction of the path at each position on the path.

<figure>
    <img src="images/offset-rotate-reverse.svg" width="470" height="120" alt="Path with reverse auto rotation">
    <figcaption>A black plane at different positions on a blue dotted path,
    rotated in the opposite direction of the path.</figcaption>
</figure>

The last example sets the 'offset-rotate' property to ''-45deg''. The shape is rotated anticlockwise by 45 degree once and keeps the rotation at each position on the path.

<figure>
    <img src="images/offset-rotate-45.svg" width="470" height="120" alt="Path with fixed rotation">
    <figcaption>A black plane at different positions on a blue dotted path,
    rotated by a fixed amount of degree.</figcaption>
</figure>
</div>

<div class=example>
This example shows how ''auto'' or ''reverse'' work when specified in combination
with <<angle>>.
The computed value of <<angle>> is added to the computed value of ''auto'' or ''reverse''.

<pre><code highlight=html>
&lt;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;
    }
&lt;/style>
&lt;body>
    &lt;div class="circle" id="item1">1&lt;/div>
    &lt;div class="circle" id="item2">2&lt;/div>
    &lt;div class="circle" id="item3">3&lt;/div>
    &lt;div class="circle" id="item4">4&lt;/div>
    &lt;div class="circle" id="item5">5&lt;/div>
    &lt;div class="circle" id="item6">6&lt;/div>
&lt;/body>
</code></pre>
<figure>
    <img alt="An image of example for offset-rotate" src="images/rotate_by_angle_with_auto.png" style="width: 250px; text-align: center"/>
    <figcaption>The boxes are rotated by the value of ''auto'' with a fixed amount of degree.</figcaption>
</figure>
</div>


### Calculating the path transform ### {#calculating-path-transform}

<div class=switch>
    1. Create a supplemental transformation matrix <dfn>T1</dfn> for the local coordinate system of the box.
    2. Find the ''initial position'' of the <a>offset path</a> specified by 'offset-position' as <dfn>T2</dfn>.
    3. Let <dfn>P</dfn> be the point at the <a>used offset distance</a> along the <a>offset path</a>.
    4. Find the translation of the box such that its <a>anchor point</a> is placed at <a>P</a>, and apply that to <a>T2</a>.
    5. Post-multiply <a>T2</a> by the rotation specified by 'offset-rotate'.
    6. Post-multiply <a>T2</a> to <a>T1</a>.
    7. Post-multiply <a>T1</a> to the local coordinate system of the box.
</div>

Issue: Do we need to say how to get the position in more detail?

Issue: There needs to be a process for converting ''rotate()'' to an angle.


Offset shorthand: The 'offset' property {#offset-shorthand}
-----------------------------------------------------------

<pre class=propdef>
Name: offset
Value: [ 'offset-position'? [ 'offset-path' [ 'offset-distance' || 'offset-rotate' ]? ]? ]! <br> [ / 'offset-anchor' ]?
Initial: see individual properties
Applies to: <a href="https://drafts.csswg.org/css-transforms-1/#transformable-element">transformable elements</a>
Inherited: no
Percentages: see individual properties
Computed value: see individual properties
Media: visual
Animation type: see individual properties
</pre>

This is a shorthand property for setting 'offset-position', 'offset-path', 'offset-distance', 'offset-rotate' and 'offset-anchor'. Omitted values are set to their initial values.


Privacy and Security Considerations {#priv-sec}
===============================================

This specification introduces no new security or privacy considerations.

<h2 class=no-num id=changes>Changes</h2>

<em>This section is non-normative.</em>

The following changes were made since the <a href="https://www.w3.org/TR/2015/WD-motion-1-20150409/">9 April 2015 First Public Working Draft</a>.

* Renamed <a href="https://www.w3.org/TR/2015/WD-motion-1-20150409/#motion-path-property">motion-path</a> to 'offset-path' for integrating with <a href="https://www.w3.org/TR/2016/WD-css-round-display-1-20160301/#polar-angle-property">polar-angle</a>.
    * Added the ''ray()'' to define an <a>offset path</a> as a line segment which direction is specified by <<angle>>.
    * Added <<size>> and 'contain' value for the ''ray()''.
* Renamed <a href="https://www.w3.org/TR/2015/WD-motion-1-20150409/#propdef-motion-offset">motion-offset</a> to 'offset-distance' for integrating with <a href="https://www.w3.org/TR/2016/WD-css-round-display-1-20160301/#polar-distance-property">polar-distance</a>.
* Renamed <a href="https://www.w3.org/TR/2015/WD-motion-1-20150409/#propdef-motion-rotation">motion-rotation</a> to 'offset-rotate'.
* Added 'offset-position' to specify the ''initial position'' of the path by merging <a href="https://www.w3.org/TR/2016/WD-css-round-display-1-20160301/#polar-origin-property">polar-origin</a> from [[CSS-ROUND-DISPLAY-1]].
* Added 'offset-anchor' to specify the origin point of the element by merging <a href="https://www.w3.org/TR/2016/WD-css-round-display-1-20160301/#polar-anchor-property">polar-anchor</a> from [[CSS-ROUND-DISPLAY-1]].
* Renamed the shorthand property <a href="https://www.w3.org/TR/2015/WD-motion-1-20150409/#propdef-motion">motion</a> to 'offset'.
* Made 'offset-rotate' specify the rotation transformation by ''auto'' or ''reverse'' in combination with <<angle>>.

<h2 class=no-num id=acknowledgments>Acknowledgments</h2>

<p>Thanks to
fantasai,
Hyojin Song,
and
all the rest of the CSS WG members
for their reviews, comments, and corrections.</p>
