如何解决Next.js 14中Material Symbols图标闪烁问题?
Next.js 14中Material Symbols SSR加载闪烁/延迟显示的解决方法
针对你在Next.js 14.0.4里用globals.css导入Material Symbols时,SSR阶段图标看不见、加载完成后才显示的问题,给你几个实用解决方案:
1. 固定图标容器尺寸,彻底避免布局闪烁
图标加载前没有占位尺寸是导致布局跳动的核心原因,直接给图标元素设置固定宽高即可:
/* 在globals.css中添加 */ .material-symbols-outlined { width: 24px; /* 匹配你设置的图标font-size */ height: 24px; display: inline-block; vertical-align: middle; }
这样不管图标是否加载完成,容器都有固定占位,不会出现页面元素跳动的情况。
2. 配置字体预加载+强制渲染,实现SSR即时显示
修改globals.css中的字体导入规则,添加font-display: block并明确字体源,让浏览器在渲染页面时直接等待字体加载完成,避免先显示空白:
@font-face { font-family: 'Material Symbols Outlined'; font-style: normal; font-weight: 400; /* 替换为你使用的Material Symbols字体源 */ src: url(https://fonts.gstatic.com/s/materialsymbolsoutlined/v147/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1n-q_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); font-display: block; /* 关键:阻止字体交换,确保SSR时直接渲染图标 */ }
如果担心字体加载慢导致长时间空白,可以结合上面的固定尺寸方案,这样至少有占位,用户感知会好很多。
3. 骨架屏方案:精准判断图标加载完成
如果要做按钮骨架屏,可以借助字体加载检测工具来切换状态:
步骤1:安装字体检测依赖
npm install fontfaceobserver
步骤2:封装字体加载检测函数
// utils/fontLoader.js import FontFaceObserver from 'fontfaceobserver'; export default function waitForFontLoad(fontFamily) { return new Promise(resolve => { const fontObserver = new FontFaceObserver(fontFamily); // 加载成功或失败都resolve,避免骨架屏一直显示 fontObserver.load().then(resolve).catch(resolve); }); }
步骤3:在组件中使用骨架屏
// components/IconButton.jsx 'use client'; import { useEffect, useState } from 'react'; import waitForFontLoad from '@/utils/fontLoader'; export default function IconButton() { const [isFontLoaded, setIsFontLoaded] = useState(false); useEffect(() => { waitForFontLoad('Material Symbols Outlined').then(() => { setIsFontLoaded(true); }); }, []); return ( <button className="px-3 py-2 flex items-center gap-2"> {!isFontLoaded ? ( <div className="icon-skeleton"></div> ) : ( <span className="material-symbols-outlined">home</span> )} <span>首页</span> </button> ); }
步骤4:添加骨架屏样式
/* globals.css */ .icon-skeleton { width: 24px; height: 24px; border-radius: 4px; background-color: #e5e7eb; animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
4. 备选方案:改用SVG图标组件
如果不想折腾字体加载问题,直接用SVG格式的Material Symbols图标是最彻底的解决办法——SSR时会直接渲染SVG代码,完全没有加载延迟:
// components/HomeIcon.jsx export default function HomeIcon() { return ( <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" fill="#333"> <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/> </svg> ); }
你可以从Material Icons官网直接下载需要的SVG,或者使用@mui/icons-material这类封装好的组件库。
内容的提问来源于stack exchange,提问作者MoDrazzz
相关产品推荐
相关产品推荐

