fix: resolve gsap animation flash on page load

- Add initial state styles for animated elements in CSS
- Change GSAP animations from .from() to .to() method
- Move reduce-motion class from JS to server-side HTML
- Improve performance by eliminating DOM flash
- Enhance code readability with better formatting
This commit is contained in:
radishzzz 2025-05-26 11:12:47 +01:00
parent ead71483ec
commit c1996585a8
5 changed files with 68 additions and 43 deletions

View file

@ -9,8 +9,10 @@ interface Props {
supportedLangs: string[]
}
const { light: { background: lightMode }, dark: { background: darkMode } } = themeConfig.color
const reduceMotion = themeConfig.global.reduceMotion
const {
light: { background: lightMode },
dark: { background: darkMode },
} = themeConfig.color
const { supportedLangs } = Astro.props
const currentPath = Astro.url.pathname
@ -63,7 +65,7 @@ const nextUrl = useSupportedLangs
<!-- Theme Toggle Script >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<script
is:inline
define:vars={{ lightMode, darkMode, reduceMotion }}
define:vars={{ lightMode, darkMode }}
>
// Update theme
function updateTheme() {
@ -85,18 +87,13 @@ function updateTheme() {
// Bind click event to the button
function setupThemeToggle() {
// Add reduce-motion class if enabled in config
if (reduceMotion) {
document.documentElement.classList.add('reduce-motion')
}
// Locate theme toggle button
const themeToggleButton = document.getElementById('theme-toggle-button')
// Add click listener to the button
if (themeToggleButton) {
themeToggleButton.addEventListener('click', () => {
// If reduceMotion is enabled or browser doesn't support View Transitions API, update theme directly
if (reduceMotion || !document.startViewTransition) {
if (document.documentElement.classList.contains('reduce-motion') || !document.startViewTransition) {
updateTheme()
return
}

View file

@ -24,9 +24,9 @@ function setupPostPageAnimation() {
if (isLargeScreen) {
// Post Content + Tags + Comments
// First 15 elements
gsap.from(allElements.slice(0, 15), {
opacity: 0,
y: '3rem',
gsap.to(allElements.slice(0, 15), {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -34,9 +34,9 @@ function setupPostPageAnimation() {
})
// Rest elements as the 16th element
if (allElements.length > 15) {
gsap.from(allElements.slice(15), {
opacity: 0,
y: '3rem',
gsap.to(allElements.slice(15), {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2 + 0.05 * 15,
ease: 'power2.out',
@ -45,9 +45,9 @@ function setupPostPageAnimation() {
// Post Date
if (dateElement) {
gsap.from(dateElement, {
opacity: 0,
y: '1.5rem',
gsap.to(dateElement, {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -56,9 +56,9 @@ function setupPostPageAnimation() {
// TOC Icon
if (tocIcon) {
gsap.from(tocIcon, {
opacity: 0,
y: '0.5rem',
gsap.to(tocIcon, {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -67,9 +67,9 @@ function setupPostPageAnimation() {
// Toc List
if (tocListChildren.length > 0) {
gsap.from(tocListChildren, {
opacity: 0,
y: '1.5rem',
gsap.to(tocListChildren, {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -79,9 +79,9 @@ function setupPostPageAnimation() {
// Back Button
if (backButton) {
gsap.from(backButton, {
opacity: 0,
x: '0.5rem',
gsap.to(backButton, {
opacity: 1,
x: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -91,9 +91,9 @@ function setupPostPageAnimation() {
else {
// Post Content + Tags + Comments
// First 7 elements
gsap.from(allElements.slice(0, 7), {
opacity: 0,
y: '3rem',
gsap.to(allElements.slice(0, 7), {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.2,
ease: 'power2.out',
@ -113,9 +113,9 @@ function setupPostPageAnimation() {
// Mobile Animation (for screens smaller than 1536px)
if (isSmallScreen && tocContainer) {
gsap.from(tocContainer, {
opacity: 0,
y: '3rem',
gsap.to(tocContainer, {
opacity: 1,
y: 0,
duration: 0.5,
delay: 0.15,
ease: 'power2.out',

View file

@ -33,7 +33,11 @@ const MarginBottom = isPost && themeConfig.comment?.enabled
<html
lang={Astro.currentLocale}
class:list={[fontStyle, { 'scroll-smooth': isPost }]}
class:list={[
fontStyle,
{ 'scroll-smooth': isPost },
{ 'reduce-motion': themeConfig.global.reduceMotion },
]}
>
<Head {postTitle} {postDescription} {postSlug} />
<body>

View file

@ -34,4 +34,28 @@ html[data-theme-changing] [data-disable-theme-transition] {
}
html.reduce-motion {
--at-apply: 'transition-colors duration-300 ease-out';
}
}
/* GSAP Animation Elements Initial States */
html:not(.reduce-motion) #gsap-post-page-content > *,
html:not(.reduce-motion) #gsap-post-page-tags,
html:not(.reduce-motion) #waline {
opacity: 0;
transform: translateY(3rem);
}
html:not(.reduce-motion) #gsap-post-page-date {
opacity: 0;
transform: translateY(1.5rem);
}
html:not(.reduce-motion) #back-button {
opacity: 0;
transform: translateX(0.5rem);
}
html:not(.reduce-motion) #toc-icon {
opacity: 0;
transform: translateY(0.5rem);
}
html:not(.reduce-motion) #toc-list > * {
opacity: 0;
transform: translateY(1.5rem);
}