Skip to content

[css-view-transitions] Normalize the exposed transform for ::view-transition-group() pseudos to be Viewport-relative. #11456

Open
@bramus

Description

@bramus

When setting up a View Transition, all transforms are relative to the snapshot containing block origin.

Relevant spec snippets:

Set capture’s old transform to a that would map element’s border box from the snapshot containing block origin to its current visual position.

Set transform to a transform that would map newRect from the snapshot containing block origin to its current visual position.

These transforms are then used in the ::view-transition-group’s keyframes (setting the starting position) and on the element itself (setting its ending position).

For example, when animating a position: fixed element in a browser that has a retractable top bar of 56px high, a top,left translation from 100,100 to 24,24 of that element results in the following transforms:

  • from transform: matrix(1, 0, 0, 1, 100, 156)
  • to transform: matrix(1, 0, 0, 1, 24, 80)

See this screenshot taken in Chrome on Android: the box got animated from position 24,24 as measured against the viewport (red outline + red arrow) but ends up being 24,80 when measured against the snapshot containing block (blue outline + blue arrow)

vt-snapshot-containing-block


When getting the keyframes of the resulting ::view-transition-group pseudo using animation.effect.getKeyframes() you end up with the following (simplified):

[
  {
    computedOffset: 0,
    transform: "matrix(1, 0, 0, 1, 100, 156)"
  },
  {
    computedOffset: 1,
    transform: "matrix(1, 0, 0, 1, 24, 80)"
  }
]

From an author POV these values are problematic, because the transforms contain values that are not relative to the coordinate space authors have access to, namely the (layout) viewport:

  • Extracting the start and end positions from these keyframes yields values that are off by <height-of-the-retractable-top-bar>
  • Doing something like animation.effect.setKeyframes(animation.effect.getKeyframes()) is destructive because the element has now shifted by <height-of-the-retractable-top-bar>. EDIT: This destructive behavior of animation.effect.setKeyframes(animation.effect.getKeyframes()) is not caused by the SCB, but by a Chrome bug.

To fix this issue I suggest that engines keep on using the snapshot containing block-relative offsets internally, but expose viewport-relative offsets to authors. The viewport as presented at the time of the new state would be used for this.

That way authors can rely on the keyframes for extracting the correct positional information and manipulate the generated keyframes without needing to worry about messing up the positions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions