- 一二章传送门:Next14 最佳实践系列文章-第一、二章
- 切记:只要能坚持下来,对前端领域的认知会有一个质的飞跃。现在是基础阶段,之所谓万丈高楼平地起,地基很重要。
- 有点小伙伴问为啥要这么创建文件目录结构,跟我原来学的不一样。有这个疑问是好的,请带着这个疑问,跟着教程走,学完自己体会。我也在最后做详解。
这一章节,可以学到:
- 如何使用
next/font
添加自定义字体 - 如何使用
next/image
添加图像 - 如何在Next.js中优化字体和图像
为什么要字体优化?
字体在网站设计中发挥着重要作用,但如果需要获取和加载字体文件,在项目中使用自定义字体可能会影响性能。字体优化是必然的,现有框架中做的最好的也就是Next.js
累积布局偏移(CLS)是Google用于评估网站性能和用户体验的指标。对于字体,当浏览器最初以后备字体或系统字体呈现文本,然后在加载后将其转换为自定义字体时,就会发生布局转换。这种转换可能会导致文本大小、间距或布局发生变化,从而移动其周围的元素。
当使用next/font
模块时,Next.js会自动优化应用程序中的字体。它在构建时下载字体文件并将它们与其他静态资产一起托管。这意味着当用户访问应用程序时,不会出现影响性能的额外网络请求字体。
添加主要字体
添加自定义Google字体。在/app/ui
文件夹中,创建一个名为fonts.ts
的新文件。此文件用来保留程序中所使用的字体。
从 next/font/google
模块中导入Inter字体-这个将是程序的主要字体。相应的,指定对应的哪个子集即可,如'latin':
javascript
import { Inter } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
将字体添加到 /app/layout.tsx
中的 <body>
元素:
javascript
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。加了这个类增加观感度,增强用户体验。读者可运行后自行体验。
练习:增加另一个辅助字体
可以将字体添加到指定的元素。现在增加一个Lusitana
的辅助字体到 /app/page.tsx
文件中的<p>
元素。除了指定子集之外,还需要指定字体的粗细。
注:先自己实现,然后看答案。跟着思路练习,不要眼高手低。感觉看会了,自己写不出来。编程就是这样,是一门理论加实践的学科,贵在练习。
点击查看解决方案
javascript
import { Inter, Lusitana } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
export const lusitana = Lusitana({
weight: ['400', '700'],
subsets: ['latin'],
});
javascript
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';
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">
Next.js Learn Course
</a>
, brought to you by Vercel.
</p>
// ...
);
}
最后需要把<AcmeLogo>
组件也使用Lusitana
。可以将代码注释去调。
javascript
// ...
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中添加/public
中的静态资源-图像:
ini
<img
src="/hero.png"
alt="Screenshots of the dashboard project showing desktop version"
/>
但是,这意味着必须手动处理:
- 图像在不同屏幕上是响应式的
- 指定不同设备的图像尺寸
- 防止图像加载时布局发生变化
- 延迟加载用户视口之外的图像
图像优化是Web开发中的一个大的主题,其本身就是一个专业领域。如此,next/image
组件提供极致的自动优化功能,而我们不用自己费劲巴拉的自己实现这些优化。
组件
<Image>
组件是HTML元素<img>
标签的扩展,并且具有自动图像优化功能,如:
- 加载图像时自动防止布局移动
- 调整图像大小从而避免不适配不同设备视口
- 默认情况下延迟加载图像(图像在进入视口时加载)
- 当浏览器支持时,提供现代格式图像,如 WebP 和 AVIF
添加图像到桌面
先在让我们使用一下<Image>
组件。查看/public
文件夹,里面有两个图像:hero-desktop.png
和hero-mobile.png
。分别是移动端还有PC端。
在 /app/page.tsx
文件夹中,从 next/image
导入组件:
javascript
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>
//...
);
}
代码中,宽度设置为1000px,高度设置为760px。最好设置图像的宽度和高度以避免布局移位,并且宽高比应该与源图像相同。
你可能还注意到隐藏类hidden
用于在移动端不展示此DOM元素,以及类md:block
用于在桌面上展示。这些事Tailwind
语法,可以看下官网大致了解一下。
现在主页的样子应如下图:
练习:添加移动端的主图
练习一下,将移动端的图片加入进来:
- 该图像为宽560px,高620px
- 在移动端展示,桌面端隐藏
点击查看答案
javascript
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>
//...
);
}
现在已经完成了字体与图像的模块学习。