通过 react 的 `
在客户端渲染(CSR)的 React 应用中,浏览器默认按 HTML 解析顺序逐步加载 CSS、字体和图片,导致未样式化文本(FOUT)、不可见文本(FOIT)或占位图闪烁等问题。单纯依赖
在 public/index.html 的
中预加载核心字体,并禁用不可见文本回退:⚠️ 注意:font-display: optional 要求浏览器在 100ms 内完成加载,否则跳过渲染字体——这正符合“全就绪再显示”的前提。
避免 的默认行为。创建一个可 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.all([...fontPromises, ...imagePromises]); } // 渲染前等待 waitForCriticalAssets().then(() => { const root = ReactDOM.createRoot(document.getElementById('root')!); root.render(); }); ? 总结与最佳实践
最终效果:用户看到的是一个空白过渡页(或品牌 Loading 动画),直到所有字体解析完毕、首屏图片解码完成,再一次性渲染完整、样式一致的页面——真正实现“所见即所载”。