通过 react 的 `
在客户端渲染(CSR)的 React 应用中,浏览器默认按 HTML 解析顺序逐步加载 CSS、字体和图片,导致未样式化文本(FOUT)、不可见文本(FOIT)或占位图闪烁等问题。单纯依赖
✅ 1. 关键字体:使用 + font-display: optional
在 public/index.html 的
中预加载核心字体,并禁用不可见文本回退:⚠️ 注意:font-display: optional 要求浏览器在 100ms 内完成加载,否则跳过渲染字体——这正符合“全就绪再显示”的前提。
✅ 2. 关键图片:用 loading="eager" + 自定义 ImageLoader 拦截
避免 的默认行为。创建一个可 Suspense 的
组件:// components/PreloadedImage.tsx import { useState, useEffect, Suspense } from 'react'; interface PreloadedImageProps extends Omit, 'src'> { src: string; } export function PreloadedImage({ src, ...props }: PreloadedImageProps) { const [isLoaded, setIsLoaded] = useState(false); const [error, setError] = useState(false); useEffect(() => { const img = new Image(); img.src = src; img.onload = () => setIsLoaded(true); img.onerror = () => setError(true); }, [src]); if (!isLoaded && !error) { throw Promise.resolve(); // 触发 Suspense fallback } return @@##@@; } 在路由入口处包裹
: // App.tsx import { Suspense } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; function App() { return (); } // 在 HomePage 中使用预加载图片 function HomePage() { return ( } /> ); } Welcome
{/* 同理可封装 SVG/图标组件 */} ✅ 3. 全局资源检查(进阶):用 document.fonts.load() + Promise.all
若需更精确控制(例如等待多个字体族),可在 index.tsx 初始化时校验:
// index.tsx async function waitForCriticalAssets() { const fontPromises = [ document.fonts.load('16px Inter'), document.fonts.load('bold 16px Inter'), ]; const imagePromises = Array.from( document.querySelectorAll('img[data-preload]') ).map((img) => { return new Promise((resolve) => { if ((img as HTMLImageElement).complete) resolve(); else img.addEventListener('load', () => resolve(), { once: true }); }); }); await Promise.a ll([...fontPromises, ...imagePromises]); } // 渲染前等待 waitForCriticalAssets().then(() => { const root = ReactDOM.createRoot(document.getElementById('root')!); root.render(); });
? 总结与最佳实践
本身不加载资源,而是协调已触发的异步操作;必须配合手动资源加载逻辑(如 new Image()、document.fonts.load())才能生效; - 不要为每个组件加 useEffect 监听加载——统一在根组件或自定义 Hook(如 usePreloadAssets())中集中管理;
- 生产环境务必启用 HTTP/2 Server Push 或 CDN 缓存优化,使 preload 真正生效;
- 对非关键资源(如滚动后才出现的图片),仍应保留 loading="lazy" 以提升 LCP。
最终效果:用户看到的是一个空白过渡页(或品牌 Loading 动画),直到所有字体解析完毕、首屏图片解码完成,再一次性渲染完整、样式一致的页面——真正实现“所见即所载”。









