Skip to content
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

feat: Editorial review: Add content for overlay and discrete animation features #29943

Merged
merged 36 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0c09617
feat: Add content for overlay and discrete animation features
chrisdavidmills Sep 11, 2023
25f6a67
Add rest of required updates
chrisdavidmills Sep 13, 2023
8cc056f
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Sep 27, 2023
8fdd02c
Improving popover transition examples based on josepharhar feedback
chrisdavidmills Sep 27, 2023
31142db
improve popover keyframe example with beforetoggle
chrisdavidmills Oct 10, 2023
44363dd
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Oct 10, 2023
3e5bd55
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Oct 31, 2023
39f6bb2
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 1, 2023
cc7e120
Making fixes for OnkarRuikar comments
chrisdavidmills Nov 1, 2023
d9365ad
Apply fixes based on estelle and dipikabh comments
chrisdavidmills Nov 2, 2023
b6368b0
mre fixes for estelle and OnkarRuikar comments
chrisdavidmills Nov 6, 2023
012fad4
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 6, 2023
0296fb0
Making fixes for next round of estelle comments
chrisdavidmills Nov 7, 2023
48ae18f
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 7, 2023
d8727bb
Fixes for next round of estelle comments
chrisdavidmills Nov 8, 2023
e83cce9
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 9, 2023
41105a8
comma
estelle Nov 13, 2023
b289c4a
Update files/en-us/web/api/cssstartingstylerule/index.md
chrisdavidmills Nov 14, 2023
506100e
Update files/en-us/web/api/cssstartingstylerule/index.md
chrisdavidmills Nov 14, 2023
e2937ee
Update files/en-us/web/api/popover_api/using/index.md
chrisdavidmills Nov 14, 2023
1be535b
Update files/en-us/web/api/popover_api/using/index.md
chrisdavidmills Nov 14, 2023
657a296
Update files/en-us/web/api/popover_api/using/index.md
chrisdavidmills Nov 14, 2023
d8169d1
Update files/en-us/web/css/@starting-style/index.md
chrisdavidmills Nov 14, 2023
c0bb544
Update files/en-us/web/css/@starting-style/index.md
chrisdavidmills Nov 14, 2023
b461119
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 14, 2023
465deb6
Fixes for estelle latest comments, add more examples on @starting-sty…
chrisdavidmills Nov 14, 2023
0aee741
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 14, 2023
a451388
More fixes for estelle comments
chrisdavidmills Nov 15, 2023
4023e96
More estelle fixes
chrisdavidmills Nov 16, 2023
086c494
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 16, 2023
beb0532
More estelle and Onkar comment fixes
chrisdavidmills Nov 20, 2023
74cea43
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 20, 2023
6bc44bf
Update descriptions in light of content-visibility transitions not ne…
chrisdavidmills Nov 20, 2023
44c146e
Merge branch 'overlay-discrete-animations' of github.com:chrisdavidmi…
chrisdavidmills Nov 20, 2023
9609659
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 20, 2023
197b3d9
Merge branch 'main' into overlay-discrete-animations
chrisdavidmills Nov 20, 2023
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
33 changes: 33 additions & 0 deletions files/en-us/web/api/cssstartingstylerule/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: CSSStartingStyleRule
slug: Web/API/CSSStartingStyleRule
page-type: web-api-interface
browser-compat: api.CSSStartingStyleRule
---

{{ APIRef("CSSOM") }}

The **`CSSStartingStyleRule`** interface of the [CSS Object Model](/en-US/docs/Web/API/CSS_Object_Model) represents a CSS [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule.
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved

{{InheritanceDiagram}}

## Instance properties

_This interface inherits properties from its parent, {{domxref("CSSGroupingRule")}}._

## Instance methods

_This interface inherits methods from its parent, {{domxref("CSSGroupingRule")}}._

## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style)
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved
- [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information)
estelle marked this conversation as resolved.
Show resolved Hide resolved
194 changes: 193 additions & 1 deletion files/en-us/web/api/popover_api/using/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,196 @@ The {{cssxref("::backdrop")}} pseudo-element is a full-screen element placed dir

See our [Popover blur background example](https://mdn.github.io/dom-examples/popover-api/blur-background/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/blur-background)) for an idea of how this renders.

Finally, animation needs a special mention, as a lot of people are going to want to animate popovers between showing and hiding. As it stands, [a few updates to CSS behavior](https://open-ui.org/components/popover.research.explainer/#animation-of-popovers) are required to get popovers to be animatable, most notably enabling animation of elements as they move to and from `display: none`. We'll update this article as soon as animation is available for popovers.
## Animating popovers

Popovers are set to `display: none;` when hidden and `display: block;` when shown, as well as being removed from / added to the {{glossary("top layer")}}. Therefore, for popovers to be animated `display` needs to be animatable. This is now the case; [supporting browsers](/en-US/docs/Web/CSS/display#browser_compatibility) animate `display` with a variation on the [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). Specifically, the browser will flip between `none` and another value of `display` so that the animated content is shown for `100%` of the animation duration. So for example:
estelle marked this conversation as resolved.
Show resolved Hide resolved
estelle marked this conversation as resolved.
Show resolved Hide resolved

- When animating between `display` `none` and `block`, the value will flip to `block` at `0%` of the animation duration so it is visible throughout.
- When animating between `display` `block` and `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout.
estelle marked this conversation as resolved.
Show resolved Hide resolved

### Transitioning a popover

When animating popovers with transitions, the following are required:
estelle marked this conversation as resolved.
Show resolved Hide resolved

- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on the popover that you want to transition from when it is shown. This is needed because, by default, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type, to avoid unexpected behavior.
- [`display`](/en-US/docs/Web/CSS/display) needs to be added to the transitions list so that the popover will remain as `display: block` for the duration of the animation, allowing the other animations to be seen.
- [`overlay`](/en-US/docs/Web/CSS/overlay) needs to be added to the transitions list so that the removal of the popover from the top layer will be deferred until the animation is finished, again allowing the other animations to be seen.
- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on the `display` and `overlay` transitions. This effectively enables discrete transitions.

Let's have a look at an example so you can see what this looks like:

The HTML contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control:
estelle marked this conversation as resolved.
Show resolved Hide resolved

```html
<button popovertarget="mypopover">Toggle the popover</button>
<div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
```

The CSS for the example looks like this:

```css
html {
font-family: Arial, Helvetica, sans-serif;
}

/* Transition for the popover itself */

[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}

[popover] {
font-size: 1.2rem;
padding: 10px;
opacity: 0;
transform: scaleX(0);
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
}
estelle marked this conversation as resolved.
Show resolved Hide resolved

/* Needs to be after the previous [popover]:popover-open rule to take effect,
as the specificity is the same */
estelle marked this conversation as resolved.
Show resolved Hide resolved
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}

/* Transition for the popover's backdrop */

[popover]::backdrop {
background-color: rgba(0, 0, 0, 0);
estelle marked this conversation as resolved.
Show resolved Hide resolved
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
}

[popover]:popover-open::backdrop {
background-color: rgba(0, 0, 0, 0.25);
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved
}

/* This starting-style rule cannot be nested inside the above selector
because the nesting selector cannot represent pseudo-elements. */
estelle marked this conversation as resolved.
Show resolved Hide resolved

@starting-style {
[popover]:popover-open::backdrop {
background-color: rgba(0, 0, 0, 0);
estelle marked this conversation as resolved.
Show resolved Hide resolved
}
}
```

The two popover properties we want to show animations for are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform) — specifically, a horizontally scaling transform. We want the popover to fade in and out, as well as growing/shrinking horizontally. To achieve this, we have set a starting state for these properties on the default hidden state of the popover element (selected via `[popover]`), and an end state on the open state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We then set a [`transition`](/en-US/docs/Web/CSS/transition) property to animate between the two.
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved

And as discussed earlier, we have:

- Set a starting state for the transition inside the `@starting-style` block.
estelle marked this conversation as resolved.
Show resolved Hide resolved
- Added `display` to the list of transitioned elements so that the animated element is visible (set to `display: block`) throughout both the entry and exit animation. Without this, the exit animation would not be visible; in effect, the popover would just disappear.
estelle marked this conversation as resolved.
Show resolved Hide resolved
- Added `overlay` to the list of transitioned elements to make sure that the removal of the element from the top layer is deferred until the animation has been completed. This doesn't make a huge difference for simple animations such as this one, but in more complex cases not doing this can result in the element being removed from the overlay too quickly, meaning the animation is not smooth or effective.
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved
- Set `allow-discrete` on both the above transitions to enable discrete transitions.
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved

You'll note that we've also included a transition on the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the popover when it opens, to provide a nice darkening animation. `[popover]:popover-open::backdrop` is needed to select the backdrop when the popover is open.
chrisdavidmills marked this conversation as resolved.
Show resolved Hide resolved

The code renders as follows:

{{ EmbedLiveSample("Transitioning a popover", "100%", "200") }}

Copy link
Member

@estelle estelle Nov 13, 2023

Choose a reason for hiding this comment

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

Suggested change
Because the popover is transitioning from `display: none` to `display: block, every time the popover opens, it transitions from the `@start-style` styles to the`[popover]:popover-open` styles. When the popover exits, it transitions from `[popover]:popover-open` state to the default `[popover]` state.

I think it's important to delineate that every time it opens it goes to start-style, not just the first time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed that we need to make this clear. I've added these notes in appropriate places.

I've also added an explanatory section and an example to the @starting-style page to explain and demonstrate the behavior. I've linked the notes in other places to the example so it can be seen in action.

### A popover keyframe animation

When animating a popover with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), there are some differences to note:

- You don't provide a starting state inside a `@starting-style` block; instead, you need to provide the starting `display` value in an explicit starting keyframe (for example using `0%` or `from`).
- You don't need to enable discrete transitions; there is no equivalent to `allow-discrete` inside keyframes.
- You can't set `overlay` inside keyframes either. The best solution we found at this time to defer removal from the top layer was to use JavaScript — add/remove classes to animate the popover as required and then use {{domxref("setTimeout()")}} to defer hiding the popover until after the animation is finished.
estelle marked this conversation as resolved.
Show resolved Hide resolved

Let's look at an example. The HTML contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control:
estelle marked this conversation as resolved.
Show resolved Hide resolved

```html
<button id="toggle-button" popovertarget="mypopover">Toggle the popover</button>
<div popover="manual" id="mypopover">I'm a Popover! I should animate.</div>
```

The CSS is as follows:
estelle marked this conversation as resolved.
Show resolved Hide resolved

```css
html {
font-family: Arial, Helvetica, sans-serif;
}

[popover] {
font-size: 1.2rem;
padding: 10px;
}

/* Animation classes */

.fade-in {
animation: fade-in 0.7s ease-out forwards;
}

.fade-out {
animation: fade-out 0.7s ease-out forwards;
}

/* Animation keyframes */

@keyframes fade-in {
0% {
opacity: 0;
transform: scaleX(0);
display: none;
estelle marked this conversation as resolved.
Show resolved Hide resolved
}

100% {
opacity: 1;
transform: scaleX(1);
display: block;
}
}

@keyframes fade-out {
0% {
opacity: 1;
transform: scaleX(1);
display: block;
}

100% {
opacity: 0;
transform: scaleX(0);
display: none;
Copy link
Member

Choose a reason for hiding this comment

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

The display none is not actually required as that is the browser default value for a closed popover.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, but as mentioned previously, I think it is easier to understand the keyframes if you are more explicit and leave the start and end value in. So I'd like to leave this one as-is.

Copy link
Member

Choose a reason for hiding this comment

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

we should add a note about it then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note added

}
}
```

We have defined keyframes that specify the desired entry and exit animations, and assigned those to CSS classes. This example doesn't animate the backdrop like the transitions example above does — that wasn't possible to reproduce with a keyframe animation at the time of writing.

We then use some rudimentary JavaScript to apply those classes to the popover as it is toggled between shown and hidden (via the handy {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} event), triggering the animations at the right times. As mentioned earlier, we have used `setTimeout()` to defer hiding the popover until the animations have finished.

```js
const popover = document.getElementById("mypopover");
const toggleBtn = document.getElementById("toggle-button");

popover.addEventListener("beforetoggle", () => {
if (!popover.matches(":popover-open")) {
popover.classList.remove("fade-out");
popover.classList.add("fade-in");
popover.showPopover();
} else if (popover.matches(":popover-open")) {
popover.classList.remove("fade-in");
popover.classList.add("fade-out");
setTimeout(() => {
popover.hidePopover();
}, 700);
}
});
```

estelle marked this conversation as resolved.
Show resolved Hide resolved
The code renders as follows:

{{ EmbedLiveSample("A popover keyframe animation", "100%", "200") }}
Loading