Chapter 3:优化字体和图片

优化字体和图片

在上一章中,您学习了如何为 Next.js 应用程序添加样式。让我们继续通过添加自定义字体和主页图片来完善您的主页。

以下是本章中将涵盖的主题:

  • 如何使用 next/font 添加自定义字体。
  • 如何使用 next/image 添加图片。
  • Next.js 中如何优化字体和图片。

为什么要优化字体?

字体在网站设计中起着重要作用,但在项目中使用自定义字体可能会影响性能,特别是当需要获取和加载字体文件时。

累积布局移位 (opens in a new tab)(Cumulative Layout Shift)是 Google 用于评估网站性能和用户体验的度量标准。对于字体而言,布局移位发生在浏览器最初使用备用或系统字体呈现文本,然后在加载完自定义字体后进行替换。这种替换可能导致文本大小、间距或布局发生变化,从而使其周围的元素发生移位。

Next.js 在您使用 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 元素。您应该会在样式下看到 Inter 和 Inter_Fallback 已经被应用。

实践:添加次要字体

您还可以将字体添加到应用程序的特定元素。

现在轮到您了!在您的 fonts.ts 文件中,导入一个名为 Lusitana 的次要字体,并将其传递给 /app/page.tsx 文件中的 <p> 元素。除了像之前一样指定一个子集,您还需要指定字体的粗细。

准备好后,展开下面的代码片段以查看解决方案。

提示:

  • 如果您不确定要传递给字体的权重选项,请在代码编辑器中检查 TypeScript 错误。
  • 访问 Google Fonts 网站并搜索 Lusitana,查看可用的选项。
  • 查看添加多个字体和所有选项的完整列表的文档。
点击展开/折叠
/app/ui/fonts.ts
import { Inter, Lusitana } from 'next/font/google';
 
export const inter = Inter({ subsets: ['latin'] });
 
export const lusitana = Lusitana({
  weight: ['400', '700'],
  subsets: ['latin'],
});
/app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
 
export default function Page() {
  return (
    // ...
    <p
      className={`${lusitana.className} text-xl text-gray-800 md:text-3xl md:leading-normal`}
    >
      <strong>Welcome to Acme.</strong> This is the example for the{' '}
      <a href="https://nextjs.org/learn/" className="text-blue-500">
        Learn Next.js Course
      </a>
      , brought to you by Vercel.
    </p>
    // ...
  );
}

最后,<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 (opens in a new tab) 文件夹下提供静态资源,如图片。/public 中的文件可以在你的应用程序中引用。

在常规的 HTML 中,你可以如下添加图片:

<img
  src="/hero.png"
  alt="Screenshots of the dashboard project showing desktop version"
/>

然而,这意味着你必须手动:

  • 确保你的图片在不同屏幕尺寸上具有响应性。
  • 为不同设备指定图片大小。
  • 防止图片加载时的布局变化。
  • 对用户视口外的图片进行懒加载。

图片优化是 Web 开发中一个庞大的主题,可以被认为是一门专业领域。与手动实现这些优化相比,你可以使用 next/image 组件来自动优化你的图片。

<Image> 组件

<Image> 组件是 HTML <img> 标签的扩展,具有自动图像优化功能,包括:

  • 图片加载时自动防止布局移位。
  • 调整图像大小,避免向视口较小的设备传送大图像。
  • 默认情况下懒加载图像(图像在进入视口时加载)。
  • 在浏览器支持的情况下,以现代格式提供图像,如 WebP (opens in a new tab)AVIF (opens in a new tab)

添加桌面版主图

让我们使用 <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">
      {/* Add Hero Images Here */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop version"
      />
    </div>
    //...
  );
}

在这里,你将宽度设置为 1000 像素,高度设置为 760 像素。设置图像的宽度和高度以避免布局变化是一种良好的实践,这些应该是与源图像相同的纵横比。

你还会注意到使用了 hidden 类,这会在移动屏幕上从 DOM 中移除图片,而 md:block 会在桌面屏幕上显示图片。

你的主页现在应该是这个样子:

实践:添加移动端主页图片

现在轮到你了!在刚刚添加的图片下面,再添加另一个用于 hero-mobile.png<Image> 组件。

这张图片的宽度应该是 560 像素,高度是 620 像素。

它应该在移动屏幕上显示,在桌面上隐藏 - 你可以使用开发工具检查桌面和移动图片是否正确切换。

当你准备好时,展开下面的代码片段查看解决方案。

/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">
      {/* Add Hero Images Here */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop version"
      />
      <Image
        src="/hero-mobile.png"
        width={560}
        height={620}
        className="block md:hidden"
        alt="Screenshot of the dashboard project showing mobile version"
      />
    </div>
    //...
  );
}

太好了!你的主页现在已经使用了自定义字体和主页图片。

是时候做个测验了!

True 或 False:没有指定尺寸的图像和 Web 字体是布局移位的常见原因。

推荐阅读

关于这些主题,还有很多可以学习的内容,包括优化远程图像和使用本地字体文件。如果您想深入了解字体和图像,请参阅:

声明

之前,有网友表示,这个项目挺好的,对他有帮助,来表示感谢!

在此声明下,本项目只是一个中文翻译版本,纯粹的 “为爱发电了”,原版权仍归 Next.js 官方教程所有,本翻译项目无任何商业行为,也不接受任何金钱上的捐赠哈。 如果真的感觉有帮助,就点个 Star 吧,关注下 “编程界” 公众号,上面平常也在分享 Next.js 相关内容。

扫码备注 “nextjs” 加入 Next.js 中文技术交流群

扫码备注「nextjs
加入 Next.js 中文技术交流群

关注公众号编程界获取最新 Next.js 开发资讯

关注公众号「编程界
获取最新 Next.js 开发资讯