Skip to content

[css-view-transitions-1] Add snapshot viewport concept #8037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 82 additions & 36 deletions css-view-transitions-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
```

Note: This pseudo-element provides a containing block for all ''::view-transition-group()'' pseudo-elements.
The aim of the style is to size the pseudo-element to cover the [=large viewport size=]
and position all ''::view-transition-group()'' pseudo-elements relative to the origin of the large viewport.
The aim of the style is to size the pseudo-element to cover the [=snapshot viewport=]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized this PR missed the part about UA styles on this pseudo-element. inset: 0 is no longer correct.

  • The first part is updating the style block for html::view-transition to:

       position: fixed;
       top: 0;
       left: 0;
  • The second part is to add a point in Style transition pseudo-elements algorithm. Something like:

    1. Let |root| be the ''::view-transition'' pseudo-element.
      1. Set "width" and "height" to snapshot viewport bounds.
      2. Set "transform" to a CSS transform that would place element at snapshot viewport origin.

and position all ''::view-transition-group()'' pseudo-elements relative to the [=snapshot viewport origin=].

: <dfn>::view-transition-group( <<pt-name-selector>> )</dfn>
:: One of these pseudo-elements exists for each 'view-transition-name' in a view transition,
Expand Down Expand Up @@ -393,6 +393,30 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
:: a boolean. Initially false.
</dl>

## The snapshot viewport ## {#snapshot-viewport-concept}

The <dfn>snapshot viewport</dfn> covers all areas of the window that could potentially display web content. This area is consistent regardless of transitionary UI that overlays content, or reduces the size of other viewports, such as scrollbars, virtual keyboards, or URL bars that can be scrolled away.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Break at "This area is..." for semantic line-feed. Probably the same at, ", or reduces the..."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good catch. I think there are a few other places I didn't correctly apply the formatting too,


<figure>
<img src="phone-browser.svg" width="200" height="335" alt="A diagram of a phone screen, including a top status bar, a browser URL bar, web-content area with a floating scrollbar, a virtual keyboard, and a bottom bar with an OS back button">
<img src="phone-browser-snapshot-viewport.svg" width="200" height="335" alt="The previous diagram, but highlights the area that's the 'snapshot' viewport, which includes everything except the top status bar and the bottom bar with the OS back button">
<figcaption>
An example of the [=snapshot viewport=] on a mobile OS. The snapshot includes the URL bar, as this can be scrolled away. The keyboard is included as this appears and disappears. The top and bottom bars are part of the OS rather than the browser, so they're not included in the snapshot viewport.
</figcaption>
</figure>

<figure>
<img src="desktop-browser.svg" width="132" height="79" alt="A diagram of a desktop browser window, including a tab bar, a URL bar, and a web-content area featuring both horizontal and vertical scrollbars" style="height:auto; width: 600px">
<img src="desktop-browser-snapshot-viewport.svg" width="132" height="79" alt="The previous diagram, but highlights the area that's the 'snapshot' viewport, which includes the web content area and the scrollbars" style="height:auto; width: 600px">
<figcaption>
An example of the [=snapshot viewport=] on a desktop OS. This includes the scrollbars, but does not include the URL bar, as web content never appears in that area.
</figcaption>
</figure>

This means the snapshot canvas size is likely to be consistent for the [=document element=]'s [=captured element/old image=] and [=captured element/new element=].

The <dfn>snapshot viewport origin</dfn> refers to the start of the block and inline of the [=snapshot viewport=].

# API # {#api}

## Additions to {{Document}} ## {#additions-to-document-api}
Expand Down Expand Up @@ -640,19 +664,18 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;

: 'transform'
:: A CSS transform that would place |element|
from the layout viewport origin to its current quad.
from the [=snapshot viewport origin=] to its current quad.
:: This value is identity for the [=document element=].

: 'width'
: 'height'
:: The width and height of |element|'s border box.
:: This value is the bounds of the initial containing block for the [=document element=].
:: The size of the [=snapshot viewport=] if |element| is the [=document element=],
otherwise, the width and height of |element|'s border box.

: 'object-view-box'
:: An 'object-view-box' value that,
when applied to the old image,
will cause the view box to coincide with |element|'s [=border box=]
in the image.
:: ''object-view-box/none'' if |element| is the [=document element=],
otherwise, an 'object-view-box' value that, when applied to the old image,
will cause the view box to coincide with |element|'s [=border box=] in the image.

: 'writing-mode'
:: The 'writing-mode' of |element|.
Expand Down Expand Up @@ -755,7 +778,7 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
1. [=skip the view transition=] |transition| with |r|.
</div>

## skip the view transition ## {#skip-the-view-transition-algorithm}
## Skip the view transition ## {#skip-the-view-transition-algorithm}

<div algorithm>
To <dfn>skip the view transition</dfn> for {{ViewTransition}} |transition| with reason |reason|:
Expand Down Expand Up @@ -795,33 +818,57 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
To <dfn lt="capture the image|capturing the image">capture the image</dfn> given an {{Element}} |element|, perform the following steps.
They return an image.

1. Render the referenced element and its descendants,
at the same size that they would be in the document,
over an infinite transparent canvas with the following characteristics:
1. If |element| is the [=document element=], then:

1. Render the region of the |element| that intersects the [=snapshot viewport=],
on a transparent canvas the size of the [=snapshot viewport=],
following the [=capture rendering characteristics=], and these additional characteristics:

- Areas outside |element|'s [=scrolling box=] should be rendered as if they were scrolled to, without moving or resizing the [=layout viewport=].
This must not trigger events related to scrolling or resizing, such as {{IntersectionObserver}}s.

Issue: "scrolling box" and "layout viewport" are not exported. They either need exporting, or replaced with better references.

* The origin of |element|'s [=ink overflow rectangle=] is anchored to canvas origin.
- Areas that cannot be scrolled to (i.e. they are out of scrolling bounds),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share an example for this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On mobile, when the document is scrolled to the very top, the URL bar is not overlaying content. I assume the same can happen with the bottom of the page when the keyboard is open.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

The resolution was that we won't paint occluded elements which can't be scrolled to but the root element background will be painted there. For example if an element has the following CSS:

position: fixed;
top: -10px;
left: -10px;

It could be occluded by the URL bar and the user can't scroll to it. So we should skip painting this element, but the area should have the root element background. That could be a color or a repeated image.

The current spec text indicates that this area should be transparent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG other than updating for this. phone-browser-scrolled-to-top-with-url.svg also shows that the area under the URL bar in the snapshot is transparent but we should paint the root background there (it should have the blue color).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, I'd forgotten to push. Done!

should render transparent.

* If the referenced element has a transform applied to it (or its ancestors),
then the transform is ignored.
1. Return the canvas as an image.
The natural size of the image is equal to the [=snapshot viewport=].

Note: This transform is applied to the snapshot using the `transform` property of the associated ''::view-transition-group'' pseudo-element.
1. Otherwise:

1. Render |element| and its descendants,
at the same size it appears in its [=node document=],
over an infinite transparent canvas,
following the [=capture rendering characteristics=].

* [=list/For each=] |descendant| of [=shadow-including descendant=] {{Element}} and [=pseudo-element=] of |element|,
if |descendant| has a [=computed value=] of 'view-transition-name' that is not ''view-transition-name/none'',
then skip painting |descendant|.
1. Let |interestRectangle| be the result of [=computing the interest rectangle=] for |element|.

Note: This is necessary since the descendant will generate its own snapshot which will be displayed and animated independently.
Note: The |interestRectangle| is the subset of |element|'s [=ink overflow rectangle=] that should be captured.
This is required for cases where an element's ink overflow rectangle needs to be clipped because of hardware constraints.
For example, if it exceeds the maximum texture size.

Issue: Refactor this so the algorithm takes a set of elements that will be captured. This centralizes the logic for deciding if an element should be included or not.
1. Return the portion of the canvas within |interestRectangle| as an image.
The natural size of the image is equal to the |interestRectangle| bounds.
</div>

<div algorithm>
The <dfn>capture rendering characteristics</dfn> are as follows:

1. Let |interestRectangle| be the result of [=computing the interest rectangle=] for |element|.
* The origin of |element|'s [=ink overflow rectangle=] is anchored to canvas origin.

Note: The |interestRectangle| is the subset of |element|'s [=ink overflow rectangle=] that should be captured.
This is required for cases where an element's ink overflow rectangle needs to be clipped because of hardware constraints.
For example, if it exceeds the maximum texture size.
* If the referenced element has a transform applied to it (or its ancestors),
then the transform is ignored.

1. Return the portion of the canvas within |interestRectangle| as an image.
The natural size of the image is equal to the |interestRectangle| bounds.
Note: This transform is applied to the snapshot using the `transform` property of the associated ''::view-transition-group'' pseudo-element.

* [=list/For each=] |descendant| of [=shadow-including descendant=] {{Element}} and [=pseudo-element=] of |element|,
if |descendant| has a [=computed value=] of 'view-transition-name' that is not ''view-transition-name/none'',
then skip painting |descendant|.

Note: This is necessary since the descendant will generate its own snapshot which will be displayed and animated independently.

Issue: Refactor this so the algorithm takes a set of elements that will be captured. This centralizes the logic for deciding if an element should be included or not.
</div>

## [=Update transition DOM=] ## {#update-transition-dom-algorithm}
Expand Down Expand Up @@ -878,16 +925,15 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
## [=Compute the interest rectangle=] ## {#compute-the-interest-rectangle-algorithm}

<div algorithm>
To <dfn lt="computing the interest rectangle|compute the interest rectangle">compute the interest rectangle</dfn> of an {{Element}} |el|, perform the following steps.
To <dfn lt="computing the interest rectangle|compute the interest rectangle">compute the interest rectangle</dfn> of an {{Element}} |element|, perform the following steps.
They return a rectangle.

1. If |el| is the document's [=document element=],
then return a rectangle that is the intersection of the layout viewport,
including the size of rendered scrollbars (if any),
with |el|'s ink overflow rectangle.
1. Assert: |element| is not |element|'s [=node document=]'s [=document element=].

Note: The [=document element=] is captured differently, as specified in [=capture the image=].

1. If |el|'s [=ink overflow area=] does not exceed an implementation-defined maximum size,
then return a rectangle that is equal to |el|'s [=ink overflow rectangle=].
1. If |element|'s [=ink overflow area=] does not exceed an implementation-defined maximum size,
then return a rectangle that is equal to |element|'s [=ink overflow rectangle=].

1. Otherwise:

Expand Down Expand Up @@ -1041,7 +1087,7 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;

1. Set |height| to the current height of |capturedElement|'s [=new element=]'s [=border box=].

1. Set |transform| to a transform that maps the |capturedElement|'s [=new element=]'s [=border box=] from document origin to its quad in layout viewport.
1. Set |transform| to a transform that maps the |capturedElement|'s [=new element=]'s [=border box=] from document origin to its quad from the [=snapshot viewport origin=].

1. Set |writingMode| to the [=computed value=] of 'writing-mode' on |capturedElement|'s [=new element=].

Expand Down
Loading