在上一章中,学习了如何设置Next.js应用程序的样式。现在我们开始添加自定义字体和图片。
为什么要优化字体?
字体在网站设计中起着重要作用,但如果需要获取和加载字体文件,则在项目中使用自定义字体可能会影响性能。
累积布局偏移是谷歌用来评估网站性能和用户体验的一个指标。对于字体而言,布局偏移发生在浏览器最初以备用字体或系统字体渲染文本,然后在加载完成后将其替换为自定义字体。这种交换会导致文字大小、间距或布局发生变化,从而移动周围的元素。
使用 next/font 模块时,Next.js 会自动优化应用程序中的字体。它会在构建时下载字体文件,并将其与其他静态资产一起托管。这意味着,当用户访问您的应用程序时,不会出现影响性能的额外字体网络请求。
如何添加字体?
让我们在应用程序中添加一个自定义的 Google 字体,看看它是如何工作的!
在 /app/ui 文件夹中新建一个名为 fonts.ts 的文件。使用该文件保存整个应用程序中使用的字体。
从 next/font/google 模块导入 Inter字体--这将是你的主要字体。然后,指定要加载的子集。本例中为 latin:
import { Inter } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
最后,将字体添加到文件 /app/layout.tsx 的 <body> 元素中:
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> 元素。除了像之前那样指定子集外,你还需要指定字体权重。
怎样?如果你练习完了,下面是参考代码
// app/ui/font.ts
import { Inter, Lusitana } from 'next/font/google'
export const inter = Inter(
{
subsets: ['latin']
}
)
export const lusitana = Lusitana(
{
subsets: ['latin'],
weight: '400'
}
)
// app/page.tsx
……
<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">
Next.js Learn 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 文件夹下提供静态文件,如图像。可以在应用程序中引用 /public 中的文件。
使用普通 HTML 时,添加图像的方法如下:
<img src="/hero.png" alt="Screenshots of the dashboard project showing desktop version"/>
不过,这意味着您必须手动操作:
- 确保图片在不同尺寸的屏幕上都能响应。
- 为不同设备指定图像尺寸
- 防止图片加载时发生布局偏移。
- 懒加载用户视窗以外的图片。
图像优化是网络开发中的一个大课题,其本身就可以被视为一门专业。您可以使用 next/image 组件自动优化图像,而无需手动实施这些优化。
组件
<Image> 组件是 HTML <img> 标记的扩展,具有自动图像优化功能,如: <Image>:
- 防止在加载图像时版面自动移动。
- 调整图片大小,避免将大图片传输到视口较小的设备上。
- 默认懒加载图像(图像在进入视口时加载)。
- 在浏览器支持的情况下,以 WebP 和 AVIF 等现代格式提供图像。
添加桌面主题图像
让我们使用 <Image> 组件。如果你查看 /public 文件夹,你会发现里面有两张图片: hero-desktop.png 和 hero-mobile.png 。这两张图片完全不同,它们的显示将取决于用户的设备是台式机还是移动设备。
在 /app/page.tsx 文件中,从 next/image 导入组件。然后,在注释下添加图片:
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>
//...
);
}
在这里,你需要将 width 设置为 1000 像素,将 height 设置为 760 像素。设置图像的 width 和 height 以避免布局偏移是个好方法,它们的宽高比应与源图像相同。
你还会注意到 hidden 类用于在移动屏幕上从 DOM 中移除图像,而 md:block 则用于在桌面屏幕上显示图像。
这就是你的主页现在的样子:
练习下:添加手机图像
现在轮到你了!在刚刚添加的图片下,为 hero-mobile.png 添加另一个 <Image> 组件。
- 图像的
width像素应为560,height像素应为620。 - 它应在手机屏幕上显示,而在桌面上隐藏--您可以使用开发工具检查桌面和手机图像是否正确交换。
如何?写完的话,你可以匹配下答案
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>
//...
);
}