Skip to content

Add CSS Text Transitions and Animations explainer#1281

Open
kbabbitt wants to merge 6 commits intoMicrosoftEdge:mainfrom
kbabbitt:user/kbabbitt/text-transitions
Open

Add CSS Text Transitions and Animations explainer#1281
kbabbitt wants to merge 6 commits intoMicrosoftEdge:mainfrom
kbabbitt:user/kbabbitt/text-transitions

Conversation

@kbabbitt
Copy link
Member

No description provided.

algorithm) is treated as a unit.
- `line`: Each line box is treated as a unit.

**`*-text-interval`** specifies the time offset between successive text units

Choose a reason for hiding this comment

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

I found this part difficult to understand, can this be explained more simply as - text-interval specifies the time duration each text-unit (a character, word or line) animates for. The next text unit will start its animation once the preceding unit in document order completes its animation.

Copy link
Contributor

Choose a reason for hiding this comment

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

If I'm understanding it correctly, this isn't intended to be a duration, just a delta between start times.

What about changing the 'time offset' to 'delay', and expanding the example a little to include an animation duration so the difference is more clear?

*`*-text-interval`** specifies the delay between successive text units
beginning their transition or animation. For example, if the `transition-text-interval`
 is `6ms`, the `transition-text-unit` is `word`, and the `transition-duration` is `100ms`,
the first word start immediately, the second word starts at 6 ms, the third at 12 ms,
and so on. The first word subsequently finishes at 100ms, the second word at 106ms,
and so on.

Comment on lines +183 to +184

Authors could animate "..." dots bouncing up and down in sequence:
Copy link

@sushraja-msft sushraja-msft Mar 18, 2026

Choose a reason for hiding this comment

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

Just an observation - can be part of open questions.

After dots developers may want to animation inline blocks - like they would want to stick image elements, point it to an svg that has their fancy "." which may be an arrow for example.

Perhaps your proposal is addressing two things
a. inability to target sub element units in animations/transitions.
b. inability to declaratively schedule animation among sibling units/elements, such that the next one starts after the previous finishes.

For your current explainer - To limit the scope of this feature call out that inline blocks and out of flow elements , blocks in between anonymous text blocks will simply be skipped.

If anonymous text blocks is no longer a common term, I mean this sort of construct:

<div class="text-animate">
  Hello
  <div> this splits up the text block into two anonymous text blocks </div>
  World !
</div>

Copy link
Contributor

@mhochk mhochk left a comment

Choose a reason for hiding this comment

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

Don't forget to update the main landing page to have an entry for this as well

algorithm) is treated as a unit.
- `line`: Each line box is treated as a unit.

**`*-text-interval`** specifies the time offset between successive text units
Copy link
Contributor

Choose a reason for hiding this comment

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

If I'm understanding it correctly, this isn't intended to be a duration, just a delta between start times.

What about changing the 'time offset' to 'delay', and expanding the example a little to include an animation duration so the difference is more clear?

*`*-text-interval`** specifies the delay between successive text units
beginning their transition or animation. For example, if the `transition-text-interval`
 is `6ms`, the `transition-text-unit` is `word`, and the `transition-duration` is `100ms`,
the first word start immediately, the second word starts at 6 ms, the third at 12 ms,
and so on. The first word subsequently finishes at 100ms, the second word at 106ms,
and so on.

Shorthands are also provided to set each pair of properties together:

```css
transition-text: word 60ms;
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor minor suggestion (so feel free to ignore without even justifying why) - consider putting the -unit second, as it's conceptually more-optional. Since the -interval defaults to 0, you would expect it to (almost) always be getting set, whereas the -unit portion defaults to hopefully the common value, so might get left out. Establishing a pattern of putting the -unit second encourages the consistent pattern of the shorthand always starting with the -interval and then sometimes having the -unit, rather than having an inconsistent starting piece.

Comment on lines +279 to +281
When text content is appended to an element that has already animated (e.g., in
a streaming response scenario), the newly added text picks up where the previous
text would leave off.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
When text content is appended to an element that has already animated (e.g., in
a streaming response scenario), the newly added text picks up where the previous
text would leave off.
When text content is appended to an element that has already started animating
(e.g., in a streaming response scenario), the newly added text picks up where the
previous text would leave off.


![Loading shimmer animation](images/loading-shimmer.gif)

### Details and open questions
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding a callout for how this will impact animationend events and the like. Based on the general direction it sounds like the animationend event should fire on the parent once all the text animations are complete, which is only a tiny change from the existing behavior in that it will be later.
e.g. In Scenario 1 above, if we had

<p class="fade-in-text">my three words</p>

the animationend event would fire on the paragraph element after 612 ms, whereas if this new feature was not supported it would fire after 600 ms.


![Loading shimmer animation](images/loading-shimmer.gif)

### Details and open questions
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to Sushant's comment above, can we get a Scenario or open question for mixed content behavior?

<div class="fade-in-text">
  <span>first three words</span>
  <img src="foobar.jpg"/>
  <span>ending</span>
</div>

My current read of the proposal is that we would get something akin to
'first' - starts at 0ms
'three' - starts at 6ms
'words' - starts at 12ms
'foobar' - starts at 0ms
'ending' - starts at 18ms

Whereas I think the intuitive desired behavior would be for the img to participate in the same cascade. Potentially this could be mitigated by expanding the behavior to be "-unit of text OR element"? Or possibly expanding from -text-unit to -child-unit?
Very roughly:
-child-unit = none/auto/normal; applied only directly to the specified element (the existing behavior, and the default)
-child-unit = leaf/child; applied to children elements in depth-first order

<div class="fade-in-text">
  <div>Starts at 0ms</div>
  <div>
    <div>Starts at 6ms</div>
    <div>Starts at 12ms</div>
  </div>
  <div>Starts at 18ms</div>
</div>

-child-unit = word treating each "word" of text in all descendants akin to a span, then following the rules of child
etc.


![Loading shimmer animation](images/loading-shimmer.gif)

### Details and open questions
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the principles you called out above of the final state matching as if this feature didn't exist, and the intermediate state behaving similar to as if each 'unit' was a span that was being impacted directly instead. For completeness (and clarification), can we get an example where the 2 are slightly in opposition? As an example, I'm thinking about if I apply a scale transition.

<style>
#item {
  transition: 0.5s ease-in-out;
  transition-child-interval: 0.5s;
}
#item:hover {
  scale: 200%;
}
</style>
<div id="item">
  my text here
</div>

If each word was its own span, they would scale in place and overlap one another. If the parent container was instead scaled they would all grow larger, never overlapping. My (greedy, naive) web dev hat would want the best of both worlds with 'my' scaling while 'text here' moved to the right, then 'text' scaling while 'here' moved to the right, and finally 'here' scaling. I expect this ask is too much, but it would be good to make it clear one way or another.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants