perf: optimizing page transition (#178)

* perf: optimizing page transition

* fix: minor fixes
This commit is contained in:
saica.go 2024-09-13 20:14:03 +08:00 committed by GitHub
parent f5ad1c643d
commit f0754cae3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 149 additions and 78 deletions

View File

@ -4,14 +4,18 @@ import { profileConfig } from '../config'
import { url } from '../utils/url-utils'
---
<div class="card-base max-w-[var(--page-width)] min-h-[4.5rem] rounded-b-none mx-auto flex items-center px-6">
<!--<div class="border-t border-[var(&#45;&#45;primary)] mx-16 border-dashed py-8 max-w-[var(&#45;&#45;page-width)] flex flex-col items-center justify-center px-6">-->
<div class="transition border-t border-black/10 dark:border-white/15 my-10 border-dashed mx-32"></div>
<!--<div class="transition bg-[oklch(92%_0.01_var(&#45;&#45;hue))] dark:bg-black rounded-2xl py-8 mt-4 mb-8 flex flex-col items-center justify-center px-6">-->
<div class="transition border-dashed border-[oklch(85%_0.01_var(--hue))] dark:border-white/15 rounded-2xl mb-12 flex flex-col items-center justify-center px-6">
<div class="transition text-50 text-sm">
© 2024 {profileConfig.name}. All Rights Reserved. /
<a class="link text-[var(--primary)] font-medium" target="_blank" href={url('rss.xml')}>RSS</a> /
<a class="link text-[var(--primary)] font-medium" target="_blank" href={url('sitemap-index.xml')}>Sitemap</a>
<br>
<a class="transition link text-[var(--primary)] font-medium" target="_blank" href={url('rss.xml')}>RSS</a> /
<a class="transition link text-[var(--primary)] font-medium" target="_blank" href={url('sitemap-index.xml')}>Sitemap</a>
</div>
<div class="transition text-50 text-sm">
Powered by
<a class="link text-[var(--primary)] font-medium" target="_blank" href="https://astro.build">Astro</a> &
<a class="link text-[var(--primary)] font-medium" target="_blank" href="https://github.com/saicaca/fuwari">Fuwari</a>
<a class="transition link text-[var(--primary)] font-medium" target="_blank" href="https://astro.build">Astro</a> &
<a class="transition link text-[var(--primary)] font-medium" target="_blank" href="https://github.com/saicaca/fuwari">Fuwari</a>
</div>
</div>

View File

@ -307,8 +307,8 @@ color_set({
#content-wrapper {
animation-delay: var(--content-delay);
}
#footer {
animation-delay: 400ms;
.footer {
animation-delay: 250ms;
}
#banner-credit {
animation-delay: 400ms;

View File

@ -19,7 +19,7 @@ let links: NavBarLink[] = navBarConfig.links.map(
},
)
---
<div id="navbar" class="sticky top-0 z-50 onload-animation">
<div id="navbar" class="z-50 onload-animation">
<div class="absolute h-8 left-0 right-0 -top-8 bg-[var(--card-bg)] transition"></div> <!-- used for onload animation -->
<div class:list={[
className,

View File

@ -44,14 +44,4 @@ import { Icon } from 'astro-icon/components'
function backToTop() {
window.scroll({ top: 0, behavior: 'smooth' });
}
function scrollFunction() {
let btn = document.getElementById('back-to-top-btn');
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
btn.classList.remove('hide')
} else {
btn.classList.add('hide')
}
}
window.onscroll = scrollFunction
</script>

View File

@ -9,7 +9,7 @@ const className = Astro.props.class
<div class="flex flex-col w-full gap-4 mb-4">
<Profile></Profile>
</div>
<div class="flex flex-col w-full gap-4 top-4 sticky top-4">
<div id="sidebar-sticky" class="transition-all duration-700 flex flex-col w-full gap-4 top-4 sticky top-4">
<Categories class="onload-animation" style="animation-delay: 150ms"></Categories>
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
</div>

View File

@ -17,7 +17,7 @@ export const siteConfig: SiteConfig = {
banner: {
enable: false,
src: 'assets/images/demo-banner.png', // Relative to the /src directory. Relative to the /public directory if it starts with '/'
position: 'center', // Equivalent to object-position, defaults center
position: 'center', // Equivalent to object-position, only supports 'top', 'center', 'bottom'. 'center' by default
credit: {
enable: false, // Display the credit text of the banner image
text: '', // Credit text to be displayed

View File

@ -58,6 +58,14 @@ if (!lang) {
lang = `${siteConfig.lang}`
}
const siteLang = lang.replace('_', '-')
const bannerOffsetByPosition = {
'top': '30vh',
'center': '15vh',
'bottom': '0'
}
const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'center']
---
<!DOCTYPE html>
@ -117,17 +125,20 @@ const siteLang = lang.replace('_', '-')
<style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
</head>
<body class=" min-h-screen transition " class:list={[{"is-home": isHomePage, "enable-banner": enableBanner}]}>
<body class=" min-h-screen transition " class:list={[{"lg:is-home": isHomePage, "enable-banner": enableBanner}]}>
<ConfigCarrier></ConfigCarrier>
<GlobalStyles>
<div id="banner-wrapper" class="absolute w-full transition-all duration-700">
<ImageWrapper id="boxtest" alt="Banner image of the blog" class:list={["object-cover h-full", {"hidden": !siteConfig.banner.enable}]}
{siteConfig.banner.enable && <div id="banner-wrapper" class="absolute -top-[30vh] w-full transition duration-700 overflow-hidden">
<ImageWrapper id="banner" alt="Banner image of the blog" class:list={["object-cover h-full transition duration-700"]}
src={siteConfig.banner.src} position={siteConfig.banner.position}
>
</ImageWrapper>
</div>
</div>}
<slot />
</GlobalStyles>
<!-- increase the page height during page transition to prevent the scrolling animation from jumping -->
<div id="page-height-extend" class="hidden h-[300vh]"></div>
</body>
</html>
<style is:global>
@ -136,23 +147,35 @@ const siteLang = lang.replace('_', '-')
--page-width: 75rem;
}
</style>
<style is:global>
<style is:global define:vars={{ bannerOffset }}>
@tailwind components;
@tailwind utilities;
@layer components {
.enable-banner.is-home #banner-wrapper {
@apply h-[var(--banner-height)] md:h-[var(--banner-height-home)]
@apply h-[var(--banner-height-home)] translate-y-[30vh]
}
.enable-banner #banner-wrapper {
@apply h-[var(--banner-height)]
@apply h-[var(--banner-height-home)]
}
.enable-banner.is-home #top-row {
@apply h-[calc(var(--banner-height)_-_4.5rem)] md:h-[calc(var(--banner-height-home)_-_4.5rem)]
.enable-banner.is-home #banner {
@apply h-[var(--banner-height-home)] translate-y-0
}
.enable-banner #banner {
@apply h-[var(--banner-height-home)] translate-y-[var(--bannerOffset)]
}
.enable-banner.is-home #main-grid {
@apply translate-y-[30vh];
}
.enable-banner #top-row {
@apply h-[calc(var(--banner-height)_-_4.5rem)]
@apply h-[calc(var(--banner-height-home)_-_4.5rem)] transition-all duration-300
}
.enable-banner.is-home #sidebar-sticky {
@apply -top-[30vh]
}
.navbar-hidden {
@apply opacity-0 -translate-y-16
}
}
</style>
@ -300,18 +323,47 @@ const setup = () => {
// Remove the delay for the first time page load
window.swup.hooks.on('link:click', () => {
document.documentElement.style.setProperty('--content-delay', '0ms')
// prevent elements from overlapping the navbar
let threshold = window.innerHeight * 0.30 - 72 - 16
let navbar = document.getElementById('navbar-wrapper')
if (!navbar || !document.body.classList.contains('lg:is-home')) {
return
}
if (document.body.scrollTop >= threshold || document.documentElement.scrollTop >= threshold) {
navbar.classList.add('navbar-hidden')
}
})
window.swup.hooks.on('content:replace', initCustomScrollbar)
window.swup.hooks.on('visit:start', (visit: {to: {url: string}}) => {
// change banner height immediately when a link is clicked
const bodyElement = document.querySelector('body')
if (pathsEqual(visit.to.url, url('/'))) {
bodyElement!.classList.add('is-home');
bodyElement!.classList.add('lg:is-home');
} else {
bodyElement!.classList.remove('is-home');
bodyElement!.classList.remove('lg:is-home');
}
// increase the page height during page transition to prevent the scrolling animation from jumping
const heightExtend = document.getElementById('page-height-extend')
if (heightExtend) {
heightExtend.classList.remove('hidden')
}
});
window.swup.hooks.on('page:view', () => {
// hide the temp high element when the transition is done
const heightExtend = document.getElementById('page-height-extend')
if (heightExtend) {
heightExtend.classList.remove('hidden')
}
});
window.swup.hooks.on('visit:end', (visit: {to: {url: string}}) => {
// execute 1s later
const heightExtend = document.getElementById('page-height-extend')
if (heightExtend) {
heightExtend.classList.add('hidden')
}
});
}
if (window?.swup?.hooks) {
setup()
@ -319,6 +371,33 @@ if (window?.swup?.hooks) {
document.addEventListener('swup:enable', setup)
}
let backToTopBtn = document.getElementById('back-to-top-btn');
const bannerEnable = !!document.getElementById('banner-wrapper')
let navbar = document.getElementById('navbar-wrapper')
function scrollFunction() {
if (backToTopBtn) {
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
backToTopBtn.classList.remove('hide')
} else {
backToTopBtn.classList.add('hide')
}
}
if (!bannerEnable) return
if (navbar) {
let threshold = window.innerHeight * 0.30 - 72 - 16
if (document.body.classList.contains('lg:is-home') && window.innerWidth >= 1024) {
threshold = window.innerHeight * 0.60 - 72 - 16
}
if (document.body.scrollTop >= threshold || document.documentElement.scrollTop >= threshold) {
navbar.classList.add('navbar-hidden')
} else {
navbar.classList.remove('navbar-hidden')
}
}
}
window.onscroll = scrollFunction
</script>
<script>
@ -382,14 +461,3 @@ if (window.swup) {
document.addEventListener("swup:enable", setup)
}
</script>
<style is:global lang="stylus">
#banner-wrapper
top: 0
opacity: 1
.banner-closed
#banner-wrapper
top: -120px
opacity: 0
</style>

View File

@ -22,40 +22,49 @@ const hasBannerLink = !!siteConfig.banner.credit.url
<Layout title={title} banner={banner} description={description} lang={lang}>
<slot slot="head" name="head"></slot>
<div class="max-w-[var(--page-width)] min-h-screen grid grid-cols-[17.5rem_auto] grid-rows-[auto_auto_1fr_auto] lg:grid-rows-[auto_1fr_auto]
mx-auto gap-4 relative px-0 md:px-4"
>
<div id="top-row" class="relative transition-all duration-700 col-span-2 grid-rows-1" class:list={[""]}>
<div id="top-row" class="z-50 pointer-events-none relative transition-all duration-700 max-w-[var(--page-width)] px-0 md:px-4 mx-auto" class:list={[""]}>
<div id="navbar-wrapper" class="pointer-events-auto sticky top-0 transition-all">
<Navbar></Navbar>
</div>
</div>
<!-- Banner image credit -->
{hasBannerCredit && <a href={siteConfig.banner.credit.url} id="banner-credit" target="_blank" rel="noopener" aria-label="Visit image source"
class:list={["group onload-animation transition-all absolute flex justify-center items-center rounded-full " +
"px-3 right-0 bottom-0 bg-black/60 hover:bg-black/70 h-9", {"hover:pr-9 active:bg-black/80": hasBannerLink}]}
<div class="absolute w-full" class:list={[{"top-[30vh]": siteConfig.banner.enable, "top-[5.5rem]": !siteConfig.banner.enable}]}>
<div class="relative max-w-[var(--page-width)] mx-auto">
<div id="main-grid" class="transition duration-700 w-full left-0 right-0 grid grid-cols-[17.5rem_auto] grid-rows-[auto_1fr_auto] lg:grid-rows-[auto]
mx-auto gap-4 px-0 md:px-4"
>
<Icon class="text-white/75 text-[1.25rem] mr-1" name="material-symbols:copyright-outline-rounded" ></Icon>
<div class="text-white/75 text-xs">{siteConfig.banner.credit.text}</div>
<Icon class:list={["transition absolute text-[oklch(0.75_0.14_var(--hue))] right-4 text-[0.75rem] opacity-0",
{"group-hover:opacity-100": hasBannerLink}]}
name="fa6-solid:arrow-up-right-from-square">
</Icon>
</a>}
<!-- Banner image credit -->
{hasBannerCredit && <a href={siteConfig.banner.credit.url} id="banner-credit" target="_blank" rel="noopener" aria-label="Visit image source"
class:list={["group onload-animation transition-all absolute flex justify-center items-center rounded-full " +
"px-3 right-4 -top-[3.25rem] bg-black/60 hover:bg-black/70 h-9", {"hover:pr-9 active:bg-black/80": hasBannerLink}]}
>
<Icon class="text-white/75 text-[1.25rem] mr-1" name="material-symbols:copyright-outline-rounded" ></Icon>
<div class="text-white/75 text-xs">{siteConfig.banner.credit.text}</div>
<Icon class:list={["transition absolute text-[oklch(0.75_0.14_var(--hue))] right-4 text-[0.75rem] opacity-0",
{"group-hover:opacity-100": hasBannerLink}]}
name="fa6-solid:arrow-up-right-from-square">
</Icon>
</a>}
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation"></SideBar>
<main id="swup-container" class="transition-swup-fade col-span-2 lg:col-span-1 overflow-hidden">
<div id="content-wrapper" class="onload-animation">
<!-- the overflow-hidden here prevent long text break the layout-->
<!-- make id different from windows.swup global property -->
<slot></slot>
<div class="footer col-span-2 onload-animation hidden lg:block">
<Footer></Footer>
</div>
</div>
</main>
<div class="footer col-span-2 onload-animation block lg:hidden">
<Footer></Footer>
</div>
</div>
<BackToTop></BackToTop>
</div>
<SideBar class="row-start-3 row-end-4 col-span-2 lg:row-start-2 lg:row-end-3 lg:col-span-1 lg:max-w-[17.5rem] onload-animation"></SideBar>
<div id="content-wrapper" class="row-start-2 row-end-3 col-span-2 lg:col-span-1 overflow-hidden onload-animation">
<!-- the overflow-hidden here prevent long text break the layout-->
<!-- make id different from windows.swup global property -->
<main id="swup-container" class="transition-swup-fade">
<slot></slot>
</main>
</div>
<div id="footer" class="grid-rows-3 col-span-2 mt-4 onload-animation">
<Footer></Footer>
</div>
<BackToTop></BackToTop>
</div>
</Layout>

View File

@ -13,7 +13,7 @@ export type SiteConfig = {
banner: {
enable: boolean
src: string
position?: string
position?: 'top' | 'center' | 'bottom'
credit: {
enable: boolean
text: string