withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!

Home Page:https://astro.build

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Optimalization: ViewTransition CSS should be after after `<body>`

Akxe opened this issue · comments

Astro Info

Astro                    v4.11.1
Node                     v20.14.0
System                   Windows (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             @astrojs/sitemap

If this issue only occurs in one browser, which browser is a problem?

All

Describe the Bug

The first 4578 lines of code are <head> (mostly CSS). 4573 lines (309525 characters) of that is only Astro transition CSS. Every one of these CSS declarations are the same:

[data-astro-transition-fallback="old"] [data-astro-transition-scope="astro-jnro4gcx-127"],
[data-astro-transition-fallback="old"][data-astro-transition-scope="astro-jnro4gcx-127"] { 
	animation-duration: 180ms;
	animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
	animation-fill-mode: both;
	animation-name: astroFadeOut;
}

[data-astro-transition-fallback="new"] [data-astro-transition-scope="astro-jnro4gcx-127"],
[data-astro-transition-fallback="new"][data-astro-transition-scope="astro-jnro4gcx-127"] { 
	animation-duration: 180ms;
	animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
	animation-fill-mode: both;
	animation-name: astroFadeIn;
}

[data-astro-transition=back][data-astro-transition-fallback="old"] [data-astro-transition-scope="astro-jnro4gcx-127"],
[data-astro-transition=back][data-astro-transition-fallback="old"][data-astro-transition-scope="astro-jnro4gcx-127"] { 
	animation-duration: 180ms;
	animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
	animation-fill-mode: both;
	animation-name: astroFadeOut;
}
[data-astro-transition=back][data-astro-transition-fallback="new"] [data-astro-transition-scope="astro-jnro4gcx-127"],
[data-astro-transition=back][data-astro-transition-fallback="new"][data-astro-transition-scope="astro-jnro4gcx-127"] { 
	animation-duration: 180ms;
	animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
	animation-fill-mode: both;
	animation-name: astroFadeIn;
}

What's the expected result?

My suggestion:
Move view transition CSS to the end of <body> for earlier HTML parsing

Additional suggestion:
Since every view transition is common to at least 2 pages, wouldn't it be better to reference them as file(s)?

Link to Minimal Reproducible Example

https://gingerarchitecture.cz/

Participation

  • I am willing to submit a pull request for this issue.

Hi @Akxe, yes this is a lot of CSS. Instead of moving it elsewhere, I assume it would be better to get rid of it. How did you generate it? It looks as if you defined ~150 transition:animate on the start page. Could you please share the code of the project so we can see how this can be avoided?

You are also welcome to open a thread for this in the #support channel on our Discord server (https://astro.build/chat).

Hello @Akxe. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with needs repro will be closed if they have no activity within 3 days.

Here is minimal reproduction: https://stackblitz.com/edit/github-drxqny

I had problems running the transition because of some "reduced-motion" settings that is inherited from stackblitz, but the code is generated non the less...

PS: This example contains "only" 700 lines for transition, because there is not so much of animated parts. In my project, due to word wrapping" I had to animate every single word inside h3, thus creating many more animated components. See https://gingerarchitecture.cz/ for my actual project.

PPS: If needs be, I can add anyone on the team to the github for the actual project at hand.

Hi @Akxe, thank you for the reproduction!

Your example is straight forward and the reason for the huge number of entries on the blog list page might not be directly obvious as you only set transition:name directives.

But under the hood, Astro adds an transition:animate="fade" directive if no transition:animate directive is defined with a transition:name. In your special case, you only need the transition names for the morph effect. You do not need the transition:* directives and should just define the names with pure CSS. You need only do this on the page that has all the images.

Instead of transition:name="xyz" use style="view-transition-name: xyz", e.g.

<a href={`/blog/${post.slug}/`}>
  <img width={720} height={360} src={post.data.heroImage} alt="" 
    style={"view-transition-name: " + post.slug + 'image'} />
  <h4 class="title" 
    style={"view-transition-name: " + post.slug + 'title'}>{post.data.title}</h4>
  <p class="date" 
    style={"view-transition-name: "+post.slug + 'date'}>
    <FormattedDate date={post.data.pubDate} />
  </p>
</a>

You should try this for the blog/index.astro page as this page has entries for all content collection entries. The [...slug].astro pages only have the CSS for a single content collection entry. You might leave them as they are or apply the same change there, too.

@martrapp I don't feel like this is what people expect. This is not specified in the View transition documentation page at all.

Also:

  • I want the elements to fade/morph from one place and/or size to another.
  • Will the animation work in reverse? (From blog post to blog listing)

One of 2 needs to be done before this issue can be actually closed:

  • Update documentation to reflect this and possibly provide an explanation.
  • Update transition:name to
    • Only add style="view-transition-name: xyz" when using the default animation
    • Consice generated code using classes or similar
    • Other solution?

Also:

I want the elements to fade/morph from one place and/or size to another.
Will the animation work in reverse? (From blog post to blog listing)

Have you give it a try?

No my CPU fan broke so I have fun for a day... But at least the docs should be updated to reflect that...

Oh, broken computer hurts! 😞
I'm sure the approach would give you the effects you want without the cluttering of the <head>. If not, be welcome to drop me another note here.
The approach is not Astro specific. You can find the relevant documentation here: https://drafts.csswg.org/css-view-transitions-1/.

It does work. My HTML is down to 700 lines in total 😊

Why does transition:name does what it does? What is its purpose? I was at the creation of this API and I still do not know what this API seems to do

Hi @Akxe,

Astro introduced transition:animate to support the generation of the necessary CSS for entry and exit animations in a way that works on browsers with native view transition support as well as those without (using Astro's simulation of cross-document view transitions).

transition:animate defines the CSS for the exit/entry animations and also defines the required view-transition-name, which is auto generated. To override the generated name, you can use transition:name, which also works for the default animation that is used if no transition:animate directive was defined.

The third kind of animation that the native view transition API supports is the morph animation that you use in you app. Those are not supported by Astro's simulation and only work on browsers with native support.

Other than for the entry and exit animations, Astro does not offer special support for morph animations. You use standard CSS to control these. For example, you can use Astro to define the speed of a fade in/out animation, but if you want to change the speed of the morph animation, just use standard CSS:

::view-transition-group(*) {
  animation-duration: 5s;
}

Astro never aims to hide standard browser APIs. In fact, we encourage people to understand and use the standards. In this regard, directly setting the "view-transition-name" (if you don't need the generated CSS for the entry/exit animations) is similar to setting the animation duration in the example above.

Astro Docs can never describe all details of HTML, JavaScript/Typescript, CSS and the Web standards. ;-) There are lots of articles and tutorials out there that add further information. If you are interested in more details about Astro's view transitions and the View Transition API in general, you might find additional information here: https://events-3bg.pages.dev/jotter/astro/

Thank you for the lengthy explanation. I really do appreciate it. I now understand what the API does and what does the transition:name itself.

I do still, however, have concerns. I would love to know how many people got the idea wrong and used <ViewTransitions / with transition:name when they should not have.

The thing is that for view transitions to work at all, you need the <ViewTransitions /. Therefore, you are on the docs page for it, and you go from there. There is a lot of text around it. But an information that simply adding style="view-transition-name: XYZ" is enough, is nowhere to be found, and therefore; not many people will figure this out.

PS: Shouldn't the animation use classes to cluster all the definitions of the same animation?

view transition classes are a rather new concept introduced with level 2. Using them would indeed allow us to reduce the code for browsers that support them. But we would still need the CSS without classes for browsers that do not yet support them. For this improvement and for improving the docs: PRs that really make things better are always welcome!

@martrapp Here is my proposal text... but the more I look at it the more it seems that transition:name without any other transition:* directives should just be an alias to style="view-transition-name: name"

Proposed text (to be inserted here into view-transition page)

:::note[Known limitations]
Unless using `transition:animate` or `transition:persist` using `transition:name` will generate unnecessary code for every transition on a page. Prefer using `style="view-transition-name: name"`
:::

Hi @Akxe, yes, when I first noticed that behavior I was also a bit irritated. But I never thought about proposing an incompatible change that might break some existing sites.

I wonder if Docs would accept your proposal when you make that PR to the docs repository. It sounds a bit harsh: Other users might really rely on the CSS that you feel is useless. Also using view-transition-name directly might not be the preferred solution as it puts the burden of escaping characters other than [A-Za-z-_] on the user.

What would it break? When I made the switch in my app, nothing changed...

The proposed text is harsh, but other than the prevention of escaping the name.

Writing good docs is hard. I'm not good at that. Try your luck with the Docs team ;-)

Example where not generating the CSS for the implicit transition:animate would change an existing site: Have a slide animation on :root, add transition:name to some other elements. Not generating the CSS will change their fade animation, especially for the simulation on browsers without native view transitions.

My bad, the effect is so subtle, i did not see it in FF the first time... sure I will try to come up with something "smart"