博客加载优化之旅
追求网站速度
第一站:instant.page
最开始看到的是 instant.page。它的理念非常简单直接:在用户鼠标悬停在链接上超过 65 毫秒后,就开始预加载(prefetch)该链接的 HTML 内容。这样,当用户真正点击链接时,页面内容可能已经下载到本地缓存,从而实现“即时”加载。
集成它也非常简单,只需在 <body>
标签结束前加入一行代码:
<script src="//instant.page/5.2.0" type="module" integrity="sha384-jnZyxPjiipYXnSU0ygqeac2q7CVYMbh84q0uHVRRxEtvFPiQYbXWUorga2aqZJ0z"></script>
这个方案的局限性:在移动端,这种基于鼠标悬停的机制不生效。
第二站:quicklink
在搜索的过程中又发现了 Google Chrome Labs 的 quicklink。它比 instant.page 更智能,采用了不同的策略:
- 检测视口内的链接:只预加载出现在用户当前屏幕视口内的链接。
- 等待浏览器空闲:使用
requestIdleCallback
来确保预加载操作不会影响当前页面的渲染性能。 - 检测慢速网络:在用户的网络连接较慢(
navigator.connection.saveData === true
)或设置为“慢速2G”时,不会进行预加载。
这使得 quicklink 成为了一个在性能和资源消耗之间取得绝佳平衡的工具。在 Astro 项目中集成它也很方便:
-
安装 quicklink:
npm install quicklink
-
在你主Layout文件中引入并初始化:
import quicklink from 'quicklink'; // 在页面加载完成后初始化 window.addEventListener('load', () => { quicklink.listen(); });
目前站点:Astro View Transitions
Perplexity 推荐了 Astro 的最新功能:View Transitions API。这本是一个浏览器原生 API,Astro 对其进行了完美的封装,让开发者可以轻松地在 MPA 架构下实现 SPA 般的平滑页面过渡。
与前两者不同,View Transitions 关注的不是“预加载”,而是“过渡动画”。它通过捕捉两个页面状态的“快照”,并智能地计算出两者之间的差异,然后应用流畅的动画效果。
开启 View Transitions
在 Astro 中开启这个功能的方法如下:
-
导入
ViewTransitions
组件:在你的公共布局文件(例如src/layouts/Layout.astro
)的<head>
部分,导入并使用ViewTransitions
组件。--- import { ViewTransitions } from 'astro:transitions'; --- <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>My Astro Site</title> <ViewTransitions /> </head> <body> <slot /> </body> </html>
自定义过渡效果
Astro 的 View Transitions 还支持自定义。
-
内置动画:除了默认的
fade
,还可以使用slide
等内置动画。<ViewTransitions fallback="slide" />
-
持久化元素:通过
transition:name
指令标记在页面跳转时保持不变的元素(例如导航栏),让它们平滑地“移动”到新页面的对应位置,而不是重新渲染。<!-- src/components/Navbar.astro --> <nav transition:name="navbar" class="main-nav"> ... </nav>
-
自定义 CSS 动画:使用
::view-transition-old()
和::view-transition-new()
等 CSS 伪元素,完全自定义元素的进入和离开动画。::view-transition-old(root) { animation: fade-out 0.5s ease-out forwards; } ::view-transition-new(root) { animation: fade-in 0.5s ease-in forwards; } @keyframes fade-in { from { opacity: 0; } } @keyframes fade-out { to { opacity: 0; } }