From 0c09617da4b3eae3d605cca90f04ef835b6c700c Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 11 Sep 2023 16:51:18 +0100 Subject: [PATCH 01/22] feat: Add content for overlay and discrete animation features --- .../web/api/cssstartingstylerule/index.md | 33 ++ files/en-us/web/css/@starting-style/index.md | 283 ++++++++++++++++++ files/en-us/web/css/overlay/index.md | 116 +++++++ .../web/css/transition-behavior/index.md | 137 +++++++++ files/en-us/web/css/transition/index.md | 10 +- files/jsondata/GroupData.json | 1 + 6 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 files/en-us/web/api/cssstartingstylerule/index.md create mode 100644 files/en-us/web/css/@starting-style/index.md create mode 100644 files/en-us/web/css/overlay/index.md create mode 100644 files/en-us/web/css/transition-behavior/index.md diff --git a/files/en-us/web/api/cssstartingstylerule/index.md b/files/en-us/web/api/cssstartingstylerule/index.md new file mode 100644 index 000000000000000..ba8a7dc779da43a --- /dev/null +++ b/files/en-us/web/api/cssstartingstylerule/index.md @@ -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. + +{{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) +- [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information) diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md new file mode 100644 index 000000000000000..846684d1772714e --- /dev/null +++ b/files/en-us/web/css/@starting-style/index.md @@ -0,0 +1,283 @@ +--- +title: "@starting-style" +slug: Web/CSS/@starting-style +page-type: css-at-rule +status: + - experimental +browser-compat: css.at-rules.starting-style +--- + +{{CSSRef}}{{SeeCompatTable}} + +The **`@starting-style`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/CSS/At-rule) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. + +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`](/en-US/docs/Web/CSS/display) type changes from `none` to another type, to avoid unexpected behavior. To put it another way, such elements do not have a starting style to transition from. `@starting-style` allows you to provide starting styles, overriding the default behavior in a specific controlled fashion. + +This enables the easy creation of entry animations that were previously complex to achieve, such as animating elements when they are changed from `display: none` (this includes elements shown in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements) or when they are first added to the DOM. + +## Syntax + +```css +@starting-style {rules} +@starting-style {declarations} +``` + +where: + +- _rules_ + - : Is the set of CSS rules providing the starting styles for the transition, when `@starting-style` is used in standalone style. +- _rules_ + - : Is the set of CSS declarations providing the starting styles for the transition, when `@starting-style` is nested inside a particular ruleset. + +## Description + +There are two ways to use `@starting-style`. Let's consider an example where we want to animate a popover when it is shown (added to the top layer). In this case, the original rule specifying the styles for the popover once opened looks like this (you can see the [full example in action](/en-US/docs/Web/CSS/@starting-style#animating_a_popover) in the examples section): + +```css +[popover]:popover-open { + opacity: 1; + transform: scaleX(1); +} +``` + +You can specify the starting styles in a separate rule contained within a standalone `@starting-style` block: + +```css +@starting-style { + [popover]:popover-open { + opacity: 0; + transform: scaleX(0); + } +} +``` + +> **Note:** In the standalone case, you need to specify the `@starting-style` block after the original rule for it to take effect, as the specificity of each is the same. If `@starting-style` was specified first, the original styles would override it. + +Alternatively, you can nest the starting styles inside the original rule: + +```css +[popover]:popover-open { + opacity: 1; + transform: scaleX(1); + + @starting-style { + opacity: 0; + transform: scaleX(0); + } +} +``` + +## Formal syntax + +{{csssyntax}} + +## Examples + +### Animating a popover + +This example shows how a [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided. + +The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. + +```html + +
I'm a Popover! I should animate.
+``` + +The CSS for the example looks like this: + +```css +html { + font-family: Arial, Helvetica, sans-serif; +} + +[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; +} + +/* Needs to be included after the previous [popover]:popover-open rule + to take effect, as the specificity is the same */ +@starting-style { + [popover]:popover-open { + opacity: 0; + transform: scaleX(0); + } +} +``` + +The two properties we want to animate 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, and include a starting state for the animation inside a [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule, as described above, so the entry animation will work. + +However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to get the animation working in both directions: + +- `display` is added 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. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand so that it will animate. +- [`overlay`](/en-US/docs/Web/CSS/overlay) is added 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. + +The code renders as follows: + +{{ EmbedLiveSample("Animating a popover", "100%", "200") }} + +### Transitioning elements as they are added to and removed from the DOM + +In this example, we provide a button that appends new elements to a {{htmlelement("section")}} container when pressed. Each element is given a nested close button which, when pressed, removes the element again. We use transitions to animate the elements when they are first added to the DOM, and when they are removed. + +The static HTML looks like this: + +```html + +
+``` + +The JavaScript that handles the adding and removing looks like this: + +```js +const btn = document.querySelector("button"); +const sectionElem = document.querySelector("section"); + +btn.addEventListener("click", createColumn); + +function randomColor() { + function randomChannel() { + return Math.floor(Math.random() * 255); + } + + return `rgb(${randomChannel()},${randomChannel()},${randomChannel()})`; +} + +function createColumn() { + const divElem = document.createElement("div"); + divElem.style.backgroundColor = randomColor(); + + const closeBtn = document.createElement("button"); + closeBtn.textContent = "✖"; + closeBtn.setAttribute("aria-label", "close"); + divElem.append(closeBtn); + sectionElem.append(divElem); + + closeBtn.addEventListener("click", () => { + divElem.classList.add("fade-out"); + + setTimeout(() => { + divElem.remove(); + }, 1000); + }); +} +``` + +The most interesting part is the `createColumn()` function — note how it creates a {{htmlelement("div")}} element and a {{htmlelement("button")}} element to close the `
` when pressed then appends the ` +
I'm a Popover! I should animate.
+``` + +The CSS for the example looks like this: + +```css +html { + font-family: Arial, Helvetica, sans-serif; +} + +[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; +} + +/* Needs to be included after the previous [popover]:popover-open rule + to take effect, as the specificity is the same */ +@starting-style { + [popover]:popover-open { + opacity: 0; + transform: scaleX(0); + } +} +``` + +The two properties we want to animate 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. + +However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to get the animation working in both directions: + +- A starting state for the animation is set inside the [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule. This is needed because by default transitions are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type, to avoid unexpected behavior. `@starting-style` allows you to override that default in a specific controlled fashion. Without this, the entry animation would not occur and the popover would just appear. +- `display` is added 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. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand so that it will animate. +- `overlay` is added 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. + +The code renders as follows: + +{{ EmbedLiveSample("Animating a popover", "100%", "200") }} + +#### Further examples + +Further examples (including a `` modal animation) can be found at [Animating elements to and from the top-layer](https://developer.chrome.com/blog/entry-exit-animations/#animating-elements-to-and-from-the-top-layer). + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) +- [`transition-behavior`](/en-US/docs/Web/CSS/transition-behavior) +- [Four new CSS features for smooth entry and exit animations](https://developer.chrome.com/blog/entry-exit-animations/) on developer.chrome.com (2023) diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md new file mode 100644 index 000000000000000..da70fb30ab86a70 --- /dev/null +++ b/files/en-us/web/css/transition-behavior/index.md @@ -0,0 +1,137 @@ +--- +title: transition-behavior +slug: Web/CSS/transition-behavior +page-type: css-property +status: + - experimental +browser-compat: css.properties.transition-behavior +--- + +{{CSSRef}}{{SeeCompatTable}} + +The **`transition-behavior`** [CSS](/en-US/docs/Web/CSS) property specifies whether transitions will be started for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). + +This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), the first two of which historically were not animatable at all to and from a hidden state (for example `display: none;`). The ability of these elements to be transitioned means that it is fairly easy to create entry and exit animations, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. + +## Syntax + +```css +/* Keyword values */ +transition-behavior: allow-discrete; +transition-behavior: normal; + +/* Global values */ +transition-behavior: inherit; +transition-behavior: initial; +transition-behavior: revert; +transition-behavior: revert-layer; +transition-behavior: unset; +``` + +### Values + +- `allow-discrete` + - : Transitions will be started on the element for discrete animated properties. +- `normal` + - : Transitions will _not_ be started on the element for discrete animated properties. + +## Formal definition + +{{cssinfo}} + +## Formal syntax + +{{CSSSyntax}} + +## Examples + +### Basic usage + +```css +.card { + transition-property: opacity, display; + transition-duration: 0.25s, 0.25s; + transition-behavior: allow-discrete; +} + +.card.fade-out { + opacity: 0; + display: none; +} +``` + +See the next example for shorthand usage. + +### Animating a popover + +This example shows how a [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided. + +The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. + +```html + +
I'm a Popover! I should animate.
+``` + +The CSS for the example looks like this: + +```css +html { + font-family: Arial, Helvetica, sans-serif; +} + +[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; +} + +/* Needs to be included after the previous [popover]:popover-open rule + to take effect, as the specificity is the same */ +@starting-style { + [popover]:popover-open { + opacity: 0; + transform: scaleX(0); + } +} +``` + +The two properties we want to animate 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. + +However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to get the animation working in both directions: + +- A starting state for the animation is set inside the [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule. This is needed because by default transitions are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type, to avoid unexpected behavior. `@starting-style` allows you to override that default in a specific controlled fashion. Without this, the entry animation would not occur and the popover would just appear. +- `display` is added 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. +- [`overlay`](/en-US/docs/Web/CSS/overlay) is added 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. + +In the transitions list, `transition-behavior: allow-discrete` is set in the shorthand for both `display` and `overlay` so that they will animate. + +The code renders as follows: + +{{ EmbedLiveSample("Animating a popover", "100%", "200") }} + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [`overlay`](/en-US/docs/Web/CSS/overlay) +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) +- [`transition`](/en-US/docs/Web/CSS/transition) +- [Four new CSS features for smooth entry and exit animations](https://developer.chrome.com/blog/entry-exit-animations/) on developer.chrome.com (2023) diff --git a/files/en-us/web/css/transition/index.md b/files/en-us/web/css/transition/index.md index 636c9530b8921cd..54f3333ce023a12 100644 --- a/files/en-us/web/css/transition/index.md +++ b/files/en-us/web/css/transition/index.md @@ -7,7 +7,7 @@ browser-compat: css.properties.transition {{CSSRef}} -The **`transition`** [CSS](/en-US/docs/Web/CSS) property is a [shorthand property](/en-US/docs/Web/CSS/Shorthand_properties) for {{ cssxref("transition-property") }}, {{ cssxref("transition-duration") }}, {{ cssxref("transition-timing-function") }}, and {{ cssxref("transition-delay") }}. +The **`transition`** [CSS](/en-US/docs/Web/CSS) property is a [shorthand property](/en-US/docs/Web/CSS/Shorthand_properties) for {{ cssxref("transition-property") }}, {{ cssxref("transition-duration") }}, {{ cssxref("transition-timing-function") }}, {{ cssxref("transition-delay") }}, and {{ cssxref("transition-behavior") }}. {{EmbedInteractiveExample("pages/css/transition.html")}} @@ -17,6 +17,7 @@ Transitions enable you to define the transition between two states of an element This property is a shorthand for the following CSS properties: +- [`transition-behavior`](/en-US/docs/Web/CSS/transition-behavior) {{experimental_inline}} - [`transition-delay`](/en-US/docs/Web/CSS/transition-delay) - [`transition-duration`](/en-US/docs/Web/CSS/transition-duration) - [`transition-property`](/en-US/docs/Web/CSS/transition-property) @@ -38,6 +39,9 @@ transition: margin-right 4s ease-in-out; /* property name | duration | easing function | delay */ transition: margin-right 4s ease-in-out 1s; +/* property name | duration | behavior */ +transition: display 4s allow-discrete; + /* Apply to 2 properties */ transition: margin-right 4s, @@ -66,6 +70,10 @@ Each single-property transition describes the transition that should be applied - zero or one {{cssxref("<easing-function>")}} value representing the easing function to use - zero, one, or two {{cssxref("<time>")}} values. The first value that can be parsed as a time is assigned to the {{cssxref("transition-duration")}}, and the second value that can be parsed as a time is assigned to {{cssxref("transition-delay")}}. +- zero or one value declaring whether to start transitions for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete): + + - the keyword `allow-discrete` + - the keyword `normal` See [how things are handled](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions#when_property_value_lists_are_of_different_lengths) when lists of property values aren't the same length. In short, extra transition descriptions beyond the number of properties actually being animated are ignored. diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index d944cebd1bd07db..938942d7f0a01f8 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -293,6 +293,7 @@ "CSSRule", "CSSRuleList", "CSSStyleDeclaration", + "CSSStartingStyleRule", "CSSStyleRule", "CSSStyleSheet", "CSSSupportsRule", From 25f6a671340b045fdd43949dceaf814bb4e61263 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 13 Sep 2023 13:11:09 +0100 Subject: [PATCH 02/22] Add rest of required updates --- .../en-us/web/api/popover_api/using/index.md | 200 +++++++++++++++- files/en-us/web/css/@starting-style/index.md | 2 + .../en-us/web/css/content-visibility/index.md | 110 +++++++++ .../using_css_animations/index.md | 109 +++++++++ .../using_css_transitions/index.md | 92 +++++++- files/en-us/web/css/display/index.md | 18 ++ .../web/css/transition-behavior/index.md | 2 +- .../web/css/transition-property/index.md | 27 +-- files/en-us/web/css/transition/index.md | 28 ++- files/en-us/web/html/element/dialog/index.md | 219 +++++++++++++++++- 10 files changed, 786 insertions(+), 21 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 7d5d3d0a33e1fff..c7ba84f56ae52dd 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -301,4 +301,202 @@ 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 + +For popovers to be animated, several different features are required. + +First of all, 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, `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: + +- 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. + +### Transitioning a popover + +When animating popovers with transitions, these additional features are needed: + +- [`@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: + +```html + +
I'm a Popover! I should animate.
+``` + +The CSS for the example looks like this: + +```css +html { + font-family: Arial, Helvetica, sans-serif; +} + +::backdrop { + background-color: rgba(0, 0, 0, 0.1); + transition: + background-color 0.5s, + display 0.5s allow-discrete, + overlay 0.5s allow-discrete; +} + +@starting-style { + ::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} + +[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; +} + +/* Needs to be included after the previous [popover]:popover-open rule + to take effect, as the specificity is the same */ +@starting-style { + [popover]:popover-open { + opacity: 0; + transform: scaleX(0); + } +} +``` + +The two 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. + +And as discussed earlier, we have: + +- Set a starting state for the transition inside the `@starting-style` block. +- 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. +- 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. +- Set `allow-discrete` on both the above transitions to enable discrete transitions. + +You'll note that we have also done something similar for the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the popover when it opens, to provide a nice darkening animation. + +The code renders as follows: + +{{ EmbedLiveSample("Transitioning a popover", "100%", "200") }} + +### 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 — animating the popover and then using {{domxref("setTimeout()")}} to defer removal of the popover until after the animation is finished. + +Let's look at an example. The HTML is contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control: + +```html + +
I'm a Popover! I should animate.
+``` + +The CSS is as follows: + +```css +html { + font-family: Arial, Helvetica, sans-serif; +} + +/* Transition the :backdrop when the popover is promoted to the top layer */ +::backdrop { + background-color: rgba(0, 0, 0, 0.1); + transition: + background-color 0.5s, + display 0.5s allow-discrete, + overlay 0.5s allow-discrete; +} + +@starting-style { + ::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} + +[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; + } + + 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; + } +} +``` + +We have defined keyframes that specify the desired entry and exit animations, and assigned those to CSS classes. Note also that the animation example includes the same [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) transition as the transition demo, to fade the backdrop in. This didn't seem possible to reproduce with a keyframe animation. + +We then use some rudimentary JavaScript to apply those classes to the popover as it is shown and hidden, triggering the animations at the right times. As mentioned earlier, we have used `setTimeout()` to defer the hiding of the popover until the animations have finished. + +```js +const popover = document.getElementById("mypopover"); +const toggleBtn = document.getElementById("toggle-button"); + +toggleBtn.addEventListener("click", () => { + 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); + } +}); +``` + +The code renders as follows: + +{{ EmbedLiveSample("A popover keyframe animation", "100%", "200") }} diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 846684d1772714e..d7ff28b1c9e88f8 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -15,6 +15,8 @@ This is needed because, by default, [CSS transitions](/en-US/docs/Web/CSS/CSS_tr This enables the easy creation of entry animations that were previously complex to achieve, such as animating elements when they are changed from `display: none` (this includes elements shown in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements) or when they are first added to the DOM. +> **Note:** `@starting-style` is only relevant to CSS transitions. When animating from `display: none` or animating elements as they are first added to the DOM, [CSS animations](/en-US/docs/Web/CSS/CSS_animations) do not need a `@starting-style` specified; instead you provide the starting style as an explicit starting keyframe (for example using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations) for an example. + ## Syntax ```css diff --git a/files/en-us/web/css/content-visibility/index.md b/files/en-us/web/css/content-visibility/index.md index f2ffe3181b58d54..92a4ff2c5faee06 100644 --- a/files/en-us/web/css/content-visibility/index.md +++ b/files/en-us/web/css/content-visibility/index.md @@ -38,6 +38,24 @@ content-visibility: unset; - `auto` - : The element turns on layout containment, style containment, and paint containment. If the element is not [relevant to the user](/en-US/docs/Web/CSS/CSS_containment#relevant_to_the_user), it also skips its contents. Unlike hidden, the skipped contents must still be available as normal to user-agent features such as find-in-page, tab order navigation, etc., and must be focusable and selectable as normal. +## Animating content-visibility + +Historically, the `content-visibility` property was not animatable/transitionable. The spec changed however, and [supporting browsers](#browser_compatibility) now animate `content-visibility` with a variation on the [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). Discrete animation generally means that the property will flip between two values `50%` through animating between the two. + +In the case of `content-visibility` however, the browser will flip between the two values so that the animated content is shown for `100%` of the animation duration. So for example: + +- When animating between `content-visibility` `hidden` and `visible`, the value will flip to `visible` at `0%` of the animation duration so it is visible throughout. +- When animating between `content-visibility` `visible` and `hidden`, the value will flip to `hidden` at `100%` of the animation duration so it is visible throughout. + +This behavior is useful for creating entry/exit animations where you want to for example remove some content from the UI immediately with `content-visibility: hidden`, but have it animate (for example fade out) rather than disappearing immediately. + +When animating `content-visibility` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `content-visibility` value in an explicit starting keyframe (for example using `0%` or `from`). For a full example, see the [content-visibility animation example](#content-visibility_animation_example) section below. + +When animating `content-visibility` with transitions, two additional features are needed: + +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. 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 `content-visibility` value changes from `hidden` to `visible`, to avoid unexpected behavior. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `content-visibility` when it is transitioned. This effectively enables `content-visibility` transitions, enabling it to animate. + ## Formal definition {{cssinfo}} @@ -149,6 +167,98 @@ document.querySelectorAll("button.toggle").forEach((button) => { {{ EmbedLiveSample('Using hidden to manually manage visibility') }} +### content-visibility animation example + +In this example, we have a {{htmlelement("div")}} element, the content of which can be toggled between shown and hidden by clicking or pressing any key. The HTML looks like this: + +```html +

+ Click anywhere on the screen or press any key to toggle the + <div> content between hidden and showing. +

+ +
+ This is a <div> element that animates between + content-visibility: hidden;and + content-visibility: visible;. We've also animated the text color + to provide a smooth animation effect. +
+``` + +In the CSS we initially set `content-visibility: hidden;` on the `
` to hide its content. We then set up `@keyframe` animations and attach them to classes to show and hide the `
`, animating `content-visibility` but also [`color`](/en-US/docs/Web/CSS/color) so that you get a smooth animation effect as the content is shown/hidden. + +```css +div { + font-size: 1.6rem; + padding: 20px; + border: 3px solid red; + border-radius: 20px; + width: 480px; + + content-visibility: hidden; +} + +/* Animation classes */ + +.show { + animation: show 0.7s ease-in forwards; +} + +.hide { + animation: hide 0.7s ease-out forwards; +} + +/* Animation keyframes */ + +@keyframes show { + 0% { + content-visibility: hidden; + color: rgba(0, 0, 0, 0); + } + + 100% { + content-visibility: visible; + color: rgba(0, 0, 0, 1); + } +} + +@keyframes hide { + 0% { + content-visibility: visible; + color: rgba(0, 0, 0, 1); + } + + 100% { + content-visibility: hidden; + color: rgba(0, 0, 0, 0); + } +} +``` + +Finally, we use some JavaScript to apply the `.show` and `.hide` classes to the `
` as appropriate to apply the animations as it is toggled between shown and hidden. + +```js +const divElem = document.querySelector("div"); +const htmlElem = document.querySelector(":root"); + +htmlElem.addEventListener("click", showHide); +document.addEventListener("keydown", showHide); + +function showHide() { + if (divElem.classList[0] === "show") { + divElem.classList.remove("show"); + divElem.classList.add("hide"); + } else { + divElem.classList.remove("hide"); + divElem.classList.add("show"); + } +} +``` + +The rendered result looks like this: + +{{ EmbedLiveSample("content-visibility animation example", "100%", "250") }} + ## Specifications {{Specifications}} diff --git a/files/en-us/web/css/css_animations/using_css_animations/index.md b/files/en-us/web/css/css_animations/using_css_animations/index.md index 28e6f88f336083a..1e871224cda9a89 100644 --- a/files/en-us/web/css/css_animations/using_css_animations/index.md +++ b/files/en-us/web/css/css_animations/using_css_animations/index.md @@ -36,6 +36,8 @@ The sub-properties of the {{cssxref("animation")}} property are: - : Specifies the name of the {{cssxref("@keyframes")}} at-rule describing an animation's keyframes. - {{cssxref("animation-play-state")}} - : Specifies whether to pause or play an animation sequence. +- {{cssxref("animation-timeline")}} {{experimental_inline}} + - : Specifies the timeline that is used to control the progress of a CSS animation. - {{cssxref("animation-timing-function")}} - : Specifies how an animation transitions through keyframes by establishing acceleration curves. @@ -381,6 +383,113 @@ And here's the live output. {{EmbedLiveSample('Using_animation_events', '600', '300')}} +## Animating display and content-visibility + +Historically, the [`display`](/en-US/docs/Web/CSS/display) and [`content-visibility`](/en-US/docs/Web/CSS/content-visibility) properties were not animatable. The specs changed however, and supporting browsers (see the reference links for details) now animate them with a [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). This generally means that properties will flip between two values `50%` through animating between the two. + +There is an exception, however, which is when animating to/from `display: none` or `content-visibility: hidden`. In this case, the browser will flip between the two values so that the animated content is shown for `100%` of the animation duration. + +So for example: + +- 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. + +This behavior is useful for creating entry/exit animations where you want to for example remove a container from the UI immediately with `display: none`, but have it fade out with [`opacity`](/en-US/docs/Web/CSS/opacity) rather than disappearing immediately. + +Let's put all of this together into a working example. The HTML contains a simple instruction message plus a {{htmlelement("div")}} that we will animate from `display` `none` to `block`. + +```html +

+ Click anywhere on the screen or press any key to toggle the + <div> between hidden and showing. +

+ +
+ This is a <div> element that animates between + display: none; opacity: 0 and + display: block; opacity: 1. Neat, huh? +
+``` + +The CSS is as follows: + +```css +html { + height: 100vh; +} + +div { + font-size: 1.6rem; + padding: 20px; + border: 3px solid red; + border-radius: 20px; + width: 480px; + opacity: 0; +} + +/* Animation classes */ + +div.fade-in { + animation: fade-in 0.7s ease-in forwards; +} + +div.fade-out { + animation: fade-out 0.7s ease-out forwards; +} + +/* Animation keyframes */ + +@keyframes fade-in { + 0% { + opacity: 0; + display: none; + } + + 100% { + opacity: 1; + display: block; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + display: block; + } + + 100% { + opacity: 0; + display: none; + } +} +``` + +Note the inclusion of the `display` property in the keyframe animations. When animating `display` or `content-visibility`, you need to provide the starting value in an explicit starting keyframe (for example using `0%` or `from`). + +Finally, we include a bit of JavaScript to set up event listeners to trigger the animations. Specifically, we add the `fade-in` class to the `
` when we want it to appear, and `fade-out` when we want it to disappear. + +```js +const divElem = document.querySelector("div"); +const htmlElem = document.querySelector(":root"); + +htmlElem.addEventListener("click", showHide); +document.addEventListener("keydown", showHide); + +function showHide() { + if (divElem.classList[0] === "fade-in") { + divElem.classList.remove("fade-in"); + divElem.classList.add("fade-out"); + } else { + divElem.classList.remove("fade-out"); + divElem.classList.add("fade-in"); + } +} +``` + +The code renders as follows: + +{{ EmbedLiveSample("Animating display and content-visibility", "100%", "250") }} + ## See also - {{domxref("AnimationEvent", "AnimationEvent")}} diff --git a/files/en-us/web/css/css_transitions/using_css_transitions/index.md b/files/en-us/web/css/css_transitions/using_css_transitions/index.md index 92e8f37e82b32d1..7007acca52b18e4 100644 --- a/files/en-us/web/css/css_transitions/using_css_transitions/index.md +++ b/files/en-us/web/css/css_transitions/using_css_transitions/index.md @@ -46,7 +46,7 @@ div { ## Examples -### Simple example +### Basic example This example performs a four-second font size transition with a two-second delay between the time the user mouses over the element and the beginning of the animation effect: @@ -258,6 +258,96 @@ el.addEventListener("transitionstart", signalStart, true); > **Note:** The `transitionend` event doesn't fire if the transition is aborted before the transition is completed because either the element is made {{cssxref("display")}}`: none` or the animating property's value is changed. +## Transitioning display and content-visibility + +Historically, the [`display`](/en-US/docs/Web/CSS/display) and [`content-visibility`](/en-US/docs/Web/CSS/content-visibility) properties were not transitionable. The specs changed however, and supporting browsers (see the reference links for details) now animate them with a [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). This generally means that properties will flip between two values `50%` through animating between the two. + +There is an exception, however, which is when animating to/from `display: none` or `content-visibility: hidden`. In this case, the browser will flip between the two values so that the transitioned content is shown for `100%` of the animation duration. + +So for example: + +- When animating between `display` `none` and `block`, the value will flip to `block` at `0%` of the transition duration so it is visible throughout. +- When animating between `display` `block` and `none`, the value will flip to `none` at `100%` of the transition duration so it is visible throughout. + +This behavior is useful for creating entry/exit animations where you want to for example remove a container from the UI immediately with `display: none`, but have it fade out with [`opacity`](/en-US/docs/Web/CSS/opacity) rather than disappearing immediately. + +When transitioning these properties, two additional features are also needed: + +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. This is needed because, by default, CSS transitions are not triggered on elements' first style updates, or when `display`/`content-visibility` changes from `none`/`hidden` to another state, to avoid unexpected behavior. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on the transitions. This effectively enables `display`/`content-visibility` transitions, enabling them to animate. + +Let's put all of this together into a working example. The HTML contains a simple instruction message plus a {{htmlelement("div")}} that we will transition from `display` `none` to `block`. + +```html +

+ Click anywhere on the screen or press any key to toggle the + <div> between hidden and showing. +

+ +
+ This is a <div> element with + display: none; opacity: 0 set on it initially. When it appears, + it transitions to display: block; opacity: 1. Neat, huh? +
+``` + +The CSS is as follows: + +```css +html { + height: 100vh; +} + +div { + font-size: 1.6rem; + padding: 20px; + border: 3px solid red; + border-radius: 20px; + width: 480px; + + display: none; + opacity: 0; + transition: + opacity 1s, + display 1s allow-discrete; +} + +.showing { + opacity: 1; + display: block; +} + +@starting-style { + .showing { + opacity: 0; + } +} +``` + +Note the `@starting-style` block used to specify the starting style for the transition, and the inclusion of the `display` property in the trainsitions list, with `allow-discrete` set on it. + +Finally, we include a bit of JavaScript to set up event listeners to trigger the transition (via the `showing` class). + +```js +const divElem = document.querySelector("div"); +const htmlElem = document.querySelector(":root"); + +htmlElem.addEventListener("click", showHide); +document.addEventListener("keydown", showHide); + +function showHide() { + if (divElem.classList[0] === "showing") { + divElem.classList.remove("showing"); + } else { + divElem.classList.add("showing"); + } +} +``` + +The code renders as follows: + +{{ EmbedLiveSample("Transitioning display and content-visibility", "100%", "250") }} + ## Specifications {{Specifications}} diff --git a/files/en-us/web/css/display/index.md b/files/en-us/web/css/display/index.md index bf3ed7dbbb642ca..ada34f1245677d8 100644 --- a/files/en-us/web/css/display/index.md +++ b/files/en-us/web/css/display/index.md @@ -259,6 +259,24 @@ The individual pages for the different types of value that `display` can have se - [CSS Grid Layout and Progressive Enhancement](/en-US/docs/Web/CSS/CSS_grid_layout/Grid_layout_and_progressive_enhancement) - [Realizing common layouts using grids](/en-US/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids) +### Animating display + +Historically, the `display` property was not animatable/transitionable. The spec changed however, and [supporting browsers](#browser_compatibility) now animate `display` with a [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). This generally means that the property will flip between two values `50%` through animating between the two. + +There is one exception, which is when animating to or from `display: none`. In this case, the browser will flip between the two values so that the animated content is shown for `100%` of the animation duration. So for example: + +- 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. + +This behavior is useful for creating entry/exit animations where you want to for example remove a container from the UI immediately with `display: none`, but have it fade out with [`opacity`](/en-US/docs/Web/CSS/opacity) rather than disappearing immediately. + +When animating `display` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `display` value in an explicit starting keyframe (for example using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations) for an example. + +When animating `display` with transitions, two additional features are needed (see the below links for examples): + +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. 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. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `display` when it is transitioned. This effectively enables `display` transitions, enabling it to animate. + ## Accessibility concerns ### display: none diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index da70fb30ab86a70..e2d47a0e034ae73 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -11,7 +11,7 @@ browser-compat: css.properties.transition-behavior The **`transition-behavior`** [CSS](/en-US/docs/Web/CSS) property specifies whether transitions will be started for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). -This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), the first two of which historically were not animatable at all to and from a hidden state (for example `display: none;`). The ability of these elements to be transitioned means that it is fairly easy to create entry and exit animations, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. +This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), the first two of which historically were not animatable. The ability of these elements to be transitioned means that it is fairly easy to create entry and exit animations, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. ## Syntax diff --git a/files/en-us/web/css/transition-property/index.md b/files/en-us/web/css/transition-property/index.md index 2d21e5c3b12b1e3..8169c4e5cd2e935 100644 --- a/files/en-us/web/css/transition-property/index.md +++ b/files/en-us/web/css/transition-property/index.md @@ -60,33 +60,34 @@ transition-property: unset; ## Examples -### Simple example +> **Note:** See our [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) guide for more `transition-property` examples. -This example performs a four-second font size transition when the user hovers over the element, the `transition-property` is the `font-size`. +### Basic example -#### HTML +When the button is hovered or focused, it undergoes a one-second opacity transition; the `transition-property` is [`opacity`](/en-US/docs/Web/CSS/opacity). + +The HTML looks like this: ```html -Hover over me + ``` -#### CSS +The CSS is as follows: ```css .target { - font-size: 14px; - transition-property: font-size; - transition-duration: 4s; + font-size: 20px; + transition-property: opacity; + transition-duration: 1s; } -.target:hover { - font-size: 36px; +.target:hover, +.target:focus { + opacity: 0; } ``` -{{EmbedLiveSample('Simple_example', 600, 100)}} - -You will find more examples of `transition-property` included in the main [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) article. +{{EmbedLiveSample('Basic_example', 600, 100)}} ## Specifications diff --git a/files/en-us/web/css/transition/index.md b/files/en-us/web/css/transition/index.md index 54f3333ce023a12..27be632bb1e5f64 100644 --- a/files/en-us/web/css/transition/index.md +++ b/files/en-us/web/css/transition/index.md @@ -87,7 +87,9 @@ See [how things are handled](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_trans ## Examples -### Simple example +> **Note:** See our [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) guide for more `transition` examples. + +### Basic example In this example, when the user hovers over the element, there is a one-second delay before the four-second `font-size` transition occurs. @@ -112,9 +114,29 @@ We include two {{cssxref("time")}} values. In the `transition` shorthand, the fi } ``` -{{EmbedLiveSample('Simple_example', 600, 100)}} +{{EmbedLiveSample('Basic_example', 600, 100)}} + +### Transitioning top layer elements + +The [`overlay`](/en-US/docs/Web/CSS/overlay) property can be added to the list of transition properties set on an element displayed in the [top layer](/en-US/docs/Glossary/Top_layer) — for example a [popover](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} element. This causes its removal from the top layer to be deferred so it can be animated instead of disappearing immediately. + +Sample CSS: + +```css +[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; +} +``` -There are several more examples of CSS transitions included in the [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) article. +See the [`overlay`](/en-US/docs/Web/CSS/overlay) page for a full working example. ## Specifications diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index 23e8e4c434b122f..44a62a166a4e00e 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -36,7 +36,7 @@ The `` element is exposed by browsers similarly to custom dialogs using ## Examples -### Simple example +### Basic example The following will render a non-modal, or modal-less, dialog. The "OK" button allows the dialog to be closed when activated. @@ -51,7 +51,7 @@ The following will render a non-modal, or modal-less, dialog. The "OK" button al #### Result -{{EmbedLiveSample("Simple_example", "100%", 200)}} +{{EmbedLiveSample("Basic_example", "100%", 200)}} Because this dialog was opened via the `open` attribute, it is non-modal. In this example, when the dialog is dismissed, no method is provided to re-open it. Opening dialogs via {{domxref("HTMLDialogElement.show()")}} is preferred over the toggling of the boolean `open` attribute. @@ -132,6 +132,221 @@ Without an `action`, submitting the form via the default {{HTTPMethod("GET")}} m It is important to provide a closing mechanism within every `dialog` element. The Esc key does not close non-modal dialogs by default, nor can one assume that a user will even have access to a physical keyboard (e.g., someone using a touch screen device without access to a keyboard). +### Animating dialogs + +For `` elements to be animated, several different features are required. + +First of all, ``s 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, `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: + +- 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. + +#### Transitioning dialog elements + +When animating ``s with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), these additional features are needed: + +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on the `` 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 `` 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 `` 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. + +Here is a quick example to show what this might look like. + +The HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. + +```html + + Content here + + + + +``` + +The CSS is as follows: + +```css +/* Open state of the dialog */ +dialog[open] { + opacity: 1; + transform: scaleY(1); +} + +/* Closed state of the dialog */ +dialog { + transition: + opacity 0.5s ease-out, + transform 0.5s ease-out, + overlay 0.5s ease-out allow-discrete, + display 0.5s ease-out allow-discrete; + opacity: 0; + transform: scaleY(0); +} + +/* Before-open state */ +/* Needs to be after the previous dialog[open] rule to take effect, + as the specificity is the same */ +@starting-style { + dialog[open] { + opacity: 0; + transform: scaleY(0); + } +} + +/* Transition the :backdrop when the dialog modal is promoted to the top layer */ +::backdrop { + background-color: rgba(0, 0, 0, 0.1); + transition: + background-color 0.5s, + display 0.5s allow-discrete, + overlay 0.5s allow-discrete; +} + +@starting-style { + ::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} + +body, +button { + font-family: system-ui; +} +``` + +Note the `@starting-style` block used to define the transition starting styles, and the `display` and `overlay` properties included in the transition list, each with `allow-discrete` set on them. Note that we've also included similar CSS to transition the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. + +The JavaScript serves to wire up the buttons to event handlers that show and close the ``: + +```js +const dialogElem = document.getElementById("dialog"); +const showBtn = document.querySelector(".show"); +const closeBtn = document.querySelector(".close"); + +showBtn.addEventListener("click", () => { + dialogElem.showModal(); +}); + +closeBtn.addEventListener("click", () => { + dialogElem.close(); +}); +``` + +The code renders as follows: + +{{ EmbedLiveSample("Transitioning dialog elements", "100%", "200") }} + +#### dialog keyframe animations + +When animating a `` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), there are some differences to note from transitions: + +- 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 — animating the `` and then using {{domxref("setTimeout()")}} to defer removal of the `` until after the animation is finished. + +Let's have a look at an example so you can see what this looks like. First, the HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. The `` has a `class` of `fade-in` set on it, which will trigger the entry animation when the dialog is shown. + +```html + + Content here + + + + +``` + +Now for the CSS: + +```css +/* Animation classes */ + +.fade-in { + animation: fade-in 0.5s ease-out forwards; +} + +.fade-out { + animation: fade-out 0.5s ease-out forwards; +} + +/* Animation keyframes */ + +@keyframes fade-in { + 0% { + opacity: 0; + transform: scaleY(0); + display: none; + } + + 100% { + opacity: 1; + transform: scaleY(1); + display: block; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + transform: scaleY(1); + display: block; + } + + 100% { + opacity: 0; + transform: scaleY(0); + display: none; + } +} + +body, +button { + font-family: system-ui; +} + +/* Transition the :backdrop when the dialog modal is promoted to the top layer */ +::backdrop { + background-color: rgba(0, 0, 0, 0.1); + transition: + background-color 0.5s, + display 0.5s allow-discrete, + overlay 0.5s allow-discrete; +} + +@starting-style { + ::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} +``` + +Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note also that the animation example includes the same [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) transition as the transition demo, to fade the backdrop in. This didn't seem possible to reproduce with a keyframe animation. + +Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``, while also adding and removing the control classes as required to apply the entry and exit animations. In addition, note how {{domxref("setTimeout()")}} is used to defer closing the `` until the exit animation is finished. + +```js +const dialogElem = document.getElementById("dialog"); +const showBtn = document.querySelector(".show"); +const closeBtn = document.querySelector(".close"); + +showBtn.addEventListener("click", () => { + dialogElem.classList.remove("fade-out"); + dialogElem.classList.add("fade-in"); + dialogElem.showModal(); +}); + +closeBtn.addEventListener("click", () => { + dialogElem.classList.remove("fade-in"); + dialogElem.classList.add("fade-out"); + setTimeout(() => { + dialogElem.close(); + }, 500); +}); +``` + +The code renders as follows: + +{{ EmbedLiveSample("dialog keyframe animations", "100%", "200") }} + ## Technical summary From 8fdd02c78c809c24a45d94fbb5dfa6e2a93999c0 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 27 Sep 2023 18:21:03 +0100 Subject: [PATCH 03/22] Improving popover transition examples based on josepharhar feedback --- .../en-us/web/api/popover_api/using/index.md | 62 +++++++++---------- files/en-us/web/css/@starting-style/index.md | 25 ++++++++ files/en-us/web/css/overlay/index.md | 25 ++++++++ .../web/css/transition-behavior/index.md | 25 ++++++++ files/en-us/web/html/element/dialog/index.md | 46 ++++++-------- 5 files changed, 123 insertions(+), 60 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index c7ba84f56ae52dd..295649603e15eea 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -335,19 +335,7 @@ html { font-family: Arial, Helvetica, sans-serif; } -::backdrop { - background-color: rgba(0, 0, 0, 0.1); - transition: - background-color 0.5s, - display 0.5s allow-discrete, - overlay 0.5s allow-discrete; -} - -@starting-style { - ::backdrop { - background-color: rgba(0, 0, 0, 0); - } -} +/* Transition for the popover itself */ [popover]:popover-open { opacity: 1; @@ -366,17 +354,40 @@ html { display 0.7s allow-discrete; } -/* Needs to be included after the previous [popover]:popover-open rule - to take effect, as the specificity is the same */ +/* Needs to be after the previous [popover]:popover-open rule to take effect, + as the specificity is the same */ @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); + 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); +} + +/* This starting-style rule cannot be nested inside the above selector +because the nesting selector cannot represent pseudo-elements. */ + +@starting-style { + [popover]:popover-open::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} ``` -The two 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. +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. And as discussed earlier, we have: @@ -385,7 +396,7 @@ And as discussed earlier, we have: - 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. - Set `allow-discrete` on both the above transitions to enable discrete transitions. -You'll note that we have also done something similar for the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the popover when it opens, to provide a nice darkening animation. +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. The code renders as follows: @@ -413,21 +424,6 @@ html { font-family: Arial, Helvetica, sans-serif; } -/* Transition the :backdrop when the popover is promoted to the top layer */ -::backdrop { - background-color: rgba(0, 0, 0, 0.1); - transition: - background-color 0.5s, - display 0.5s allow-discrete, - overlay 0.5s allow-discrete; -} - -@starting-style { - ::backdrop { - background-color: rgba(0, 0, 0, 0); - } -} - [popover] { font-size: 1.2rem; padding: 10px; @@ -474,7 +470,7 @@ html { } ``` -We have defined keyframes that specify the desired entry and exit animations, and assigned those to CSS classes. Note also that the animation example includes the same [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) transition as the transition demo, to fade the backdrop in. This didn't seem possible to reproduce with a keyframe animation. +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 did, as that didn't seem possible to reproduce with a keyframe animation in our experiments. We then use some rudimentary JavaScript to apply those classes to the popover as it is shown and hidden, triggering the animations at the right times. As mentioned earlier, we have used `setTimeout()` to defer the hiding of the popover until the animations have finished. diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index d7ff28b1c9e88f8..4ba85e730fed78f 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -118,6 +118,29 @@ html { transform: scaleX(0); } } + +/* Transition for the popover's backdrop */ + +[popover]::backdrop { + background-color: rgba(0, 0, 0, 0); + 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); +} + +/* This starting-style rule cannot be nested inside the above selector +because the nesting selector cannot represent pseudo-elements. */ + +@starting-style { + [popover]:popover-open::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} ``` The two properties we want to animate 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). @@ -129,6 +152,8 @@ However, because the animated element is being promoted to the [top layer](/en-U - `display` is added 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. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand so that it will animate. - [`overlay`](/en-US/docs/Web/CSS/overlay) is added 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. +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. + The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} diff --git a/files/en-us/web/css/overlay/index.md b/files/en-us/web/css/overlay/index.md index 4626d46d731e8d9..8500733419cfbae 100644 --- a/files/en-us/web/css/overlay/index.md +++ b/files/en-us/web/css/overlay/index.md @@ -83,6 +83,29 @@ html { transform: scaleX(0); } } + +/* Transition for the popover's backdrop */ + +[popover]::backdrop { + background-color: rgba(0, 0, 0, 0); + 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); +} + +/* This starting-style rule cannot be nested inside the above selector +because the nesting selector cannot represent pseudo-elements. */ + +@starting-style { + [popover]:popover-open::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} ``` The two properties we want to animate 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. @@ -93,6 +116,8 @@ However, because the animated element is being promoted to the [top layer](/en-U - `display` is added 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. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand so that it will animate. - `overlay` is added 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. +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. + The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index e2d47a0e034ae73..73e333ed582f26a 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -105,6 +105,29 @@ html { transform: scaleX(0); } } + +/* Transition for the popover's backdrop */ + +[popover]::backdrop { + background-color: rgba(0, 0, 0, 0); + 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); +} + +/* This starting-style rule cannot be nested inside the above selector +because the nesting selector cannot represent pseudo-elements. */ + +@starting-style { + [popover]:popover-open::backdrop { + background-color: rgba(0, 0, 0, 0); + } +} ``` The two properties we want to animate 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. @@ -117,6 +140,8 @@ However, because the animated element is being promoted to the [top layer](/en-U In the transitions list, `transition-behavior: allow-discrete` is set in the shorthand for both `display` and `overlay` so that they will animate. +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. + The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index 44a62a166a4e00e..d7bd9c85b83ac32 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -166,13 +166,13 @@ The HTML contains a `` element, plus a button to show the dialog. Additi The CSS is as follows: ```css -/* Open state of the dialog */ +/* Open state of the dialog */ dialog[open] { opacity: 1; transform: scaleY(1); } -/* Closed state of the dialog */ +/* Closed state of the dialog */ dialog { transition: opacity 0.5s ease-out, @@ -183,9 +183,9 @@ dialog { transform: scaleY(0); } -/* Before-open state */ +/* Before-open state */ /* Needs to be after the previous dialog[open] rule to take effect, - as the specificity is the same */ + as the specificity is the same */ @starting-style { dialog[open] { opacity: 0; @@ -194,16 +194,23 @@ dialog { } /* Transition the :backdrop when the dialog modal is promoted to the top layer */ -::backdrop { - background-color: rgba(0, 0, 0, 0.1); +dialog::backdrop { + background-color: rgba(0, 0, 0, 0); transition: - background-color 0.5s, - display 0.5s allow-discrete, - overlay 0.5s allow-discrete; + display 0.7s allow-discrete, + overlay 0.7s allow-discrete, + background-color 0.7s; } +dialog[open]::backdrop { + background-color: rgba(0, 0, 0, 0.25); +} + +/* This starting-style rule cannot be nested inside the above selector +because the nesting selector cannot represent pseudo-elements. */ + @starting-style { - ::backdrop { + dialog[open]::backdrop { background-color: rgba(0, 0, 0, 0); } } @@ -214,7 +221,7 @@ button { } ``` -Note the `@starting-style` block used to define the transition starting styles, and the `display` and `overlay` properties included in the transition list, each with `allow-discrete` set on them. Note that we've also included similar CSS to transition the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. +Note the `@starting-style` block used to define the transition starting styles, and the `display` and `overlay` properties included in the transition list, each with `allow-discrete` set on them. Note that we've also included similar CSS to transition the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. `dialog[open]::backdrop` is required to select the backdrop when the dialog is open. The JavaScript serves to wire up the buttons to event handlers that show and close the ``: @@ -302,24 +309,9 @@ body, button { font-family: system-ui; } - -/* Transition the :backdrop when the dialog modal is promoted to the top layer */ -::backdrop { - background-color: rgba(0, 0, 0, 0.1); - transition: - background-color 0.5s, - display 0.5s allow-discrete, - overlay 0.5s allow-discrete; -} - -@starting-style { - ::backdrop { - background-color: rgba(0, 0, 0, 0); - } -} ``` -Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note also that the animation example includes the same [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) transition as the transition demo, to fade the backdrop in. This didn't seem possible to reproduce with a keyframe animation. +Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. This example does not animate the backdrop like the above transition demo does; this didn't seem possible to reproduce with a keyframe animation in our experiments. Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``, while also adding and removing the control classes as required to apply the entry and exit animations. In addition, note how {{domxref("setTimeout()")}} is used to defer closing the `` until the exit animation is finished. From 31142db3fd68e7d6ad76fb6443d2134bac0d0980 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 10 Oct 2023 13:05:34 +0100 Subject: [PATCH 04/22] improve popover keyframe example with beforetoggle --- files/en-us/web/api/popover_api/using/index.md | 18 ++++++++---------- files/en-us/web/html/element/dialog/index.md | 8 +++----- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 295649603e15eea..e7de99a2b0c60cb 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -303,16 +303,14 @@ See our [Popover blur background example](https://mdn.github.io/dom-examples/pop ## Animating popovers -For popovers to be animated, several different features are required. - -First of all, 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, `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: +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: - 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. ### Transitioning a popover -When animating popovers with transitions, these additional features are needed: +When animating popovers with transitions, the following are required: - [`@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. @@ -408,12 +406,12 @@ When animating a popover with [CSS animations](/en-US/docs/Web/CSS/CSS_animation - 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 — animating the popover and then using {{domxref("setTimeout()")}} to defer removal of the popover until after the animation is finished. +- 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. -Let's look at an example. The HTML is contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control: +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: ```html - +
I'm a Popover! I should animate.
``` @@ -470,15 +468,15 @@ html { } ``` -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 did, as that didn't seem possible to reproduce with a keyframe animation in our experiments. +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 shown and hidden, triggering the animations at the right times. As mentioned earlier, we have used `setTimeout()` to defer the hiding of the popover until the animations have finished. +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"); -toggleBtn.addEventListener("click", () => { +popover.addEventListener("beforetoggle", () => { if (!popover.matches(":popover-open")) { popover.classList.remove("fade-out"); popover.classList.add("fade-in"); diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index d7bd9c85b83ac32..13cbebd4f9f0b1c 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -134,16 +134,14 @@ It is important to provide a closing mechanism within every `dialog` element. Th ### Animating dialogs -For `` elements to be animated, several different features are required. - -First of all, ``s 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, `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: +``s 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 `` elements 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: - 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. #### Transitioning dialog elements -When animating ``s with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), these additional features are needed: +When animating ``s with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), the following are required: - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on the `` 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 `` will remain as `display: block` for the duration of the animation, allowing the other animations to be seen. @@ -311,7 +309,7 @@ button { } ``` -Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. This example does not animate the backdrop like the above transition demo does; this didn't seem possible to reproduce with a keyframe animation in our experiments. +Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. 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. Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``, while also adding and removing the control classes as required to apply the entry and exit animations. In addition, note how {{domxref("setTimeout()")}} is used to defer closing the `` until the exit animation is finished. From cc7e120d173583f5be29b6f02c2761c3814c4cc8 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 1 Nov 2023 15:02:02 +0000 Subject: [PATCH 05/22] Making fixes for OnkarRuikar comments --- .../en-us/web/api/popover_api/using/index.md | 46 ++++++++----------- files/en-us/web/css/@starting-style/index.md | 6 +-- .../en-us/web/css/content-visibility/index.md | 6 +-- files/en-us/web/css/display/index.md | 6 +-- files/en-us/web/html/element/dialog/index.md | 46 +++++++++++-------- 5 files changed, 54 insertions(+), 56 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index e7de99a2b0c60cb..889e48e868ae35f 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -308,11 +308,13 @@ Popovers are set to `display: none;` when hidden and `display: block;` when show - 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. +> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), `transition-behavior: allow-discrete` needs to be set to enabled the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. + ### Transitioning a popover When animating popovers with transitions, the following are required: -- [`@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. +- [`@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 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. @@ -402,11 +404,11 @@ The code renders as follows: ### A popover keyframe animation -When animating a popover with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), there are some differences to note: +When animating a popover with 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. +- You can't set `overlay` inside keyframes either, but we found we could get the animation example working OK by setting the animations as appropriate on the shown and closed states of the popover via CSS. 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: @@ -425,16 +427,15 @@ html { [popover] { font-size: 1.2rem; padding: 10px; + animation: fade-out 0.7s ease-out forwards; } -/* Animation classes */ - -.fade-in { +[popover]:popover-open { animation: fade-in 0.7s ease-out forwards; } -.fade-out { - animation: fade-out 0.7s ease-out forwards; +[popover]:popover-open::backdrop { + animation: backdrop-fade-in 0.7s ease-out forwards; } /* Animation keyframes */ @@ -466,31 +467,20 @@ html { display: none; } } -``` -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. +@keyframes backdrop-fade-in { + 0% { + background-color: rgba(0, 0, 0, 0); + } -```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); + 100% { + background-color: rgba(0, 0, 0, 0.25); } -}); +} ``` +We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to reproduce a keyframe animation for the backdrop fade out at the time of writing. + The code renders as follows: {{ EmbedLiveSample("A popover keyframe animation", "100%", "200") }} diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 4ba85e730fed78f..6785876c9d8efa9 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -20,15 +20,15 @@ This enables the easy creation of entry animations that were previously complex ## Syntax ```css -@starting-style {rules} -@starting-style {declarations} +@starting-style { rules } +@starting-style { declarations } ``` where: - _rules_ - : Is the set of CSS rules providing the starting styles for the transition, when `@starting-style` is used in standalone style. -- _rules_ +- _declarations_ - : Is the set of CSS declarations providing the starting styles for the transition, when `@starting-style` is nested inside a particular ruleset. ## Description diff --git a/files/en-us/web/css/content-visibility/index.md b/files/en-us/web/css/content-visibility/index.md index f8c78dc704d769a..03173e528f3469f 100644 --- a/files/en-us/web/css/content-visibility/index.md +++ b/files/en-us/web/css/content-visibility/index.md @@ -51,10 +51,10 @@ This behavior is useful for creating entry/exit animations where you want to for When animating `content-visibility` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `content-visibility` value in an explicit starting keyframe (for example using `0%` or `from`). For a full example, see the [content-visibility animation example](#content-visibility_animation_example) section below. -When animating `content-visibility` with transitions, two additional features are needed: +When animating `content-visibility` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), two additional features are needed: -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. 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 `content-visibility` value changes from `hidden` to `visible`, to avoid unexpected behavior. -- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `content-visibility` when it is transitioned. This effectively enables `content-visibility` transitions, enabling it to animate. +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. This is needed because, by default, CSS transitions are not triggered on elements' first style updates, or when the `content-visibility` value changes from `hidden` to `visible`, to avoid unexpected behavior. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `content-visibility` when it is transitioned. This effectively enables `content-visibility` transitions. ## Formal definition diff --git a/files/en-us/web/css/display/index.md b/files/en-us/web/css/display/index.md index ada34f1245677d8..dd41b88f123e515 100644 --- a/files/en-us/web/css/display/index.md +++ b/files/en-us/web/css/display/index.md @@ -272,10 +272,10 @@ This behavior is useful for creating entry/exit animations where you want to for When animating `display` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `display` value in an explicit starting keyframe (for example using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations) for an example. -When animating `display` with transitions, two additional features are needed (see the below links for examples): +When animating `display` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), two additional features are needed (see the below links for examples): -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. 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. -- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `display` when it is transitioned. This effectively enables `display` transitions, enabling it to animate. +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. This is needed because, by default, 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. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `display` when it is transitioned. This effectively enables `display` transitions. ## Accessibility concerns diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index a017dba3fc80e23..9302b2a9f985931 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -207,9 +207,11 @@ It is important to provide a closing mechanism within every `dialog` element. Th - 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. +> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), `transition-behavior: allow-discrete` needs to be set to enabled the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. + #### Transitioning dialog elements -When animating ``s with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), the following are required: +When animating ``s with CSS transitions, the following are required: - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on the `` 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 `` will remain as `display: block` for the duration of the animation, allowing the other animations to be seen. @@ -311,16 +313,16 @@ The code renders as follows: #### dialog keyframe animations -When animating a `` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), there are some differences to note from transitions: +When animating a `` with CSS animations, there are some differences to note from transitions: - 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 — animating the `` and then using {{domxref("setTimeout()")}} to defer removal of the `` until after the animation is finished. +- You can't set `overlay` inside keyframes either, but we found we could get the animation example working OK by setting the animations as appropriate on the shown and closed states of the `` via CSS. -Let's have a look at an example so you can see what this looks like. First, the HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. The `` has a `class` of `fade-in` set on it, which will trigger the entry animation when the dialog is shown. +Let's have a look at an example so you can see what this looks like. First, the HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. ```html - + Content here @@ -331,14 +333,16 @@ Let's have a look at an example so you can see what this looks like. First, the Now for the CSS: ```css -/* Animation classes */ +dialog { + animation: fade-out 0.7s ease-out forwards; +} -.fade-in { - animation: fade-in 0.5s ease-out forwards; +dialog[open] { + animation: fade-in 0.7s ease-out forwards; } -.fade-out { - animation: fade-out 0.5s ease-out forwards; +dialog[open]::backdrop { + animation: backdrop-fade-in 0.7s ease-out forwards; } /* Animation keyframes */ @@ -371,15 +375,25 @@ Now for the CSS: } } +@keyframes backdrop-fade-in { + 0% { + background-color: rgba(0, 0, 0, 0); + } + + 100% { + background-color: rgba(0, 0, 0, 0.25); + } +} + body, button { font-family: system-ui; } ``` -Note the keyframes defined to animate between the closed and open states, which are then applied to control classes. This includes animating `display` to make sure the actual visible animation effects remain visible for the whole duration. 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. +Note the keyframes defined to animate between the closed and shown states of the ``, plus the fade-in animation for the ``'s backdrop. The `` animations include animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to reproduce a keyframe animation for the backdrop fade out at the time of writing. -Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``, while also adding and removing the control classes as required to apply the entry and exit animations. In addition, note how {{domxref("setTimeout()")}} is used to defer closing the `` until the exit animation is finished. +Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``. ```js const dialogElem = document.getElementById("dialog"); @@ -387,17 +401,11 @@ const showBtn = document.querySelector(".show"); const closeBtn = document.querySelector(".close"); showBtn.addEventListener("click", () => { - dialogElem.classList.remove("fade-out"); - dialogElem.classList.add("fade-in"); dialogElem.showModal(); }); closeBtn.addEventListener("click", () => { - dialogElem.classList.remove("fade-in"); - dialogElem.classList.add("fade-out"); - setTimeout(() => { - dialogElem.close(); - }, 500); + dialogElem.close(); }); ``` From d9365adf50c84a870f819a546ca70b7b835735f2 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 2 Nov 2023 14:32:30 +0000 Subject: [PATCH 06/22] Apply fixes based on estelle and dipikabh comments --- .../web/api/cssstartingstylerule/index.md | 1 + .../en-us/web/api/popover_api/using/index.md | 66 ++++++---- files/en-us/web/css/@starting-style/index.md | 117 ++++++++++-------- .../en-us/web/css/content-visibility/index.md | 22 +++- .../using_css_animations/index.md | 12 +- .../using_css_transitions/index.md | 14 ++- files/en-us/web/css/overlay/index.md | 17 ++- .../web/css/transition-behavior/index.md | 18 ++- files/en-us/web/css/transition/index.md | 6 +- files/en-us/web/html/element/dialog/index.md | 72 +++++++---- 10 files changed, 229 insertions(+), 116 deletions(-) diff --git a/files/en-us/web/api/cssstartingstylerule/index.md b/files/en-us/web/api/cssstartingstylerule/index.md index ba8a7dc779da43a..d29f3734f303f0c 100644 --- a/files/en-us/web/api/cssstartingstylerule/index.md +++ b/files/en-us/web/api/cssstartingstylerule/index.md @@ -30,4 +30,5 @@ _This interface inherits methods from its parent, {{domxref("CSSGroupingRule")}} ## See also - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) +- [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) - [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 889e48e868ae35f..262a4de3292448e 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -303,31 +303,39 @@ See our [Popover blur background example](https://mdn.github.io/dom-examples/pop ## 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: +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")}} and the [accessibility tree](/en-US/docs/Web/Performance/How_browsers_work#building_the_accessibility_tree). Therefore, for popovers to be animated the {{cssxref("display")}} property 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: - 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. -> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), `transition-behavior: allow-discrete` needs to be set to enabled the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. +> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. ### Transitioning a popover -When animating popovers with transitions, the following are required: +When animating popovers with CSS transitions, the following features are required: -- [`@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 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. +- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule + - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed because, by default, CSS transitions only occur when a property changes from one value to another on a visible element; they 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) property + - : Add `display` to the transitions list so that the popover will remain as `display: block` for the duration of the transition, ensuring the other transitions are visible. +- [`overlay`](/en-US/docs/Web/CSS/overlay) property + - : Include `overlay` in the transitions list to ensure the removal of the popover from the top layer is deferred until the transition completes, again ensuring the transition is visible. +- {{cssxref("transition-behavior")}} property + - : Set `transition-behavior: allow-discrete` on the `display` and `overlay` transitions to enable discrete transitions on these two properties that are not by default animatable. 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: +#### HTML + +The HTML contains a {{htmlelement("div")}} element declared to be a popover via the global [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) HTML attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control: ```html
I'm a Popover! I should animate.
``` +#### CSS + The CSS for the example looks like this: ```css @@ -352,6 +360,8 @@ html { transform 0.7s, overlay 0.7s allow-discrete, display 0.7s allow-discrete; + /* Equivalent to + all 0.7s allow-discrete */ } /* Needs to be after the previous [popover]:popover-open rule to take effect, @@ -366,15 +376,17 @@ html { /* Transition for the popover's backdrop */ [popover]::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); transition: display 0.7s allow-discrete, overlay 0.7s allow-discrete, background-color 0.7s; + /* Equivalent to + all 0.7s allow-discrete */ } [popover]:popover-open::backdrop { - background-color: rgba(0, 0, 0, 0.25); + background-color: rgb(0 0 0 / 0.25); } /* This starting-style rule cannot be nested inside the above selector @@ -382,21 +394,23 @@ because the nesting selector cannot represent pseudo-elements. */ @starting-style { [popover]:popover-open::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); } } ``` -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. +The two popover properties we want to transition are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform). We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the default hidden state of the popover element (selected with the `[popover]` [attribute selector](/en-US/docs/Web/CSS/Attribute_selectors)) and an end state for the shown state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We also set the [`transition`](/en-US/docs/Web/CSS/transition) property to define the properties to animate and the animation duration as the popover gets shown or hidden. And as discussed earlier, we have: - Set a starting state for the transition inside the `@starting-style` block. - 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. -- 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. -- Set `allow-discrete` on both the above transitions to enable discrete transitions. +- 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. The effect of this may not be noticeable for basic animations such as this one, but in more complex cases, omitting this property can result in the element being removed from the overlay before the transition completes. +- Set `allow-discrete` on both the above transitions to enable [discrete transitions](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). -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. +You'll note that we've also included a transition on the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) appearing behind the popover when it opens, providing a nice darkening animation. + +#### Result The code renders as follows: @@ -406,17 +420,23 @@ The code renders as follows: When animating a popover with 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, but we found we could get the animation example working OK by setting the animations as appropriate on the shown and closed states of the popover via CSS. +- You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit starting keyframe (using `0%` or `from`). +- You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. +- You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the popover from shown to hidden. + +Let's look at an example. -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: +#### HTML + +The HTML contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control: ```html
I'm a Popover! I should animate.
``` +#### CSS + The CSS is as follows: ```css @@ -470,16 +490,18 @@ html { @keyframes backdrop-fade-in { 0% { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); } 100% { - background-color: rgba(0, 0, 0, 0.25); + background-color: rgb(0 0 0 / 0.25); } } ``` -We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to reproduce a keyframe animation for the backdrop fade out at the time of writing. +We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the popover is closed, so there is nothing to animate. + +#### Result The code renders as follows: diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 6785876c9d8efa9..f74ed83b8465aeb 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -9,31 +9,26 @@ browser-compat: css.at-rules.starting-style {{CSSRef}}{{SeeCompatTable}} -The **`@starting-style`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/CSS/At-rule) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. - -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`](/en-US/docs/Web/CSS/display) type changes from `none` to another type, to avoid unexpected behavior. To put it another way, such elements do not have a starting style to transition from. `@starting-style` allows you to provide starting styles, overriding the default behavior in a specific controlled fashion. - -This enables the easy creation of entry animations that were previously complex to achieve, such as animating elements when they are changed from `display: none` (this includes elements shown in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements) or when they are first added to the DOM. - -> **Note:** `@starting-style` is only relevant to CSS transitions. When animating from `display: none` or animating elements as they are first added to the DOM, [CSS animations](/en-US/docs/Web/CSS/CSS_animations) do not need a `@starting-style` specified; instead you provide the starting style as an explicit starting keyframe (for example using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations) for an example. +The **`@starting-style`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/CSS/At-rule) is used to define starting values for properties set on an element that you want to transition from when the element receives its first style update, i.e. when an element is first displayed on a previously loaded page. ## Syntax ```css -@starting-style { rules } -@starting-style { declarations } +@starting-style { rules } /* when standalone */ +@starting-style { declarations } /* when nested within a ruleset */ ``` -where: +## Description -- _rules_ - - : Is the set of CSS rules providing the starting styles for the transition, when `@starting-style` is used in standalone style. -- _declarations_ - - : Is the set of CSS declarations providing the starting styles for the transition, when `@starting-style` is nested inside a particular ruleset. +By default, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are not triggered on an element's initial style update, or when its [`display`](/en-US/docs/Web/CSS/display) type changes from `none` to another type, to avoid unexpected behavior. `@starting-style` rules are needed to enable first-style transitions; they provide starting styles for elements that do not have a previous state with starting styles to transition from. -## Description +`@starting-style` enables the creation of entry and exit transitions for elements displayed in the [top layer](/en-US/docs/Glossary/Top_layer) (such as [popovers](/en-US/docs/Web/API/Popover_API) and modal {{htmlelement("dialog")}}s), elements that are changing to and from `display: none`, and elements when first added to or removed from the DOM. -There are two ways to use `@starting-style`. Let's consider an example where we want to animate a popover when it is shown (added to the top layer). In this case, the original rule specifying the styles for the popover once opened looks like this (you can see the [full example in action](/en-US/docs/Web/CSS/@starting-style#animating_a_popover) in the examples section): +> **Note:** `@starting-style` is only relevant to CSS transitions. When using [CSS animations](/en-US/docs/Web/CSS/CSS_animations) to animate such elements, `@starting-style` is not needed; instead, provide the starting style as an explicit starting keyframe (using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations#animating_display_and_content-visibility) for an example. + +There are two ways to use `@starting-style`: as a standalone rule or nested within a ruleset. + +Let's consider a scenario where we want to animate a [popover](/en-US/docs/Web/API/Popover_API) when shown (that is, when added to the top layer). The "original rule" specifying the styles for the open popover looks like this (see the [full example in action](/en-US/docs/Web/CSS/@starting-style#animating_a_popover) in the "Examples" section below): ```css [popover]:popover-open { @@ -42,7 +37,7 @@ There are two ways to use `@starting-style`. Let's consider an example where we } ``` -You can specify the starting styles in a separate rule contained within a standalone `@starting-style` block: +To specify the starting style for the popover using the first method, you include a standalone `@starting-style` block in your CSS, as shown below: ```css @starting-style { @@ -53,9 +48,9 @@ You can specify the starting styles in a separate rule contained within a standa } ``` -> **Note:** In the standalone case, you need to specify the `@starting-style` block after the original rule for it to take effect, as the specificity of each is the same. If `@starting-style` was specified first, the original styles would override it. +> **Note:** The `@starting-style` at-rule and the "original rule" have the same specificity. To ensure that starting styles get applied, include the `@starting-style` at-rule _after_ the "original rule". If you specify the `@starting-style` at-rule before the "original rule", the original styles will override the starting styles. -Alternatively, you can nest the starting styles inside the original rule: +To specify the starting style for the popover using the second method, you can nest the `@starting-style` block inside the "original rule", as shown below: ```css [popover]:popover-open { @@ -77,15 +72,19 @@ Alternatively, you can nest the starting styles inside the original rule: ### Animating a popover -This example shows how a [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided. +This example shows how a [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided using the [`transition`](/en-US/docs/Web/CSS/transition) property. -The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. +#### HTML + +The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. ```html
I'm a Popover! I should animate.
``` +#### CSS + The CSS for the example looks like this: ```css @@ -108,10 +107,11 @@ html { transform 0.7s, overlay 0.7s allow-discrete, display 0.7s allow-discrete; + /* Equivalent to + all 0.7s allow-discrete */ } -/* Needs to be included after the previous [popover]:popover-open rule - to take effect, as the specificity is the same */ +/* Include after the [popover]:popover-open rule */ @starting-style { [popover]:popover-open { opacity: 0; @@ -120,47 +120,51 @@ html { } /* Transition for the popover's backdrop */ - [popover]::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); transition: display 0.7s allow-discrete, overlay 0.7s allow-discrete, background-color 0.7s; + /* Equivalent to + all 0.7s allow-discrete */ } [popover]:popover-open::backdrop { - background-color: rgba(0, 0, 0, 0.25); + background-color: rgb(0 0 0 / 0.25); } -/* This starting-style rule cannot be nested inside the above selector -because the nesting selector cannot represent pseudo-elements. */ - +/* Nesting is not supported for pseudo-elements +so specify a standalone starting-style block. */ @starting-style { [popover]:popover-open::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); } } ``` -The two properties we want to animate 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). +In this example, we want to animate two properties, [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform) (specifically, a horizontally scaling transform), to make the popover to fade in and out, as well as grow and shrink 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 ending 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 states. A starting state for the animation is included inside a `@starting-style` at-rule to enable the entry animation. -We then set a [`transition`](/en-US/docs/Web/CSS/transition) property to animate between the two, and include a starting state for the animation inside a [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule, as described above, so the entry animation will work. +However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to ensure the animation works in both directions: -However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to get the animation working in both directions: +- `display` is added to the list of transitioned elements to ensure the animated element is visible (set to `display: block`) throughout both the entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand to activate the animation. +- [`overlay`](/en-US/docs/Web/CSS/overlay) is added to the list of transitioned elements to ensure 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. -- `display` is added 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. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand so that it will animate. -- [`overlay`](/en-US/docs/Web/CSS/overlay) is added 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. +> **Note:** 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 used to select the backdrop when the popover is open. -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. +#### Result The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} -### Transitioning elements as they are added to and removed from the DOM +### Transitioning elements on DOM addition and removal -In this example, we provide a button that appends new elements to a {{htmlelement("section")}} container when pressed. Each element is given a nested close button which, when pressed, removes the element again. We use transitions to animate the elements when they are first added to the DOM, and when they are removed. +This example contains a button, which when pressed, appends new elements to a {{htmlelement("section")}} container. Each element, in turn, contains a nested button, which when pressed, removes the element. This example demonstrates how to use transitions to animate elements when they are added to the DOM and when they are removed. + +#### HTML The static HTML looks like this: @@ -169,7 +173,9 @@ The static HTML looks like this:
``` -The JavaScript that handles the adding and removing looks like this: +#### JavaScript + +The JavaScript code that handles the addition and removal of the elements looks like this: ```js const btn = document.querySelector("button"); @@ -205,11 +211,13 @@ function createColumn() { } ``` -The most interesting part is the `createColumn()` function — note how it creates a {{htmlelement("div")}} element and a {{htmlelement("button")}} element to close the `
` when pressed then appends the ` ``` -The CSS is as follows: +##### CSS ```css /* Open state of the dialog */ @@ -242,13 +248,15 @@ dialog[open] { /* Closed state of the dialog */ dialog { - transition: - opacity 0.5s ease-out, - transform 0.5s ease-out, - overlay 0.5s ease-out allow-discrete, - display 0.5s ease-out allow-discrete; opacity: 0; transform: scaleY(0); + transition: + opacity 0.7s ease-out, + transform 0.7s ease-out, + overlay 0.7s ease-out allow-discrete, + display 0.7s ease-out allow-discrete; + /* Equivalent to + all 0.7s allow-discrete */ } /* Before-open state */ @@ -263,15 +271,17 @@ dialog { /* Transition the :backdrop when the dialog modal is promoted to the top layer */ dialog::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); transition: display 0.7s allow-discrete, overlay 0.7s allow-discrete, background-color 0.7s; + /* Equivalent to + all 0.7s allow-discrete */ } dialog[open]::backdrop { - background-color: rgba(0, 0, 0, 0.25); + background-color: rgb(0 0 0 / 0.25); } /* This starting-style rule cannot be nested inside the above selector @@ -279,7 +289,7 @@ because the nesting selector cannot represent pseudo-elements. */ @starting-style { dialog[open]::backdrop { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); } } @@ -291,6 +301,8 @@ button { Note the `@starting-style` block used to define the transition starting styles, and the `display` and `overlay` properties included in the transition list, each with `allow-discrete` set on them. Note that we've also included similar CSS to transition the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. `dialog[open]::backdrop` is required to select the backdrop when the dialog is open. +##### JavaScript + The JavaScript serves to wire up the buttons to event handlers that show and close the ``: ```js @@ -307,6 +319,8 @@ closeBtn.addEventListener("click", () => { }); ``` +##### Result + The code renders as follows: {{ EmbedLiveSample("Transitioning dialog elements", "100%", "200") }} @@ -315,11 +329,15 @@ The code renders as follows: When animating a `` with CSS animations, there are some differences to note from transitions: -- 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, but we found we could get the animation example working OK by setting the animations as appropriate on the shown and closed states of the `` via CSS. +- You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit starting keyframe (using `0%` or `from`). +- You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. +- You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the `` from shown to hidden. + +Let's have a look at an example so you can see what this looks like. + +##### HTML -Let's have a look at an example so you can see what this looks like. First, the HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. +First, the HTML contains a `` element, plus a button to show the dialog. Additionally, the `` element contains another button to close itself. ```html @@ -330,7 +348,7 @@ Let's have a look at an example so you can see what this looks like. First, the ``` -Now for the CSS: +##### CSS ```css dialog { @@ -377,11 +395,11 @@ dialog[open]::backdrop { @keyframes backdrop-fade-in { 0% { - background-color: rgba(0, 0, 0, 0); + background-color: rgb(0 0 0 / 0); } 100% { - background-color: rgba(0, 0, 0, 0.25); + background-color: rgb(0 0 0 / 0.25); } } @@ -391,7 +409,9 @@ button { } ``` -Note the keyframes defined to animate between the closed and shown states of the ``, plus the fade-in animation for the ``'s backdrop. The `` animations include animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to reproduce a keyframe animation for the backdrop fade out at the time of writing. +Note the keyframes defined to animate between the closed and shown states of the ``, plus the fade-in animation for the ``'s backdrop. The `` animations include animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the `` is closed, so there is nothing to animate. + +##### JavaScript Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``. @@ -409,6 +429,8 @@ closeBtn.addEventListener("click", () => { }); ``` +##### Result + The code renders as follows: {{ EmbedLiveSample("dialog keyframe animations", "100%", "200") }} From b6368b0c2c96f954eaa248f0a3ca8df92dca2226 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 6 Nov 2023 15:36:10 +0000 Subject: [PATCH 07/22] mre fixes for estelle and OnkarRuikar comments --- .../web/api/cssstartingstylerule/index.md | 2 +- .../en-us/web/api/popover_api/using/index.md | 29 +++--- files/en-us/web/css/@starting-style/index.md | 96 +++++++++++-------- .../en-us/web/css/content-visibility/index.md | 12 +-- .../using_css_animations/index.md | 10 +- .../using_css_transitions/index.md | 12 +-- files/en-us/web/css/display/index.md | 2 +- files/en-us/web/css/overlay/index.md | 11 ++- .../web/css/transition-behavior/index.md | 11 ++- files/en-us/web/css/transition/index.md | 2 +- files/en-us/web/html/element/dialog/index.md | 14 +-- 11 files changed, 106 insertions(+), 95 deletions(-) diff --git a/files/en-us/web/api/cssstartingstylerule/index.md b/files/en-us/web/api/cssstartingstylerule/index.md index d29f3734f303f0c..17f40101f20ee46 100644 --- a/files/en-us/web/api/cssstartingstylerule/index.md +++ b/files/en-us/web/api/cssstartingstylerule/index.md @@ -30,5 +30,5 @@ _This interface inherits methods from its parent, {{domxref("CSSGroupingRule")}} ## See also - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) -- [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) +- [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) module - [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 262a4de3292448e..7171fa91d3bda42 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -303,7 +303,7 @@ See our [Popover blur background example](https://mdn.github.io/dom-examples/pop ## 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")}} and the [accessibility tree](/en-US/docs/Web/Performance/How_browsers_work#building_the_accessibility_tree). Therefore, for popovers to be animated the {{cssxref("display")}} property 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: +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")}} and the [accessibility tree](/en-US/docs/Web/Performance/How_browsers_work#building_the_accessibility_tree). Therefore, for popovers to be animated the {{cssxref("display")}} property needs to be animatable. [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: - 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. @@ -315,13 +315,13 @@ Popovers are set to `display: none;` when hidden and `display: block;` when show When animating popovers with CSS transitions, the following features are required: - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule - - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed because, by default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type, to avoid unexpected behavior. + - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type. - [`display`](/en-US/docs/Web/CSS/display) property - : Add `display` to the transitions list so that the popover will remain as `display: block` for the duration of the transition, ensuring the other transitions are visible. - [`overlay`](/en-US/docs/Web/CSS/overlay) property - : Include `overlay` in the transitions list to ensure the removal of the popover from the top layer is deferred until the transition completes, again ensuring the transition is visible. - {{cssxref("transition-behavior")}} property - - : Set `transition-behavior: allow-discrete` on the `display` and `overlay` transitions to enable discrete transitions on these two properties that are not by default animatable. + - : Set `transition-behavior: allow-discrete` on the `display` and `overlay` transitions (or on the {{cssxref("transition")}} shorthand) to enable discrete transitions on these two properties that are not by default animatable. Let's have a look at an example so you can see what this looks like: @@ -336,8 +336,6 @@ The HTML contains a {{htmlelement("div")}} element declared to be a popover via #### CSS -The CSS for the example looks like this: - ```css html { font-family: Arial, Helvetica, sans-serif; @@ -353,15 +351,18 @@ html { [popover] { font-size: 1.2rem; padding: 10px; + + /* Final state of the exit animation */ opacity: 0; transform: scaleX(0); + transition: opacity 0.7s, transform 0.7s, overlay 0.7s allow-discrete, display 0.7s allow-discrete; /* Equivalent to - all 0.7s allow-discrete */ + transition: all 0.7s allow-discrete; */ } /* Needs to be after the previous [popover]:popover-open rule to take effect, @@ -382,7 +383,7 @@ html { overlay 0.7s allow-discrete, background-color 0.7s; /* Equivalent to - all 0.7s allow-discrete */ + transition: all 0.7s allow-discrete; */ } [popover]:popover-open::backdrop { @@ -390,7 +391,7 @@ html { } /* This starting-style rule cannot be nested inside the above selector -because the nesting selector cannot represent pseudo-elements. */ +because the nesting selector (&) cannot represent pseudo-elements. */ @starting-style { [popover]:popover-open::backdrop { @@ -399,7 +400,7 @@ because the nesting selector cannot represent pseudo-elements. */ } ``` -The two popover properties we want to transition are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform). We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the default hidden state of the popover element (selected with the `[popover]` [attribute selector](/en-US/docs/Web/CSS/Attribute_selectors)) and an end state for the shown state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We also set the [`transition`](/en-US/docs/Web/CSS/transition) property to define the properties to animate and the animation duration as the popover gets shown or hidden. +The two popover properties we want to transition are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform). We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the hidden state of the popover element (selected with the `[popover]` [attribute selector](/en-US/docs/Web/CSS/Attribute_selectors)) and an end state for the shown state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We also use the [`transition`](/en-US/docs/Web/CSS/transition) property to define the properties to animate and the animation's duration as the popover gets shown or hidden. And as discussed earlier, we have: @@ -418,10 +419,10 @@ The code renders as follows: ### A popover keyframe animation -When animating a popover with CSS animations, there are some differences to note: +When animating a popover with CSS keyframe animations, there are some differences to note: - You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit starting keyframe (using `0%` or `from`). -- You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. +- You don't explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. - You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the popover from shown to hidden. Let's look at an example. @@ -437,8 +438,6 @@ The HTML contains a {{htmlelement("div")}} element declared as a popover, and a #### CSS -The CSS is as follows: - ```css html { font-family: Arial, Helvetica, sans-serif; @@ -447,11 +446,11 @@ html { [popover] { font-size: 1.2rem; padding: 10px; - animation: fade-out 0.7s ease-out forwards; + animation: fade-out 0.7s ease-out; } [popover]:popover-open { - animation: fade-in 0.7s ease-out forwards; + animation: fade-in 0.7s ease-out; } [popover]:popover-open::backdrop { diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index f74ed83b8465aeb..3f6365c8ea21bff 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -13,22 +13,39 @@ The **`@starting-style`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/C ## Syntax -```css -@starting-style { rules } /* when standalone */ -@starting-style { declarations } /* when nested within a ruleset */ -``` +The `@starting-style` at rule can be used in two ways: + +1. As a standalone block, in which case it contains one or more rulesets defining starting style declarations and selecting the elements they apply to: + + ```css + @starting-style { + rulesets + } + ``` + +2. Nested within an existing ruleset, in which case it contains one or more declarations defining starting styles for the elements already selected by that ruleset: + + ```css + selector { /* existing ruleset */ + /* ... */ + + @starting-style { + declarations + } + } + ``` ## Description -By default, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are not triggered on an element's initial style update, or when its [`display`](/en-US/docs/Web/CSS/display) type changes from `none` to another type, to avoid unexpected behavior. `@starting-style` rules are needed to enable first-style transitions; they provide starting styles for elements that do not have a previous state with starting styles to transition from. +To avoid unexpected behavior, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are by default not triggered on an element's initial style update, or when its [`display`](/en-US/docs/Web/CSS/display) type changes from `none` to another type. To enable first-style transitions, `@starting-style` rules are needed. They provide starting styles for elements that do not have a previous state, defining the styles to transition from. -`@starting-style` enables the creation of entry and exit transitions for elements displayed in the [top layer](/en-US/docs/Glossary/Top_layer) (such as [popovers](/en-US/docs/Web/API/Popover_API) and modal {{htmlelement("dialog")}}s), elements that are changing to and from `display: none`, and elements when first added to or removed from the DOM. +`@starting-style` is especially useful when creating entry and exit transitions for elements displayed in the [top layer](/en-US/docs/Glossary/Top_layer) (such as [popovers](/en-US/docs/Web/API/Popover_API) and modal {{htmlelement("dialog")}}s), elements that are changing to and from `display: none`, and elements when first added to or removed from the DOM. > **Note:** `@starting-style` is only relevant to CSS transitions. When using [CSS animations](/en-US/docs/Web/CSS/CSS_animations) to animate such elements, `@starting-style` is not needed; instead, provide the starting style as an explicit starting keyframe (using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations#animating_display_and_content-visibility) for an example. There are two ways to use `@starting-style`: as a standalone rule or nested within a ruleset. -Let's consider a scenario where we want to animate a [popover](/en-US/docs/Web/API/Popover_API) when shown (that is, when added to the top layer). The "original rule" specifying the styles for the open popover looks like this (see the [full example in action](/en-US/docs/Web/CSS/@starting-style#animating_a_popover) in the "Examples" section below): +Let's consider a scenario where we want to animate a [popover](/en-US/docs/Web/API/Popover_API) when shown (that is, when added to the top layer). The "original rule" specifying the styles for the open popover looks like this (see the [full example in action](#animating_a_popover) in the "Examples" section below): ```css [popover]:popover-open { @@ -48,9 +65,9 @@ To specify the starting style for the popover using the first method, you includ } ``` -> **Note:** The `@starting-style` at-rule and the "original rule" have the same specificity. To ensure that starting styles get applied, include the `@starting-style` at-rule _after_ the "original rule". If you specify the `@starting-style` at-rule before the "original rule", the original styles will override the starting styles. +> **Note:** The `@starting-style` at-rule and the "original rule" have the same {{cssxref("specificity")}}. To ensure that starting styles get applied, include the `@starting-style` at-rule _after_ the "original rule". If you specify the `@starting-style` at-rule before the "original rule", the original styles will override the starting styles. -To specify the starting style for the popover using the second method, you can nest the `@starting-style` block inside the "original rule", as shown below: +To specify the starting style for the popover using the nested method, you can nest the `@starting-style` block inside the "original rule", as shown below: ```css [popover]:popover-open { @@ -85,8 +102,6 @@ The HTML contains a {{htmlelement("div")}} element declared as a popover using t #### CSS -The CSS for the example looks like this: - ```css html { font-family: Arial, Helvetica, sans-serif; @@ -100,15 +115,18 @@ html { [popover] { font-size: 1.2rem; padding: 10px; + + /* Final state of the exit animation */ opacity: 0; transform: scaleX(0); + transition: opacity 0.7s, transform 0.7s, overlay 0.7s allow-discrete, display 0.7s allow-discrete; /* Equivalent to - all 0.7s allow-discrete */ + transition: all 0.7s allow-discrete; */ } /* Include after the [popover]:popover-open rule */ @@ -127,14 +145,14 @@ html { overlay 0.7s allow-discrete, background-color 0.7s; /* Equivalent to - all 0.7s allow-discrete */ + transition: all 0.7s allow-discrete; */ } [popover]:popover-open::backdrop { background-color: rgb(0 0 0 / 0.25); } -/* Nesting is not supported for pseudo-elements +/* Nesting (&) is not supported for pseudo-elements so specify a standalone starting-style block. */ @starting-style { [popover]:popover-open::backdrop { @@ -143,13 +161,13 @@ so specify a standalone starting-style block. */ } ``` -In this example, we want to animate two properties, [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform) (specifically, a horizontally scaling transform), to make the popover to fade in and out, as well as grow and shrink 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 ending state on the open state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). +In this example, we want to animate two properties, [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform) (specifically, a horizontally scaling transform), to make the popover fade in and out as well as grow and shrink 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 ending 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 states. A starting state for the animation is included inside a `@starting-style` at-rule to enable the entry animation. However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden — which also means that its hidden state has [`display: none`](/en-US/docs/Web/CSS/display) set on it — some extra steps are required to ensure the animation works in both directions: -- `display` is added to the list of transitioned elements to ensure the animated element is visible (set to `display: block`) throughout both the entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand to activate the animation. +- `display` is added to the list of transitioned elements to ensure the animated element is visible (set to `display: block` or another visible `display` value) throughout both the entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand to activate the animation. - [`overlay`](/en-US/docs/Web/CSS/overlay) is added to the list of transitioned elements to ensure 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. > **Note:** 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 used to select the backdrop when the popover is open. @@ -160,14 +178,14 @@ The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} +> **Note:** You can find an example that demonstrates transitioning a {{htmlelement("dialog")}} element and its backdrop as it is shown and hidden on the `` reference page — see [Transitioning dialog elements](/en-US/docs/Web/HTML/Element/dialog#transitioning_dialog_elements). + ### Transitioning elements on DOM addition and removal -This example contains a button, which when pressed, appends new elements to a {{htmlelement("section")}} container. Each element, in turn, contains a nested button, which when pressed, removes the element. This example demonstrates how to use transitions to animate elements when they are added to the DOM and when they are removed. +This example contains a button, which when pressed, appends new elements to a {{htmlelement("section")}} container. Each element, in turn, contains a nested button, which when pressed, removes the element. This example demonstrates how to use transitions to animate elements when they are added to or removed from the DOM. #### HTML -The static HTML looks like this: - ```html
@@ -175,7 +193,7 @@ The static HTML looks like this: #### JavaScript -The JavaScript code that handles the addition and removal of the elements looks like this: +JavaScript enables the addition and removal of elements: ```js const btn = document.querySelector("button"); @@ -184,11 +202,11 @@ const sectionElem = document.querySelector("section"); btn.addEventListener("click", createColumn); function randomColor() { - function randomChannel() { + function randomNum() { return Math.floor(Math.random() * 255); } - return `rgb(${randomChannel()},${randomChannel()},${randomChannel()})`; + return `rgb(${randomNum()} ${randomNum()} ${randomNum()})`; } function createColumn() { @@ -211,16 +229,16 @@ function createColumn() { } ``` -The most interesting part is the `createColumn()` function. Notice how it creates a {{htmlelement("div")}} element and a {{htmlelement("button")}} element to close the `
` when pressed, then appends the ` ``` -The CSS is as follows: +#### CSS + +```css hidden +html { + height: 100vh; +} + +button { + font-size: 1.4rem; + padding: 10px 20px; + border: 1px solid #ccc; + border-radius: 10px; + outline: none; +} +``` ```css .target { - font-size: 1.4rem; - transition-property: opacity; - transition-duration: 1s; + transition-property: background-color; + transition-duration: 0.7s; + background-color: #ccc; } .target:hover, .target:focus { - opacity: 0; + background-color: #eee; } ``` {{EmbedLiveSample('Basic_example', 600, 100)}} +See our [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) guide for more `transition-property` examples. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/css/transition/index.md b/files/en-us/web/css/transition/index.md index b6c813f49c5c24b..9f5d11587c4d3e8 100644 --- a/files/en-us/web/css/transition/index.md +++ b/files/en-us/web/css/transition/index.md @@ -63,19 +63,30 @@ The `transition` property value is specified as one of the following: - The special value `none`, which specifies that no transitions will occur on this element. This is the default value. - One or more single-property transitions, separated by commas. -- One single-property transition, which is structured as described below, except that the special value `all` is used in place of a property value. This specifies that the transition will be applied to all properties that change as the element changes state. - > **Note:** If you exclude the property value in the single-property transition, then a value of `all` will be inferred and the specified transition will still apply to all changing properties. -Each single-property transition describes the transition that should be applied to a single property. It includes: +Each single-property transition describes the transition that should be applied to a single property or all properties. It includes: -- zero or one {{cssxref("<custom-ident>")}} value representing the property to which the transition should apply. +- zero or one value representing the property or properties to which the transition should apply. This can be set as: + - A {{cssxref("<custom-ident>")}} representing a single property. + - The special value `all`, which specifies that the transition will be applied to all properties that change as the element changes state. + - No value, in which case a value of `all` will be inferred and the specified transition will still apply to all changing properties. - zero or one {{cssxref("<easing-function>")}} value representing the easing function to use - zero, one, or two {{cssxref("<time>")}} values. The first value that can be parsed as a time is assigned to the {{cssxref("transition-duration")}}, and the second value that can be parsed as a time is assigned to {{cssxref("transition-delay")}}. -- zero or one value declaring whether to start transitions for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete): +- zero or one value declaring whether to start transitions for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). This can be one of: - the keyword `allow-discrete` - the keyword `normal` +If you specify `all` as the transition property for one single-property transition, but then specify subsequent single-property transitions with {{cssxref("<custom-ident>")}} values, those subsequent transitions will override the first one. For example: + +```css +transition: + all 200ms, + opacity 400ms; +``` + +In this case, {{cssxref("opacity")}} will transition with a duration of 400ms, but all other properties that change as the element changes state will transition with a duration of 200ms. + See [how things are handled](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions#when_property_value_lists_are_of_different_lengths) when lists of property values aren't the same length. In short, extra transition descriptions beyond the number of properties actually being animated are ignored. ## Formal definition @@ -88,8 +99,6 @@ See [how things are handled](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_trans ## Examples -> **Note:** See [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) for more `transition` examples. - ### Basic example In this example, when the user hovers over the element, there is a one-second delay before the four-second `font-size` transition occurs. @@ -117,30 +126,6 @@ We include two {{cssxref("time")}} values. In the `transition` shorthand, the fi {{EmbedLiveSample('Basic_example', 600, 100)}} -### Transitioning top layer elements - -The [`overlay`](/en-US/docs/Web/CSS/overlay) property can be added to the list of transition properties set on an element displayed in the [top layer](/en-US/docs/Glossary/Top_layer) — for example a [popover](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} element. This causes its removal from the top layer to be deferred so it can be animated instead of disappearing immediately. - -Sample CSS: - -```css -[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; - /* Equivalent to - transition: all 0.7s allow-discrete; */ -} -``` - -See the [`overlay`](/en-US/docs/Web/CSS/overlay) page for a full working example. - ## Specifications {{Specifications}} @@ -152,4 +137,5 @@ See the [`overlay`](/en-US/docs/Web/CSS/overlay) page for a full working example ## See also - [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) module +- [Using CSS transitions](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) - {{ domxref("TransitionEvent") }} diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index d7bf9f5ac986335..c06a9fdfced19df 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -202,10 +202,12 @@ It is important to provide a closing mechanism within every `dialog` element. Th ### Animating dialogs -``s are set to `display: none;` when hidden and `display: block;` when shown, as well as being removed from / added to the {{glossary("top layer")}} and the [accessibility tree](/en-US/docs/Web/Performance/How_browsers_work#building_the_accessibility_tree). Therefore, for `` elements to be animated the {{cssxref("display")}} property needs to be animatable. [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: +``s are set to `display: none;` when hidden and `display: block;` when shown, as well as being removed from / added to the {{glossary("top layer")}} and the [accessibility tree](/en-US/docs/Web/Performance/How_browsers_work#building_the_accessibility_tree). Therefore, for `` elements to be animated the {{cssxref("display")}} property needs to be animatable. [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 the entire animation duration. -- 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. +So for example: + +- When animating `display` from `none` to `block` (or another visible `display` value), the value will flip to `block` at `0%` of the animation duration so it is visible throughout. +- When animating `display` from `block` (or another visible `display` value) to `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout. > **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. @@ -329,7 +331,7 @@ The code renders as follows: When animating a `` with CSS animations, there are some differences to note from transitions: -- You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit starting keyframe (using `0%` or `from`). +- You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit keyframe (using `0%` or `from`). - You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. - You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the `` from shown to hidden. From 41105a82a047699bb68a93dac1e0cc85c02b58ef Mon Sep 17 00:00:00 2001 From: Estelle Weyl Date: Mon, 13 Nov 2023 01:04:49 -0800 Subject: [PATCH 10/22] comma --- files/en-us/web/api/popover_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 62f026a7997ff1e..965e66dc4e5e7fa 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -308,7 +308,7 @@ Popovers are set to `display: none;` when hidden and `display: block;` when show - When animating `display` from `none` to `block` (or another visible `display` value), the value will flip to `block` at `0%` of the animation duration so it is visible throughout. - When animating `display` from `block` (or another visible `display` value) to `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout. -> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. +> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), the above behavior is available by default; an equivalent step is not required. ### Transitioning a popover From b289c4a405ee2fb05a2384c947109c520fb9d705 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:51:26 +0000 Subject: [PATCH 11/22] Update files/en-us/web/api/cssstartingstylerule/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/api/cssstartingstylerule/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/cssstartingstylerule/index.md b/files/en-us/web/api/cssstartingstylerule/index.md index 17f40101f20ee46..4d624c6f138b203 100644 --- a/files/en-us/web/api/cssstartingstylerule/index.md +++ b/files/en-us/web/api/cssstartingstylerule/index.md @@ -7,7 +7,7 @@ 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. +The **`CSSStartingStyleRule`** interface of the [CSS Object Model](/en-US/docs/Web/API/CSS_Object_Model) represents a CSS {{CSSxRef("@starting-style")}} at-rule. {{InheritanceDiagram}} From 506100e20147b4ee41c541fc9a1abfe74ba8d3e4 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:51:37 +0000 Subject: [PATCH 12/22] Update files/en-us/web/api/cssstartingstylerule/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/api/cssstartingstylerule/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/cssstartingstylerule/index.md b/files/en-us/web/api/cssstartingstylerule/index.md index 4d624c6f138b203..ef25e2ad4ecf274 100644 --- a/files/en-us/web/api/cssstartingstylerule/index.md +++ b/files/en-us/web/api/cssstartingstylerule/index.md @@ -29,6 +29,6 @@ _This interface inherits methods from its parent, {{domxref("CSSGroupingRule")}} ## See also -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) +- {{CSSxRef("@starting-style")}} - [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) module - [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information) From e2937ee47a013475b9fc817d86e42e3767aae9c9 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:51:49 +0000 Subject: [PATCH 13/22] Update files/en-us/web/api/popover_api/using/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/api/popover_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 965e66dc4e5e7fa..f6b16996fa830f3 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -314,7 +314,7 @@ Popovers are set to `display: none;` when hidden and `display: block;` when show When animating popovers with CSS transitions, the following features are required: -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule +- {{CSSxRef("@starting-style")}} at-rule - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on an element's first style update, or when the `display` type changes from `none` to another type. - [`display`](/en-US/docs/Web/CSS/display) property - : Add `display` to the transitions list so that the popover will remain as `display: block` (or another visible `display` value) for the duration of the transition, ensuring the other transitions are visible. From 1be535b260b057fdb49ddd557889c75bb934e0a5 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:52:02 +0000 Subject: [PATCH 14/22] Update files/en-us/web/api/popover_api/using/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/api/popover_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index f6b16996fa830f3..6e71a9895346a60 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -316,7 +316,7 @@ When animating popovers with CSS transitions, the following features are require - {{CSSxRef("@starting-style")}} at-rule - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on an element's first style update, or when the `display` type changes from `none` to another type. -- [`display`](/en-US/docs/Web/CSS/display) property +- {{CSSxRef("display")}} property - : Add `display` to the transitions list so that the popover will remain as `display: block` (or another visible `display` value) for the duration of the transition, ensuring the other transitions are visible. - [`overlay`](/en-US/docs/Web/CSS/overlay) property - : Include `overlay` in the transitions list to ensure the removal of the popover from the top layer is deferred until the transition completes, again ensuring the transition is visible. From 657a296058bea2076d5ff35bd647e0042da986a5 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:52:13 +0000 Subject: [PATCH 15/22] Update files/en-us/web/api/popover_api/using/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/api/popover_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 6e71a9895346a60..ce5dd67454cae29 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -318,7 +318,7 @@ When animating popovers with CSS transitions, the following features are require - : Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on an element's first style update, or when the `display` type changes from `none` to another type. - {{CSSxRef("display")}} property - : Add `display` to the transitions list so that the popover will remain as `display: block` (or another visible `display` value) for the duration of the transition, ensuring the other transitions are visible. -- [`overlay`](/en-US/docs/Web/CSS/overlay) property +- {{CSSxRef("overlay")}} property - : Include `overlay` in the transitions list to ensure the removal of the popover from the top layer is deferred until the transition completes, again ensuring the transition is visible. - {{cssxref("transition-behavior")}} property - : Set `transition-behavior: allow-discrete` on the `display` and `overlay` transitions (or on the {{cssxref("transition")}} shorthand) to enable discrete transitions on these two properties that are not by default animatable. From d8169d14d58e169d4346e1e71b39935c20984d58 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:52:29 +0000 Subject: [PATCH 16/22] Update files/en-us/web/css/@starting-style/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/css/@starting-style/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index e325c531ac65824..94f10ad9c014487 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -37,7 +37,7 @@ The `@starting-style` at rule can be used in two ways: ## Description -To avoid unexpected behavior, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are by default not triggered on an element's initial style update, or when its [`display`](/en-US/docs/Web/CSS/display) type changes from `none` to another value. To enable first-style transitions, `@starting-style` rules are needed. They provide starting styles for elements that do not have a previous state, defining the property values to transition from. +To avoid unexpected behavior, [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) are by default not triggered on an element's initial style update, or when its {{CSSxRef("display")}} type changes from `none` to another value. To enable first-style transitions, `@starting-style` rules are needed. They provide starting styles for elements that do not have a previous state, defining the property values to transition from. `@starting-style` is especially useful when creating entry and exit transitions for elements displayed in the [top layer](/en-US/docs/Glossary/Top_layer) (such as [popovers](/en-US/docs/Web/API/Popover_API) and modal {{htmlelement("dialog")}}s), elements that are changing to and from `display: none`, and elements when first added to or removed from the DOM. From c0bb544f7afd7e999f021a20831bfe5e2b0e47e6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 08:52:42 +0000 Subject: [PATCH 17/22] Update files/en-us/web/css/@starting-style/index.md Co-authored-by: Rami Yushuvaev --- files/en-us/web/css/@starting-style/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 94f10ad9c014487..4b52b97d3305390 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -89,7 +89,7 @@ To specify the starting style for the popover using the nested method, you can n ### Animating a popover -In this example, the [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided using the [`transition`](/en-US/docs/Web/CSS/transition) property. +In this example, the [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided using the {{CSSxRef("transition")}} property. #### HTML From 465deb6a4820a5ff5f3b3fc0569dcdfaa1d63d6a Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 14 Nov 2023 12:49:41 +0000 Subject: [PATCH 18/22] Fixes for estelle latest comments, add more examples on @starting-style page --- .../en-us/web/api/popover_api/using/index.md | 24 ++-- files/en-us/web/css/@starting-style/index.md | 133 +++++++++++++++++- files/en-us/web/css/overlay/index.md | 8 +- .../web/css/transition-behavior/index.md | 8 +- .../web/css/transition-property/index.md | 2 +- files/en-us/web/html/element/dialog/index.md | 25 ++-- 6 files changed, 171 insertions(+), 29 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index ce5dd67454cae29..ce44bc20e269e44 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -327,15 +327,17 @@ Let's have a look at an example so you can see what this looks like: #### HTML -The HTML contains a {{htmlelement("div")}} element declared to be a popover via the global [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) HTML attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control: +The HTML contains a {{htmlelement("div")}} element declared to be a popover via the global [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) HTML attribute, and a {{htmlelement("button")}} element designated as the popover's display control: ```html - +
I'm a Popover! I should animate.
``` #### CSS +The two popover properties we want to transition are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform). We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the hidden state of the popover element (selected with the `[popover]` [attribute selector](/en-US/docs/Web/CSS/Attribute_selectors)) and an end state for the shown state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We also use the [`transition`](/en-US/docs/Web/CSS/transition) property to define the properties to animate and the animation's duration as the popover gets shown or hidden. + ```css html { font-family: Arial, Helvetica, sans-serif; @@ -400,9 +402,7 @@ so this starting-style rule cannot be nested */ } ``` -The two popover properties we want to transition are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform). We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the hidden state of the popover element (selected with the `[popover]` [attribute selector](/en-US/docs/Web/CSS/Attribute_selectors)) and an end state for the shown state of the popover (selected via the [`:popover-open`](/en-US/docs/Web/CSS/:popover-open) pseudo-class). We also use the [`transition`](/en-US/docs/Web/CSS/transition) property to define the properties to animate and the animation's duration as the popover gets shown or hidden. - -And as discussed earlier, we have: +As discussed earlier, we have also: - Set a starting state for the `transition` inside the `@starting-style` block. - Added `display` to the list of transitioned properties so that the animated element is visible (set to `display: block`) throughout the popover's entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear. @@ -417,6 +417,10 @@ The code renders as follows: {{ EmbedLiveSample("Transitioning a popover", "100%", "200") }} +> **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. +> +> It is possible for the style transition on entry and exit to be different in such cases. See our [Demonstration of when starting styles are used](/en-US/docs/Web/CSS/@starting-style#demonstration_of_when_starting_styles_are_used) example for a proof of this. + ### A popover keyframe animation When animating a popover with CSS keyframe animations, there are some differences to note: @@ -429,15 +433,17 @@ Let's look at an example. #### HTML -The HTML contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's toggle control: +The HTML contains a {{htmlelement("div")}} element declared as a popover, and a {{htmlelement("button")}} element designated as the popover's display control: ```html - -
I'm a Popover! I should animate.
+ +
I'm a Popover! I should animate.
``` #### CSS +We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the popover is closed, so there is nothing to animate. + ```css html { font-family: Arial, Helvetica, sans-serif; @@ -498,8 +504,6 @@ html { } ``` -We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the popover is closed, so there is nothing to animate. - #### Result The code renders as follows: diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 4b52b97d3305390..60b036b288b0fc1 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -81,22 +81,143 @@ To specify the starting style for the popover using the nested method, you can n } ``` +### When exactly are starting styles used? + +It is important to understand that an element will transition from its `@starting-style` styles when it is first rendered in the DOM, or when it transitions from {{cssxref("display", "display: none")}} (or {{cssxref("content-visibility", "content-visibility: hidden")}}) to a visible value. When it transitions back from its initial visible state, it will no longer use the `@starting-style` styles as it is now visible in the DOM. Instead, it will transition back to whatever styles exist for that element's default state. + +In effect, there are three style states to manage in these situations — starting-style state, transitioned state, and default state. It is possible for the "to" and "from" transitions to be different in such cases. You can see a proof of this in our [Demonstration of when starting styles are used](#demonstration_of_when_starting_styles_are_used) example, below. + ## Formal syntax {{csssyntax}} ## Examples +### Basic @starting-style usage + +Transition an element's {{cssxref("background-color")}} from transparent to green when it is initially rendered: + +```css +#target { + transition: background-color 1.5s; + background-color: green; +} + +@starting-style { + #target { + background-color: transparent; + } +} +``` + +Transition the {{cssxref("opacity")}} of an element when it changes its {{cssxref("display")}} value to or from `none`: + +```css +#target { + transition-property: opacity, display; + transition-duration: 0.5s; + display: block; + opacity: 1; + @starting-style { + opacity: 0; + } +} + +#target.hidden { + display: none; + opacity: 0; +} +``` + +### Demonstration of when starting styles are used + +In this example, a button is pressed to create a {{htmlelement("div")}} element, give it a `class` of `showing`, and add it to the DOM. + +`showing` is given a `@starting-style` of `background-color: red` and a style of `background-color: blue` to transition to. The default `div` ruleset contains `background-color: yellow`, and is also where the `transition` is set. + +When the `
` is first added to the DOM, you'll see the background transition from red to blue. After a timeout, we remove the `showing` class from the `
` via JavaScript. At that point it transitions from blue back to yellow, not red. This proves that the starting styles are only used when the element is first rendered in the DOM. Once it has appeared, the element transitions back to the default style set on it. + +After another timeout, we then remove the `
` from the DOM altogether, resetting the initial state of the example so it can be run again. + +#### HTML + +```html + +``` + +#### CSS + +```css hidden +div { + width: 200px; + height: 100px; + border: 1px solid black; + margin-top: 10px; +} + +div::after { + content: "class: " attr(class); + position: relative; + top: 3px; + left: 3px; +} +``` + +```css +div { + background-color: yellow; + transition: background-color 3s; +} + +div.showing { + background-color: skyblue; +} + +@starting-style { + div.showing { + background-color: red; + } +} +``` + +#### JavaScript + +```js +const btn = document.querySelector("button"); + +btn.addEventListener("click", () => { + btn.disabled = true; + const divElem = document.createElement("div"); + divElem.classList.add("showing"); + document.body.append(divElem); + + setTimeout(() => { + divElem.classList.remove("showing"); + + setTimeout(() => { + divElem.remove(); + btn.disabled = false; + }, 3000); + }, 3000); +}); +``` + +#### Result + +The code renders as follows: + +{{ EmbedLiveSample("Demonstration of when starting styles are used", "100%", "150") }} + ### Animating a popover -In this example, the [popover](/en-US/docs/Web/API/Popover_API) can be animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided using the {{CSSxRef("transition")}} property. +In this example, a [popover](/en-US/docs/Web/API/Popover_API) is animated using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions). Basic entry and exit animations are provided using the {{CSSxRef("transition")}} property. #### HTML -The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. +The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute and a {{htmlelement("button")}} element designated as the popover's display control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. ```html - +
I'm a Popover! I should animate.
``` @@ -167,7 +288,7 @@ To achieve this, we have set a starting state for these properties on the defaul We then set a [`transition`](/en-US/docs/Web/CSS/transition) property to animate between the two states. A starting state for the animation is included inside a `@starting-style` at-rule to enable the entry animation. -However, because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden (with [`display: none`](/en-US/docs/Web/CSS/display)), some extra steps are required to ensure the animation works in both directions: +Because the animated element is being promoted to the [top layer](/en-US/docs/Glossary/Top_layer) when shown and removed from the top layer when hidden (with [`display: none`](/en-US/docs/Web/CSS/display)), some extra steps are required to ensure the animation works in both directions: - `display` is added to the list of transitioned elements to ensure the animated element is visible (set to `display: block` or another visible `display` value) throughout both the entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear. Note that the [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) value is also set in the shorthand to activate the animation. - [`overlay`](/en-US/docs/Web/CSS/overlay) is added to the list of transitioned elements to ensure that the removal of the element from the top layer is deferred until the animation ends. 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. Again, `transition-behavior: allow-discrete` is required in this case for the animation to occur. @@ -180,6 +301,8 @@ The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} +> **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. + > **Note:** You can find an example that demonstrates transitioning a {{htmlelement("dialog")}} element and its backdrop as it is shown and hidden on the `` reference page — see [Transitioning dialog elements](/en-US/docs/Web/HTML/Element/dialog#transitioning_dialog_elements). ### Transitioning elements on DOM addition and removal @@ -231,7 +354,7 @@ function createColumn() { } ``` -When the "Create new column" button is clicked, the `createColumn()` function is called. This creates a {{htmlelement("div")}} element with a randomly generated background color and a {{htmlelement("button")}} element to close the `
` when pressed. It then appends the ` +
I'm a Popover! I should animate.
``` @@ -134,6 +134,10 @@ The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} +> **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. +> +> It is possible for the style transition on entry and exit to be different in such cases. See our [Demonstration of when starting styles are used](/en-US/docs/Web/CSS/@starting-style#demonstration_of_when_starting_styles_are_used) example for a proof of this. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index 243551e2ec4b14b..48f3f02e8dd67d2 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -66,10 +66,10 @@ In this example, a [popover](/en-US/docs/Web/API/Popover_API) is animated as it #### HTML -The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, and a {{htmlelement("button")}} element designated as the popover's toggle control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. +The HTML contains a {{htmlelement("div")}} element declared as a popover using the [popover](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, and a {{htmlelement("button")}} element designated as the popover's display control using its [popovertarget](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute. ```html - +
I'm a Popover! I should animate.
``` @@ -154,6 +154,10 @@ The code renders as follows: {{ EmbedLiveSample("Animating a popover", "100%", "200") }} +> **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. +> +> It is possible for the style transition on entry and exit to be different in such cases. See our [Demonstration of when starting styles are used](/en-US/docs/Web/CSS/@starting-style#demonstration_of_when_starting_styles_are_used) example for a proof of this. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/css/transition-property/index.md b/files/en-us/web/css/transition-property/index.md index ad4fa4285f8b731..48d06d3a57135f0 100644 --- a/files/en-us/web/css/transition-property/index.md +++ b/files/en-us/web/css/transition-property/index.md @@ -62,7 +62,7 @@ transition-property: unset; ### Basic example -When the button is hovered or focused, it undergoes a one-second opacity transition; the `transition-property` is [`background-color`](/en-US/docs/Web/CSS/background-color). +When the button is hovered or focused, it undergoes a one-second color transition; the `transition-property` is [`background-color`](/en-US/docs/Web/CSS/background-color). #### HTML diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index c06a9fdfced19df..9a457ada72e9c89 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -209,7 +209,7 @@ So for example: - When animating `display` from `none` to `block` (or another visible `display` value), the value will flip to `block` at `0%` of the animation duration so it is visible throughout. - When animating `display` from `block` (or another visible `display` value) to `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout. -> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. When animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations) the above behavior is available by default; an equivalent step is not required. +> **Note:** When animating using [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set to enable the above behavior. This behavior is available by default when animating with [CSS animations](/en-US/docs/Web/CSS/CSS_animations); an equivalent step is not required. #### Transitioning dialog elements @@ -241,6 +241,10 @@ The HTML contains a `` element, plus a button to show the dialog. Additi ##### CSS +In the CSS, we include a `@starting-style` block that defines the transition starting styles for the `opacity` and `transform` properties, transition end styles on the `dialog[open]` state, and default styles on the default `dialog` state to transition back to once the `` has appeared. Note how the the ``'s `transition` list includes not only these properties, but also the `display` and `overlay` properties, each with `allow-discrete` set on them. + +We also set a starting style value for the {{cssxref("background-color")}} property on the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. The `dialog[open]::backdrop` selector selects only the backdrops of `` elements when the dialog is open. + ```css /* Open state of the dialog */ dialog[open] { @@ -301,11 +305,9 @@ button { } ``` -Note the `@starting-style` block used to define the transition starting styles, and the `display` and `overlay` properties included in the transition list, each with `allow-discrete` set on them. Note that we've also included similar CSS to transition the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. `dialog[open]::backdrop` is required to select the backdrop when the dialog is open. - ##### JavaScript -The JavaScript serves to wire up the buttons to event handlers that show and close the ``: +The JavaScript adds event handlers to the show and close buttons causing them to show and close the `` when they are clicked: ```js const dialogElem = document.getElementById("dialog"); @@ -327,11 +329,16 @@ The code renders as follows: {{ EmbedLiveSample("Transitioning dialog elements", "100%", "200") }} +> **Note:** Because ``s change from `display: none` to `display: block` each time they are shown, the `` transitions from its `@starting-style` styles to its `dialog[open]` styles every time the entry transition occurs. When the `` closes, it transitions from its `dialog[open]` state to the default `dialog` state. +> +> It is possible for the style transition on entry and exit to be different in such cases. See our [Demonstration of when starting styles are used](/en-US/docs/Web/CSS/@starting-style#demonstration_of_when_starting_styles_are_used) example for a proof of this. + #### dialog keyframe animations -When animating a `` with CSS animations, there are some differences to note from transitions: +When animating a `` with CSS keyframe animations, there are some differences to note from transitions: -- You don't provide a `@starting-style`; instead, you provide the starting values (including the initial `display` value) in an explicit keyframe (using `0%` or `from`). +- You don't provide a `@starting-style`; instead, you provide the starting value in an explicit keyframe (using `0%` or `from`). +- You include the `display` value in a keyframe; this will be the `display` value for the entirety of the animation, or until another non-`none` display value is encountered. - You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. - You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the `` from shown to hidden. @@ -352,6 +359,8 @@ First, the HTML contains a `` element, plus a button to show the dialog. ##### CSS +The CSS defines keyframes to animate between the closed and shown states of the ``, plus the fade-in animation for the ``'s backdrop. The `` animations include animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the `` is closed, so there is nothing to animate. + ```css dialog { animation: fade-out 0.7s ease-out; @@ -411,11 +420,9 @@ button { } ``` -Note the keyframes defined to animate between the closed and shown states of the ``, plus the fade-in animation for the ``'s backdrop. The `` animations include animating `display` to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the `` is closed, so there is nothing to animate. - ##### JavaScript -Finally, the JavaScript serves to wire up the buttons to event handlers that show and close the ``. +Finally, the JavaScript adds event handlers to the buttons to enable showing and closing the ``: ```js const dialogElem = document.getElementById("dialog"); From a45138865d0a0d820f8ed5eb2e4c5d042fe85687 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 15 Nov 2023 08:34:53 +0000 Subject: [PATCH 19/22] More fixes for estelle comments --- .../web/css/transition-behavior/index.md | 58 ++++++++----------- files/en-us/web/css/transition/index.md | 7 +-- 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index 48f3f02e8dd67d2..7a6535b15de1025 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -11,8 +11,6 @@ browser-compat: css.properties.transition-behavior The **`transition-behavior`** [CSS](/en-US/docs/Web/CSS) property specifies whether transitions will be started for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). -This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), the first two of which historically were not animatable. The ability of these elements to be transitioned means that it is fairly easy to create entry and exit animations, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. - ## Syntax ```css @@ -35,6 +33,23 @@ transition-behavior: unset; - `normal` - : Transitions will _not_ be started on the element for discrete animated properties. +## Description + +When attempting to transition properties with a [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete), `transition-behavior` must be set to `allow-discrete` to enable those transitions to occur. + +This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), which historically were not animatable. The ability of these elements to be transitioned means that it is fairly easy to create entry and exit transitions, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. + +### Discrete animation behavior + +Discrete-animated properties generally flip between two values 50% through animating between the two. + +There is an exception, however, which is when animating to or from `display: none` or `content-visibility: hidden`. In this case, the browser will flip between the two values so that the transitioned content is shown for the entire animation duration. + +So for example: + +- When animating `display` from `none` to `block` (or another visible `display` value), the value will flip to `block` at `0%` of the animation duration so it is visible throughout. +- When animating `display` from `block` (or another visible `display` value) to `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout. + ## Formal definition {{cssinfo}} @@ -75,20 +90,24 @@ The HTML contains a {{htmlelement("div")}} element declared as a popover using t #### CSS -```css +```css hidden html { font-family: Arial, Helvetica, sans-serif; } +[popover] { + font-size: 1.2rem; + padding: 10px; +} +``` + +```css [popover]:popover-open { opacity: 1; transform: scaleX(1); } [popover] { - font-size: 1.2rem; - padding: 10px; - /* Final state of the exit animation */ opacity: 0; transform: scaleX(0); @@ -110,31 +129,6 @@ html { transform: scaleX(0); } } - -/* Transition for the popover's backdrop */ - -[popover]::backdrop { - background-color: rgb(0 0 0 / 0); - transition: - display 0.7s allow-discrete, - overlay 0.7s allow-discrete, - background-color 0.7s; - /* Equivalent to - transition: all 0.7s allow-discrete; */ -} - -[popover]:popover-open::backdrop { - background-color: rgb(0 0 0 / 0.25); -} - -/* The nesting selector (&) cannot represent pseudo-elements -so this starting-style rule cannot be nested */ - -@starting-style { - [popover]:popover-open::backdrop { - background-color: rgb(0 0 0 / 0); - } -} ``` The two properties we want to animate are [`opacity`](/en-US/docs/Web/CSS/opacity) and [`transform`](/en-US/docs/Web/CSS/transform)): we want the popover to fade in and out while growing and shrinking in the horizontal direction. We 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. @@ -146,8 +140,6 @@ Because the animated element is being promoted to the [top layer](/en-US/docs/Gl In addition, a starting state for the animation is set inside the [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule. This is needed to avoid unexpected behavior. By default transitions are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type. `@starting-style` allows you to override that default in a specific controlled fashion. Without this, the entry animation would not occur and the popover would just appear. -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. - #### Result The code renders as follows: diff --git a/files/en-us/web/css/transition/index.md b/files/en-us/web/css/transition/index.md index 9f5d11587c4d3e8..0da9d6203242caa 100644 --- a/files/en-us/web/css/transition/index.md +++ b/files/en-us/web/css/transition/index.md @@ -72,10 +72,7 @@ Each single-property transition describes the transition that should be applied - No value, in which case a value of `all` will be inferred and the specified transition will still apply to all changing properties. - zero or one {{cssxref("<easing-function>")}} value representing the easing function to use - zero, one, or two {{cssxref("<time>")}} values. The first value that can be parsed as a time is assigned to the {{cssxref("transition-duration")}}, and the second value that can be parsed as a time is assigned to {{cssxref("transition-delay")}}. -- zero or one value declaring whether to start transitions for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). This can be one of: - - - the keyword `allow-discrete` - - the keyword `normal` +- zero or one value declaring whether to start transitions for properties whose animation behavior is [discrete](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). The value, if present, is either the keyword `allow-discrete` or the keyword `normal`. If you specify `all` as the transition property for one single-property transition, but then specify subsequent single-property transitions with {{cssxref("<custom-ident>")}} values, those subsequent transitions will override the first one. For example: @@ -85,7 +82,7 @@ transition: opacity 400ms; ``` -In this case, {{cssxref("opacity")}} will transition with a duration of 400ms, but all other properties that change as the element changes state will transition with a duration of 200ms. +In this case, all the properties that change as the element changes state will transition with a duration of 200ms except for {{cssxref("opacity")}}, which will take 400ms to transition. See [how things are handled](/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions#when_property_value_lists_are_of_different_lengths) when lists of property values aren't the same length. In short, extra transition descriptions beyond the number of properties actually being animated are ignored. From 4023e96c893ab61a97621f102d1ef657ea6f86f3 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 16 Nov 2023 08:40:29 +0000 Subject: [PATCH 20/22] More estelle fixes --- .../en-us/web/api/popover_api/using/index.md | 2 ++ files/en-us/web/css/overlay/index.md | 7 +++++++ .../web/css/transition-behavior/index.md | 20 ++++++++++++------- files/en-us/web/html/element/dialog/index.md | 9 ++------- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index ce44bc20e269e44..ebb10d8e8938c81 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -489,6 +489,8 @@ html { 100% { opacity: 0; transform: scaleX(0); + /* display: none not required here because it is the default value + for a closed popover, but including it so the behavior is clear */ display: none; } } diff --git a/files/en-us/web/css/overlay/index.md b/files/en-us/web/css/overlay/index.md index a3ff01635c68c48..5b34da706a9f1a1 100644 --- a/files/en-us/web/css/overlay/index.md +++ b/files/en-us/web/css/overlay/index.md @@ -21,6 +21,13 @@ It is important to note that `overlay` can _only_ be set by the browser — auth /* Keyword values */ overlay: auto; overlay: none; + +/* Global values */ +display: inherit; +display: initial; +display: revert; +display: revert-layer; +display: unset; ``` ### Values diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index 7a6535b15de1025..77d0d9a649a8d50 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -112,13 +112,19 @@ html { opacity: 0; transform: scaleX(0); - transition: - opacity 0.7s, - transform 0.7s, - overlay 0.7s allow-discrete, - display 0.7s allow-discrete; - /* Equivalent to - transition: all 0.7s allow-discrete; */ + transition-property: opacity, transform, overlay, display; + transition-duration: 0.7s; + transition-behavior: allow-discrete; + /* Using the shorthand transition property, we could write: + transition: + opacity 0.7s, + transform 0.7s, + overlay 0.7s allow-discrete, + display 0.7s allow-discrete; + + or even: + transition: all 0.7s allow-discrete; + */ } /* Needs to be included after the previous [popover]:popover-open diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index 9a457ada72e9c89..f06495dff95530c 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -216,9 +216,9 @@ So for example: When animating ``s with CSS transitions, the following features are required: - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) at-rule - - : Provides a set of starting values for properties set on the `` that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type. + - : Provides a set of starting values for properties set on the `` that you want to transition from every time it is opened. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on elements' first style updates, or when the `display` type changes from `none` to another type. - [`display`](/en-US/docs/Web/CSS/display) property - - : Add `display` to the transitions list so that the `` will remain as `display: block` for the duration of the transition, ensuring the other transitions are visible. + - : Add `display` to the transitions list so that the `` will remain as `display: block` (or another visible `display` value set on the dialog's open state) for the duration of the transition, ensuring the other transitions are visible. - [`overlay`](/en-US/docs/Web/CSS/overlay) property - : Include `overlay` in the transitions list to ensure the removal of the `` from the top layer is deferred until the transition completes, again ensuring the transition is visible. - {{cssxref("transition-behavior")}} property @@ -298,11 +298,6 @@ because the nesting selector cannot represent pseudo-elements. */ background-color: rgb(0 0 0 / 0); } } - -body, -button { - font-family: system-ui; -} ``` ##### JavaScript From beb0532f76468a36846085284dc04ea4d5018972 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 20 Nov 2023 13:17:41 +0000 Subject: [PATCH 21/22] More estelle and Onkar comment fixes --- .../en-us/web/css/content-visibility/index.md | 6 +-- .../using_css_transitions/index.md | 2 +- files/en-us/web/css/display/index.md | 2 +- files/en-us/web/css/overlay/index.md | 8 ++-- .../web/css/transition-behavior/index.md | 48 ++++++++++++------- .../web/css/transition-property/index.md | 2 +- files/en-us/web/html/element/dialog/index.md | 14 +++--- 7 files changed, 49 insertions(+), 33 deletions(-) diff --git a/files/en-us/web/css/content-visibility/index.md b/files/en-us/web/css/content-visibility/index.md index 099127d34873669..4cf5567141e1781 100644 --- a/files/en-us/web/css/content-visibility/index.md +++ b/files/en-us/web/css/content-visibility/index.md @@ -51,7 +51,7 @@ Discrete animation generally means that the property will flip between two value This behavior is useful for creating entry/exit animations where you want to, for example, remove some content from the DOM with `content-visibility: hidden`, but you want a smooth transition (such as a fade-out) rather than it disappearing immediately. -When animating `content-visibility` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `content-visibility` value in an explicit keyframe (for example using `0%` or `from`). For a full example, see the [content-visibility animation example](#content-visibility_animation_example) below. +When animating `content-visibility` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `content-visibility` value in an explicit keyframe (for example using `0%` or `from`). For a full example, see the [Animating content-visibility](#animating_content-visibility) example below. When animating `content-visibility` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), two additional features are needed: @@ -169,7 +169,7 @@ document.querySelectorAll("button.toggle").forEach((button) => { {{ EmbedLiveSample('Using hidden to manually manage visibility') }} -### content-visibility animation example +### Animating content-visibility In this example, we have a {{htmlelement("div")}} element, the content of which can be toggled between shown and hidden by clicking or pressing any key. @@ -267,7 +267,7 @@ function showHide() { The rendered result looks like this: -{{ EmbedLiveSample("content-visibility animation example", "100%", "300") }} +{{ EmbedLiveSample("Animating content-visibility", "100%", "300") }} ## Specifications diff --git a/files/en-us/web/css/css_transitions/using_css_transitions/index.md b/files/en-us/web/css/css_transitions/using_css_transitions/index.md index 669631a69b0d8e0..66dd045c97a2dce 100644 --- a/files/en-us/web/css/css_transitions/using_css_transitions/index.md +++ b/files/en-us/web/css/css_transitions/using_css_transitions/index.md @@ -262,7 +262,7 @@ div { } ``` -Note the `@starting-style` block used to specify the starting style for the transition, and the inclusion of the `display` property in the trainsitions list, with `allow-discrete` set on it. +Note the `@starting-style` block used to specify the starting style for the transition, and the inclusion of the `display` property in the transitions list, with `allow-discrete` set on it. #### JavaScript diff --git a/files/en-us/web/css/display/index.md b/files/en-us/web/css/display/index.md index 168ec2bc772430f..c7350ed2a03b8c2 100644 --- a/files/en-us/web/css/display/index.md +++ b/files/en-us/web/css/display/index.md @@ -275,7 +275,7 @@ When animating `display` with [CSS animations](/en-US/docs/Web/CSS/CSS_animation When animating `display` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), two additional features are needed: - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) provides starting values for properties you want to transition from when the animated element is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions are not triggered on an element's first style update or when the `display` type changes from `none` to another type. -- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `display` when it is transitioned to enable `display` transitions. +- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on the {{cssxref("transition-property")}} declaration (or the {{cssxref("transition")}} shorthand) to enable `display` transitions. For examples of transitioning the `display` property, see the [`@starting-style`](/en-US/docs/Web/CSS/@starting-style#examples) and [`transition-behavior`](/en-US/docs/Web/CSS/transition-behavior#examples) pages. diff --git a/files/en-us/web/css/overlay/index.md b/files/en-us/web/css/overlay/index.md index 5b34da706a9f1a1..488e31da9b09e43 100644 --- a/files/en-us/web/css/overlay/index.md +++ b/files/en-us/web/css/overlay/index.md @@ -9,7 +9,7 @@ browser-compat: css.properties.overlay {{CSSRef}}{{SeeCompatTable}} -The **`overlay`** [CSS](/en-US/docs/Web/CSS) property specifies whether an element appearing in the [top layer](/en-US/docs/Glossary/Top_layer) (for example, a shown [popover](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} element) is actually rendered in the top layer. +The **`overlay`** [CSS](/en-US/docs/Web/CSS) property specifies whether an element appearing in the [top layer](/en-US/docs/Glossary/Top_layer) (for example, a shown [popover](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} element) is actually rendered in the top layer. This property is only relevant within a list of {{cssxref("transition-property")}} values, and only if `allow-discrete` is set as the {{cssxref("transition-behavior")}}. It is important to note that `overlay` can _only_ be set by the browser — author styles cannot change the `overlay` value of any element. You can, however, add `overlay` to the [list of transition properties](/en-US/docs/Web/CSS/transition-property) set on an element. This causes its removal from the top layer to be deferred so it can be animated instead of disappearing immediately. @@ -62,6 +62,8 @@ The HTML contains a {{htmlelement("div")}} element declared as a popover using t #### CSS +The `overlay` property is only present in the list of transitioned properties. As `overlay` is a user-agent controlled property, it is not declared in the pre-transition or post-transition states. + ```css html { font-family: Arial, Helvetica, sans-serif; @@ -139,7 +141,7 @@ You'll note that we've also included a transition on the [`::backdrop`](/en-US/d The code renders as follows: -{{ EmbedLiveSample("Animating a popover", "100%", "200") }} +{{ EmbedLiveSample("Transitioning a popover", "100%", "200") }} > **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. > @@ -155,7 +157,7 @@ The code renders as follows: ## See also -- [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) +- [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions) module - [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) - [`transition-behavior`](/en-US/docs/Web/CSS/transition-behavior) - [Four new CSS features for smooth entry and exit animations](https://developer.chrome.com/blog/entry-exit-animations/) on developer.chrome.com (2023) diff --git a/files/en-us/web/css/transition-behavior/index.md b/files/en-us/web/css/transition-behavior/index.md index 77d0d9a649a8d50..3de56806463920f 100644 --- a/files/en-us/web/css/transition-behavior/index.md +++ b/files/en-us/web/css/transition-behavior/index.md @@ -35,9 +35,36 @@ transition-behavior: unset; ## Description -When attempting to transition properties with a [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete), `transition-behavior` must be set to `allow-discrete` to enable those transitions to occur. +The `transition-behavior` property is only relevant when used in conjunction with other transition properties, notably {{cssxref("transition-property")}} and {{cssxref("transition-duration")}}, as no transition occurs if no properties are animated over a non-zero duration of time. -This is most significant in the cases of [`display`](/en-US/docs/Web/CSS/display), [`content-visibility`](/en-US/docs/Web/CSS/display), and [`overlay`](/en-US/docs/Web/CSS/overlay), which historically were not animatable. The ability of these elements to be transitioned means that it is fairly easy to create entry and exit transitions, where an element is transitioned to and from a hidden state (which includes elements appearing in the [top layer](/en-US/docs/Glossary/Top_layer) such as [popovers](/en-US/docs/Web/API/Popover_API) or modal {{htmlelement("dialog")}} elements), or transitioned as soon as it is added to the DOM. +```css +.card { + transition-property: opacity, display; + transition-duration: 0.25s; + transition-behavior: allow-discrete; +} + +.card.fade-out { + opacity: 0; + display: none; +} +``` + +The `transition-behavior` value can be included as part of a shorthand {{cssxref("transition")}} declaration. When included in the shorthand, when using or defaulting to all properties, the `allow-discrete` value has no impact on regular animatable properties. The following CSS is equivalent to the longhand declarations above: + +```css +.card { + transition: all 0.25s; + transition: all 0.25s allow-discrete; +} + +.card.fade-out { + opacity: 0; + display: none; +} +``` + +In the above snippet we include the `transition` property twice. The first instance does not include the `allow-discrete` value — this provides cross-browser support, ensuring the card's other properties still transition in browsers that don't support `transition-behavior.` ### Discrete animation behavior @@ -60,21 +87,6 @@ So for example: ## Examples -### Basic usage - -```css -.card { - transition-property: opacity, display; - transition-duration: 0.25s; - transition-behavior: allow-discrete; -} - -.card.fade-out { - opacity: 0; - display: none; -} -``` - ### Transitioning a popover In this example, a [popover](/en-US/docs/Web/API/Popover_API) is animated as it [transitions](/en-US/docs/Web/CSS/CSS_transitions) from hidden to shown and back again. @@ -150,7 +162,7 @@ In addition, a starting state for the animation is set inside the [`@starting-st The code renders as follows: -{{ EmbedLiveSample("Animating a popover", "100%", "200") }} +{{ EmbedLiveSample("Transitioning a popover", "100%", "200") }} > **Note:** Because popovers change from `display: none` to `display: block` each time they are shown, the popover transitions from its `@starting-style` styles to its `[popover]:popover-open` styles every time the entry transition occurs. When the popover closes, it transitions from its `[popover]:popover-open` state to the default `[popover]` state. > diff --git a/files/en-us/web/css/transition-property/index.md b/files/en-us/web/css/transition-property/index.md index 48d06d3a57135f0..2299ed32eccc47c 100644 --- a/files/en-us/web/css/transition-property/index.md +++ b/files/en-us/web/css/transition-property/index.md @@ -89,7 +89,7 @@ button { ```css .target { transition-property: background-color; - transition-duration: 0.7s; + transition-duration: 1s; background-color: #ccc; } diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index f06495dff95530c..d6af0223fe0b387 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -51,7 +51,9 @@ This example demonstrates the create a non-modal dialog by using only HTML. Beca {{EmbedLiveSample("HTML-only_dialog", "100%", 200)}} -This dialog is initially open because of the presence of the `open` attribute. Dialogs that are displayed using the `open` attribute are non-modal. You may notice that after clicking "OK", the dialog gets dismissed leaving the Result frame empty. When the dialog is dismissed, there is no method provided to reopen it. For this reason, the preferred method to display non-modal dialogs is by using the {{domxref("HTMLDialogElement.show()")}} method. It is possible to toggle the display of the dialog by adding or removing the boolean `open` attribute, but it is not the recommended practice. +> **Note:** Reload the page to reset the output. + +This dialog is initially open because of the presence of the `open` attribute. Dialogs that are displayed using the `open` attribute are non-modal. After clicking "OK", the dialog gets dismissed, leaving the Result frame empty. When the dialog is dismissed, there is no method provided to reopen it. For this reason, the preferred method to display non-modal dialogs is by using the {{domxref("HTMLDialogElement.show()")}} method. It is possible to toggle the display of the dialog by adding or removing the boolean `open` attribute, but it is not the recommended practice. ### Creating a modal dialog @@ -187,11 +189,11 @@ confirmBtn.addEventListener("click", (event) => { {{EmbedLiveSample("Handling the return value from the dialog", "100%", 300)}} -This example demonstrates the following three methods of closing modal dialogs: +The above examples demonstrate the following three methods of closing modal dialogs: -- By submitting the form within the dialog form using the `dialog` method (as seen in the [HTML-only example](#caveats-of-creating-a-dialog-using-only-html)). +- By submitting the form within the dialog form using the `dialog` method (as seen in the [HTML-only example](#html-only_dialog)). - By pressing the Esc key. -- By calling the {{domxref("HTMLDialogElement.close()")}} method (as seen in the [modal example](#creating_a_modal_dialog). +- By calling the {{domxref("HTMLDialogElement.close()")}} method (as seen in the [modal example](#creating_a_modal_dialog)). In this example, the "Cancel" button closes the dialog via the `dialog` form method and the "Confirm" button closes the dialog via the {{domxref("HTMLDialogElement.close()")}} method. The "Cancel" button includes the [`formmethod="dialog"`](/en-US/docs/Web/HTML/Element/input/submit#formmethod) attribute, which overrides the {{HTMLElement("form")}}'s default {{HTTPMethod("GET")}} method. When a form's method is [`dialog`](#usage_notes), the state of the form is saved but not submitted, and the dialog gets closed. @@ -241,12 +243,12 @@ The HTML contains a `` element, plus a button to show the dialog. Additi ##### CSS -In the CSS, we include a `@starting-style` block that defines the transition starting styles for the `opacity` and `transform` properties, transition end styles on the `dialog[open]` state, and default styles on the default `dialog` state to transition back to once the `` has appeared. Note how the the ``'s `transition` list includes not only these properties, but also the `display` and `overlay` properties, each with `allow-discrete` set on them. +In the CSS, we include a `@starting-style` block that defines the transition starting styles for the `opacity` and `transform` properties, transition end styles on the `dialog[open]` state, and default styles on the default `dialog` state to transition back to once the `` has appeared. Note how the ``'s `transition` list includes not only these properties, but also the `display` and `overlay` properties, each with `allow-discrete` set on them. We also set a starting style value for the {{cssxref("background-color")}} property on the [`::backdrop`](/en-US/docs/Web/CSS/::backdrop) that appears behind the `` when it opens, to provide a nice darkening animation. The `dialog[open]::backdrop` selector selects only the backdrops of `` elements when the dialog is open. ```css -/* Open state of the dialog */ +/* Open state of the dialog */ dialog[open] { opacity: 1; transform: scaleY(1); From 6bc44bf0695a93ae8905ada803616a1bbfd5d3d0 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 20 Nov 2023 14:42:08 +0000 Subject: [PATCH 22/22] Update descriptions in light of content-visibility transitions not needing @starting-style --- files/en-us/web/api/popover_api/using/index.md | 2 +- files/en-us/web/css/@starting-style/index.md | 4 ++-- files/en-us/web/css/content-visibility/index.md | 7 ++----- .../web/css/css_animations/using_css_animations/index.md | 2 +- .../web/css/css_transitions/using_css_transitions/index.md | 5 ++--- files/en-us/web/html/element/dialog/index.md | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index ebb10d8e8938c81..189894d871b325b 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -425,7 +425,7 @@ The code renders as follows: When animating a popover with CSS keyframe animations, there are some differences to note: -- You don't provide a `@starting-style`; instead, you provide the starting values in an explicit keyframe (using `0%` or `from`). Also, include a visible `display` value. +- You don't provide a `@starting-style`; you include your "to" and "from" `display` values in keyframes. - You don't explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. - You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the popover from shown to hidden. diff --git a/files/en-us/web/css/@starting-style/index.md b/files/en-us/web/css/@starting-style/index.md index 60b036b288b0fc1..1a02300e2ec3cb4 100644 --- a/files/en-us/web/css/@starting-style/index.md +++ b/files/en-us/web/css/@starting-style/index.md @@ -41,7 +41,7 @@ To avoid unexpected behavior, [CSS transitions](/en-US/docs/Web/CSS/CSS_transiti `@starting-style` is especially useful when creating entry and exit transitions for elements displayed in the [top layer](/en-US/docs/Glossary/Top_layer) (such as [popovers](/en-US/docs/Web/API/Popover_API) and modal {{htmlelement("dialog")}}s), elements that are changing to and from `display: none`, and elements when first added to or removed from the DOM. -> **Note:** `@starting-style` is only relevant to CSS transitions. When using [CSS animations](/en-US/docs/Web/CSS/CSS_animations) to animate such elements, `@starting-style` is not needed; instead, provide the starting style in an explicit keyframe (using `0%` or `from`). See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations#animating_display_and_content-visibility) for an example. +> **Note:** `@starting-style` is only relevant to CSS transitions. When using [CSS animations](/en-US/docs/Web/CSS/CSS_animations) to implement such effects, `@starting-style` is not needed. See [Using CSS animations](/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations) for an example. There are two ways to use `@starting-style`: as a standalone rule or nested within a ruleset. @@ -83,7 +83,7 @@ To specify the starting style for the popover using the nested method, you can n ### When exactly are starting styles used? -It is important to understand that an element will transition from its `@starting-style` styles when it is first rendered in the DOM, or when it transitions from {{cssxref("display", "display: none")}} (or {{cssxref("content-visibility", "content-visibility: hidden")}}) to a visible value. When it transitions back from its initial visible state, it will no longer use the `@starting-style` styles as it is now visible in the DOM. Instead, it will transition back to whatever styles exist for that element's default state. +It is important to understand that an element will transition from its `@starting-style` styles when it is first rendered in the DOM, or when it transitions from {{cssxref("display", "display: none")}} to a visible value. When it transitions back from its initial visible state, it will no longer use the `@starting-style` styles as it is now visible in the DOM. Instead, it will transition back to whatever styles exist for that element's default state. In effect, there are three style states to manage in these situations — starting-style state, transitioned state, and default state. It is possible for the "to" and "from" transitions to be different in such cases. You can see a proof of this in our [Demonstration of when starting styles are used](#demonstration_of_when_starting_styles_are_used) example, below. diff --git a/files/en-us/web/css/content-visibility/index.md b/files/en-us/web/css/content-visibility/index.md index 4cf5567141e1781..2bd9ad0ca6af873 100644 --- a/files/en-us/web/css/content-visibility/index.md +++ b/files/en-us/web/css/content-visibility/index.md @@ -51,12 +51,9 @@ Discrete animation generally means that the property will flip between two value This behavior is useful for creating entry/exit animations where you want to, for example, remove some content from the DOM with `content-visibility: hidden`, but you want a smooth transition (such as a fade-out) rather than it disappearing immediately. -When animating `content-visibility` with [CSS animations](/en-US/docs/Web/CSS/CSS_animations), you need to provide the starting `content-visibility` value in an explicit keyframe (for example using `0%` or `from`). For a full example, see the [Animating content-visibility](#animating_content-visibility) example below. +When animating `content-visibility` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `content-visibility`. This effectively enables `content-visibility` transitions. -When animating `content-visibility` with [CSS transitions](/en-US/docs/Web/CSS/CSS_transitions), two additional features are needed: - -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) provides a set of starting values for properties that you want to transition from when the animated element is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions are not triggered on elements' first style updates, or when the `content-visibility` value changes from `hidden` to `visible`. -- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on `content-visibility` when it is transitioned. This effectively enables `content-visibility` transitions. +> **Note:** When transitioning an element's `content-visibility` value, you don't need to provide a set of starting values for transitioned properties using a [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) block, like you do when [transitioning `display`](/en-US/docs/Web/CSS/display#animating_display). This is because `content-visibility` doesn't hide an element from the DOM like `display` does: it just skips rendering the element's content. ## Formal definition diff --git a/files/en-us/web/css/css_animations/using_css_animations/index.md b/files/en-us/web/css/css_animations/using_css_animations/index.md index 3e8a7e2be577347..d4c6c60d5c8560a 100644 --- a/files/en-us/web/css/css_animations/using_css_animations/index.md +++ b/files/en-us/web/css/css_animations/using_css_animations/index.md @@ -475,7 +475,7 @@ div.fade-out { } ``` -Note the inclusion of the `display` property in the keyframe animations. When animating `display` or `content-visibility`, you need to provide the starting value in an explicit keyframe (for example using `0%` or `from`). +Note the inclusion of the `display` property in the keyframe animations. #### JavaScript diff --git a/files/en-us/web/css/css_transitions/using_css_transitions/index.md b/files/en-us/web/css/css_transitions/using_css_transitions/index.md index 66dd045c97a2dce..2935f74b89ebce5 100644 --- a/files/en-us/web/css/css_transitions/using_css_transitions/index.md +++ b/files/en-us/web/css/css_transitions/using_css_transitions/index.md @@ -198,10 +198,9 @@ So for example: - When animating `display` from `none` to `block` (or another visible `display` value), the value will flip to `block` at `0%` of the animation duration so it is visible throughout. - When animating `display` from `block` (or another visible `display` value) to `none`, the value will flip to `none` at `100%` of the animation duration so it is visible throughout. -When transitioning these properties, two additional features are also needed: +When transitioning these properties [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on the transitions. This effectively enables `display`/`content-visibility` transitions. -- [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is used to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. This is needed to avoid unexpected behavior. By default, CSS transitions are not triggered on elements' first style updates, or when `display`/`content-visibility` changes from `none`/`hidden` to another state. -- [`transition-behavior: allow-discrete`](/en-US/docs/Web/CSS/transition-behavior) needs to be set on the transitions. This effectively enables `display`/`content-visibility` transitions. +When transitioning `display`, [`@starting-style`](/en-US/docs/Web/CSS/@starting-style) is needed to provide a set of starting values for properties set on an element that you want to transition from when the element receives its first style update. This is needed to avoid unexpected behavior. By default, CSS transitions are not triggered on elements' first style updates when they first appear in the DOM, which includes when `display` changes from `none` to another state. `content-visibility` animations do not need starting values specified in a `@starting-style` block. This is because `content-visibility` doesn't hide an element from the DOM like `display` does: it just skips rendering the element's content. #### HTML diff --git a/files/en-us/web/html/element/dialog/index.md b/files/en-us/web/html/element/dialog/index.md index d6af0223fe0b387..c293e490afc265a 100644 --- a/files/en-us/web/html/element/dialog/index.md +++ b/files/en-us/web/html/element/dialog/index.md @@ -334,7 +334,7 @@ The code renders as follows: When animating a `` with CSS keyframe animations, there are some differences to note from transitions: -- You don't provide a `@starting-style`; instead, you provide the starting value in an explicit keyframe (using `0%` or `from`). +- You don't provide a `@starting-style`. - You include the `display` value in a keyframe; this will be the `display` value for the entirety of the animation, or until another non-`none` display value is encountered. - You don't need to explicitly enable discrete animations; there is no equivalent to `allow-discrete` inside keyframes. - You don't need to set `overlay` inside keyframes either; the `display` animation handles the animation of the `` from shown to hidden.