trigger-scope CSS property

Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.

The trigger-scope CSS property can be used to limit the scope of a scroll-triggered animation trigger name to a document subtree.

Syntax

css
/* Keywords */
trigger-scope: none;
trigger-scope: all;

/* <dashed-ident> */
trigger-scope: --my-trigger;

/* Multiple values */
trigger-scope: --my-trigger, --another-trigger;

/* Global values */
trigger-scope: inherit;
trigger-scope: initial;
trigger-scope: revert;
trigger-scope: revert-layer;
trigger-scope: unset;

Values

Specified as none, all, or a comma-separated list of <dashed-ident> values:

none

Specifies that no trigger scoping is set. This is the default value.

all

Sets the scope so that any timeline-trigger-name values set in the subtree can only be associated with animated elements in the same subtree.

<dashed-ident>

A trigger name. Sets the scope so that the specified timeline-trigger-name values, when set in the subtree, can only be associated with animated elements in the same subtree.

Description

The trigger-scope property is used to limit trigger scope to specific element subtrees in scroll-triggered animations.

Trigger names, defined with the timeline-trigger-name property, are global by default. When an animated element is associated with a trigger name via its animation-trigger property, the browser determines what its trigger element is as follows:

  1. It walks up the animated element's ancestor tree until it finds an ancestor with a timeline-trigger-name set that is the same as the name referenced in its animation-trigger property value. If the animated element is also the trigger, it will be found instantly.
  2. If it can't find a suitable ancestor trigger, it will use the last element in the HTML source order with that timeline-trigger-name value.
  3. If it can't find an element anywhere in the DOM with that timeline-trigger-name value, the animated element won't be scroll-triggered; having no associated timeline, the animation will not happen.

If multiple elements define triggers with the same trigger name, only the last one in the document tree will be used as the trigger for animated elements referencing that trigger name in their animation-trigger properties. This is likely not the desired behavior.

The trigger-scope property can solve this problem by limiting the scope of a trigger name to a subtree of the document. This means the trigger is visible only to elements within the same subtree and has no effect on elements outside the subtree. When trigger-scope is set on an element, and that element or its descendants are defined as triggers, animated elements are associated with those triggers only if they are within the same subtree.

Which trigger names are included in the scope depends on the trigger-scope value set:

  • trigger-scope: all means that all trigger names are included in the scope.
  • trigger-scope: --my-trigger, --another-trigger means that only triggers with names of --my-trigger and/or --another-trigger are included in the scope.
  • trigger-scope: none means that no trigger scoping is set on the element.

Formal definition

Initial valuenone
Applies toall elements
Inheritedno
Computed valueas specified
Animation typeNot animatable

Formal syntax

trigger-scope = 
none |
all |
<dashed-ident>#

Examples

Basic usage

This example demonstrates using the trigger-scope property to limit the scope of an animation-trigger-name.

HTML

We include three <section> elements, each containing two <div> elements: an .animated element and a .trigger element.

Most of the HTML, including a checkbox toggle that enables or disables the trigger-scope property, has been hidden for brevity.

html
<section id="one">
  <div class="animated"></div>
  ...
  <div class="trigger">Trigger for first animation</div>
  ...
</section>
<section id="two">
  <div class="animated"></div>
  ...
  <div class="trigger">Trigger for second animation</div>
  ...
</section>
<section id="three">
  <div class="animated"></div>
  ...
  <div class="trigger">Trigger for third animation</div>
  ...
</section>

CSS

We define three @keyframes animations. Each will be applied to a different .animated element.

css
@keyframes fade-in {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
  }
}

@keyframes color-cycle {
  from {
    background: red;
    scale: 1;
  }

  to {
    background: blue;
    scale: 2;
  }
}

@keyframes move-up-down {
  25% {
    translate: 0 -20px;
  }

  75% {
    translate: 0 20px;
  }
}

The animated elements' position is set to fixed, positioning them near the top of the scrollport to keep them visible at all times.

Each animated element has the same animation-trigger value: their animations are triggered by a trigger with a timeline-trigger-name of --t, and the animations will play when their trigger activates and then reset when their trigger deactivates.

css
.animated {
  position: fixed;
  top: 10px;
  animation-trigger: --t play reset;
}

Using the animation shorthand, each .animated element is given a different animation-name. They each also have a different left value so that they are not positioned on top of one another.

css
#one .animated {
  animation: fade-in 1s infinite alternate ease-in;
  left: 10px;
}

#two .animated {
  animation: color-cycle 1s infinite alternate linear;
  left: 110px;
}

#three .animated {
  animation: move-up-down 2s infinite linear;
  left: 210px;
}

The .trigger elements are set as triggers for the .animated elements by giving them a timeline-trigger-name value that references the same identifier, --t, and a timeline-trigger-source of view(). We set the timeline-trigger-activation-range to contain, so activation and deactivation occur while the trigger is still visible. We also set some rudimentary styles to make them stand out from the rest of the text.

css
.trigger {
  timeline-trigger-name: --t;
  timeline-trigger-source: view();
  timeline-trigger-activation-range: contain;

  padding: 10px;
  border: 2px solid black;
  background: black;
  color: white;
}

Finally, we set the trigger-scope on the <section> element to all. This limits the effect of each trigger named --t to their <section> ancestor.

css
section {
  trigger-scope: all;
}

Result

Scroll down the example. One square animates at a time. This is because each square animates only when the trigger element located in the same scope (the same <section>) is visible in the scrollport. Even though the three triggers share the same trigger name, each .animated element's animation is triggered by a different trigger.

Now check the checkbox to remove trigger-scope: all from the <section> elements. Scroll through the content again. None of the squares animate until the third .trigger is visible in the scrollport, at which point all of the squares start animating at the same time. Because scoping has been removed, each .animated element's animation is activated and deactivated by the last element with --t as a timeline-trigger-name.

Specifications

Specification
Animation Triggers
# propdef-trigger-scope

Browser compatibility

See also