优化字体与图片

在上一章节中,您学习了如何为 Next.js 应用添加样式。现在我们将继续完善首页,添加自定义字体和主视觉图片。

为何需要优化字体?

字体对网站设计至关重要,但如果项目中使用的自定义字体需要通过网络获取和加载,则可能影响性能。

累积布局偏移 (CLS) 是谷歌用于评估网站性能和用户体验的指标。字体导致的布局偏移发生在浏览器最初使用备用字体或系统字体渲染文本,随后加载完成后再替换为自定义字体时。这种替换可能导致文本大小、间距或布局发生变化,从而影响周边元素。

模拟界面展示页面初始加载效果,随后因自定义字体加载引发的布局偏移

当您使用 next/font 模块时,Next.js 会自动优化应用中的字体。它会在构建时下载字体文件并与其它静态资源一同托管。这意味着用户访问应用时,不会产生额外的字体网络请求而影响性能。

添加主字体

让我们为应用添加 Google 字体来了解其工作原理。

/app/ui 文件夹中新建 fonts.ts 文件,用于存放整个应用将使用的字体。

next/font/google 模块导入 Inter 字体作为主字体,并指定加载的子集,此处选择 'latin'

/app/ui/fonts.ts
import { Inter } from 'next/font/google';
 
export const inter = Inter({ subsets: ['latin'] });

最后在 /app/layout.tsx 中将字体添加到 <body> 元素:

/app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

通过将 Inter 添加到 <body> 元素,字体将应用于整个应用。此处还添加了 Tailwind 的 antialiased 类来实现字体抗锯齿效果(非必需但能提升显示质量)。

在浏览器中打开开发者工具并选中 body 元素,您会看到样式已应用 InterInter_Fallback

练习:添加辅助字体

您也可以为特定元素添加字体。

现在请尝试:在 fonts.ts 文件中导入名为 Lusitana 的辅助字体,并将其应用到 /app/page.tsx 文件的 <p> 元素。除了像之前那样指定子集外,还需指定不同的字体权重(如 400 常规和 700 加粗)。

完成后可展开下方代码查看解决方案:

提示:

最后,<AcmeLogo /> 组件也使用了 Lusitana 字体(之前被注释以避免错误),现在可以取消注释:

/app/page.tsx
// ...
 
export default function Page() {
  return (
    <main className="flex min-h-screen flex-col p-6">
      <div className="flex h-20 shrink-0 items-end rounded-lg bg-blue-500 p-4 md:h-52">
        <AcmeLogo />
        {/* ... */}
      </div>
    </main>
  );
}

很好!您已成功为应用添加两种自定义字体。接下来让我们为主页添加主视觉图片。

为何需要优化图片?

Next.js 可以通过顶级 /public 文件夹提供静态资源(如图片)。/public 中的文件可直接在应用中引用。

传统 HTML 添加图片的方式如下:

<img
  src="/hero.png"
  alt="仪表盘项目的桌面版截图"
/>

但这种方式需要手动处理:

  • 确保图片在不同屏幕尺寸下响应式显示
  • 为不同设备指定图片尺寸
  • 防止图片加载时的布局偏移
  • 对可视区域外的图片实现懒加载

图片优化是前端开发中的重要课题,甚至可以成为专门的技术方向。与其手动实现这些优化,您可以使用 next/image 组件自动完成。

<Image> 组件

<Image> 组件是对 HTML <img> 标签的扩展,提供以下自动优化功能:

  • 防止图片加载时的布局偏移
  • 根据视窗大小自动调整图片尺寸
  • 默认启用懒加载(进入视窗时加载)
  • 支持现代图片格式如 WebPAVIF(根据浏览器支持情况)

添加桌面版主视觉图片

让我们使用 <Image> 组件。查看 /public 文件夹会发现两张图片:hero-desktop.pnghero-mobile.png,它们将根据用户设备类型分别显示。

/app/page.tsx 中导入 next/image 组件,然后在注释下方添加图片:

/app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* 在此添加主视觉图片 */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="仪表盘项目的桌面版截图"
      />
    </div>
    //...
  );
}

此处设置 width1000height760 像素。建议始终指定图片宽高以避免布局偏移,这些值应与源图片保持相同的宽高比(并非实际渲染尺寸)。

hidden 类用于在移动端隐藏图片,md:block 则在桌面端显示。

现在您的主页应该呈现如下效果:

应用自定义字体和主视觉图片后的首页效果

练习:添加移动版主视觉图片

现在请尝试:在刚添加的图片下方,为 hero-mobile.png 添加另一个 <Image> 组件:

  • 设置 width560height620 像素
  • 应在移动端显示,桌面端隐藏(可使用开发者工具验证切换效果)

完成后可展开下方代码查看解决方案:

太棒了!现在您的主页已拥有自定义字体和响应式主视觉图片。

扩展阅读

关于字体和图片优化还有更多内容值得探索,包括优化远程图片和使用本地字体文件。如需深入了解,请参考:

On this page