perf: optimizing page transition (#178)
* perf: optimizing page transition * fix: minor fixes
This commit is contained in:
parent
f5ad1c643d
commit
f0754cae3f
|
@ -4,14 +4,18 @@ import { profileConfig } from '../config'
|
||||||
import { url } from '../utils/url-utils'
|
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(--primary)] mx-16 border-dashed py-8 max-w-[var(--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(--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">
|
<div class="transition text-50 text-sm">
|
||||||
© 2024 {profileConfig.name}. All Rights Reserved. /
|
© 2024 {profileConfig.name}. All Rights Reserved. /
|
||||||
<a class="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('rss.xml')}>RSS</a> /
|
||||||
<a class="link text-[var(--primary)] font-medium" target="_blank" href={url('sitemap-index.xml')}>Sitemap</a>
|
<a class="transition link text-[var(--primary)] font-medium" target="_blank" href={url('sitemap-index.xml')}>Sitemap</a>
|
||||||
<br>
|
</div>
|
||||||
|
<div class="transition text-50 text-sm">
|
||||||
Powered by
|
Powered by
|
||||||
<a class="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://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://github.com/saicaca/fuwari">Fuwari</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -307,8 +307,8 @@ color_set({
|
||||||
#content-wrapper {
|
#content-wrapper {
|
||||||
animation-delay: var(--content-delay);
|
animation-delay: var(--content-delay);
|
||||||
}
|
}
|
||||||
#footer {
|
.footer {
|
||||||
animation-delay: 400ms;
|
animation-delay: 250ms;
|
||||||
}
|
}
|
||||||
#banner-credit {
|
#banner-credit {
|
||||||
animation-delay: 400ms;
|
animation-delay: 400ms;
|
||||||
|
|
|
@ -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="absolute h-8 left-0 right-0 -top-8 bg-[var(--card-bg)] transition"></div> <!-- used for onload animation -->
|
||||||
<div class:list={[
|
<div class:list={[
|
||||||
className,
|
className,
|
||||||
|
|
|
@ -44,14 +44,4 @@ import { Icon } from 'astro-icon/components'
|
||||||
function backToTop() {
|
function backToTop() {
|
||||||
window.scroll({ top: 0, behavior: 'smooth' });
|
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>
|
</script>
|
||||||
|
|
|
@ -9,7 +9,7 @@ const className = Astro.props.class
|
||||||
<div class="flex flex-col w-full gap-4 mb-4">
|
<div class="flex flex-col w-full gap-4 mb-4">
|
||||||
<Profile></Profile>
|
<Profile></Profile>
|
||||||
</div>
|
</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>
|
<Categories class="onload-animation" style="animation-delay: 150ms"></Categories>
|
||||||
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
|
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const siteConfig: SiteConfig = {
|
||||||
banner: {
|
banner: {
|
||||||
enable: false,
|
enable: false,
|
||||||
src: 'assets/images/demo-banner.png', // Relative to the /src directory. Relative to the /public directory if it starts with '/'
|
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: {
|
credit: {
|
||||||
enable: false, // Display the credit text of the banner image
|
enable: false, // Display the credit text of the banner image
|
||||||
text: '', // Credit text to be displayed
|
text: '', // Credit text to be displayed
|
||||||
|
|
|
@ -58,6 +58,14 @@ if (!lang) {
|
||||||
lang = `${siteConfig.lang}`
|
lang = `${siteConfig.lang}`
|
||||||
}
|
}
|
||||||
const siteLang = lang.replace('_', '-')
|
const siteLang = lang.replace('_', '-')
|
||||||
|
|
||||||
|
const bannerOffsetByPosition = {
|
||||||
|
'top': '30vh',
|
||||||
|
'center': '15vh',
|
||||||
|
'bottom': '0'
|
||||||
|
}
|
||||||
|
const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'center']
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!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 -->
|
<style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
|
||||||
|
|
||||||
</head>
|
</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>
|
<ConfigCarrier></ConfigCarrier>
|
||||||
<GlobalStyles>
|
<GlobalStyles>
|
||||||
<div id="banner-wrapper" class="absolute w-full transition-all duration-700">
|
{siteConfig.banner.enable && <div id="banner-wrapper" class="absolute -top-[30vh] w-full transition duration-700 overflow-hidden">
|
||||||
<ImageWrapper id="boxtest" alt="Banner image of the blog" class:list={["object-cover h-full", {"hidden": !siteConfig.banner.enable}]}
|
<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}
|
src={siteConfig.banner.src} position={siteConfig.banner.position}
|
||||||
>
|
>
|
||||||
</ImageWrapper>
|
</ImageWrapper>
|
||||||
</div>
|
</div>}
|
||||||
<slot />
|
<slot />
|
||||||
</GlobalStyles>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<style is:global>
|
<style is:global>
|
||||||
|
@ -136,23 +147,35 @@ const siteLang = lang.replace('_', '-')
|
||||||
--page-width: 75rem;
|
--page-width: 75rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style is:global>
|
<style is:global define:vars={{ bannerOffset }}>
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.enable-banner.is-home #banner-wrapper {
|
.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 {
|
.enable-banner #banner-wrapper {
|
||||||
@apply h-[var(--banner-height)]
|
@apply h-[var(--banner-height-home)]
|
||||||
}
|
}
|
||||||
|
|
||||||
.enable-banner.is-home #top-row {
|
.enable-banner.is-home #banner {
|
||||||
@apply h-[calc(var(--banner-height)_-_4.5rem)] md:h-[calc(var(--banner-height-home)_-_4.5rem)]
|
@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 {
|
.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>
|
</style>
|
||||||
|
@ -300,18 +323,47 @@ const setup = () => {
|
||||||
// Remove the delay for the first time page load
|
// Remove the delay for the first time page load
|
||||||
window.swup.hooks.on('link:click', () => {
|
window.swup.hooks.on('link:click', () => {
|
||||||
document.documentElement.style.setProperty('--content-delay', '0ms')
|
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('content:replace', initCustomScrollbar)
|
||||||
window.swup.hooks.on('visit:start', (visit: {to: {url: string}}) => {
|
window.swup.hooks.on('visit:start', (visit: {to: {url: string}}) => {
|
||||||
// change banner height immediately when a link is clicked
|
// change banner height immediately when a link is clicked
|
||||||
const bodyElement = document.querySelector('body')
|
const bodyElement = document.querySelector('body')
|
||||||
if (pathsEqual(visit.to.url, url('/'))) {
|
if (pathsEqual(visit.to.url, url('/'))) {
|
||||||
bodyElement!.classList.add('is-home');
|
bodyElement!.classList.add('lg:is-home');
|
||||||
} else {
|
} 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) {
|
if (window?.swup?.hooks) {
|
||||||
setup()
|
setup()
|
||||||
|
@ -319,6 +371,33 @@ if (window?.swup?.hooks) {
|
||||||
document.addEventListener('swup:enable', setup)
|
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>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -382,14 +461,3 @@ if (window.swup) {
|
||||||
document.addEventListener("swup:enable", setup)
|
document.addEventListener("swup:enable", setup)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style is:global lang="stylus">
|
|
||||||
#banner-wrapper
|
|
||||||
top: 0
|
|
||||||
opacity: 1
|
|
||||||
.banner-closed
|
|
||||||
#banner-wrapper
|
|
||||||
top: -120px
|
|
||||||
opacity: 0
|
|
||||||
</style>
|
|
|
@ -22,16 +22,21 @@ const hasBannerLink = !!siteConfig.banner.credit.url
|
||||||
|
|
||||||
<Layout title={title} banner={banner} description={description} lang={lang}>
|
<Layout title={title} banner={banner} description={description} lang={lang}>
|
||||||
<slot slot="head" name="head"></slot>
|
<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]
|
<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={[""]}>
|
||||||
mx-auto gap-4 relative px-0 md:px-4"
|
<div id="navbar-wrapper" class="pointer-events-auto sticky top-0 transition-all">
|
||||||
>
|
|
||||||
<div id="top-row" class="relative transition-all duration-700 col-span-2 grid-rows-1" class:list={[""]}>
|
|
||||||
<Navbar></Navbar>
|
<Navbar></Navbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
>
|
||||||
<!-- Banner image credit -->
|
<!-- Banner image credit -->
|
||||||
{hasBannerCredit && <a href={siteConfig.banner.credit.url} id="banner-credit" target="_blank" rel="noopener" aria-label="Visit image source"
|
{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 " +
|
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}]}
|
"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>
|
<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>
|
<div class="text-white/75 text-xs">{siteConfig.banner.credit.text}</div>
|
||||||
|
@ -41,21 +46,25 @@ const hasBannerLink = !!siteConfig.banner.credit.url
|
||||||
</Icon>
|
</Icon>
|
||||||
</a>}
|
</a>}
|
||||||
|
|
||||||
</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">
|
<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-->
|
<!-- the overflow-hidden here prevent long text break the layout-->
|
||||||
<!-- make id different from windows.swup global property -->
|
<!-- make id different from windows.swup global property -->
|
||||||
<main id="swup-container" class="transition-swup-fade">
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
<div class="footer col-span-2 onload-animation hidden lg:block">
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="footer" class="grid-rows-3 col-span-2 mt-4 onload-animation">
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div class="footer col-span-2 onload-animation block lg:hidden">
|
||||||
|
<Footer></Footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<BackToTop></BackToTop>
|
<BackToTop></BackToTop>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -13,7 +13,7 @@ export type SiteConfig = {
|
||||||
banner: {
|
banner: {
|
||||||
enable: boolean
|
enable: boolean
|
||||||
src: string
|
src: string
|
||||||
position?: string
|
position?: 'top' | 'center' | 'bottom'
|
||||||
credit: {
|
credit: {
|
||||||
enable: boolean
|
enable: boolean
|
||||||
text: string
|
text: string
|
||||||
|
|
Loading…
Reference in New Issue