Next.js-样式处理
#题引:我认为跟着官方文档学习不会走歪路
Next.js 支持多种为应用程序添加样式的方法,包括:
- CSS Modules:创建局部作用域的 CSS 类,避免命名冲突并提高可维护性。
- 全局 CSS:使用简单,对于有传统 CSS 经验的人来说很熟悉,但可能导致 CSS 包体积较大,且随着应用程序增长难以管理样式。
- Tailwind CSS:一个实用优先的 CSS 框架,通过组合实用类可以快速创建自定义设计。
- CSS预处理器:比如Sass,通过变量、嵌套规则和混合等特性扩展了 CSS 功能。
- CSS-in-JS:直接在 JavaScript 组件中嵌入 CSS,实现动态和作用域样式。
一:CSS Modules 和 全局CSS
CSS Modules 通过自动创建唯一的类名来实现 CSS 的局部作用域。这使得你可以在不同文件中使用相同的类名而不用担心冲突。这种特性使 CSS Modules 成为引入组件级 CSS 的理想方式。
Next.js 内置支持使用 .module.css 扩展名的 CSS Modules。
CSS Modules 仅对扩展名为 .module.css 和 .module.sass 的文件启用。
在生产环境中,所有 CSS Module 文件会自动合并成多个经过代码分割和压缩的 .css 文件。这些 .css 文件代表了应用程序中的热执行路径,确保只加载应用程序渲染所需的最少 CSS。
而全局样式可以在 app 目录下的任何布局、页面或组件中导入,例如在根布局 (app/layout.js) 中,导入 global.css 样式表以将样式应用到应用程序的每个路由。
Next.js 在生产构建期间通过自动分块(合并)样式表来优化 CSS。CSS 的顺序是由_你在应用程序代码中导入样式表的顺序_决定的。因此官方建议:
- 只在单个 JS/TS 文件中导入一个 CSS 文件。
如果使用全局类名,在同一个文件中按照你想要应用的顺序导入全局样式。 - 优先使用 CSS Modules 而不是全局样式。
为你的 CSS modules 使用一致的命名约定。例如,使用·<name>.module.css
而不是<name>.tsx
。 - 将共享样式提取到单独的共享组件中。
- 如果使用 Tailwind,最好在文件顶部导入样式表,最好是在根布局中。
- 关闭任何会自动对导入进行排序的 linters/formatters(例如,ESLint 的 sort-import)
你可以使用 next.config.js 中的 cssChunking 选项来控制 CSS 如何分块。
const nextConfig = {
experimental: {
cssChunking: 'loose', // 默认值
},
}
- ‘loose’ (默认值):Next.js 会尽可能合并 CSS 文件,通过导入顺序确定文件之间的显式和隐式依赖关系,以减少分块数量,从而减少请求数量。
- ‘strict’:Next.js 将按照文件中导入的正确顺序加载 CSS 文件,这可能会导致更多的分块和请求。(遇到意外的 CSS 行为时使用)
二:Tailwind CSS
创建新的 Next.js 应用程序,可以选择使用Tailwind CSS,它会为你自动设置好。
或者手动添加,,通过以下命令安装并生成tailwind.config.js 和 postcss.config.js 文件。
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
在tailwind.config.ts可以添加将使用 Tailwind 类名的文件路径。
你不需要修改 postcss.config.js。
可以将 Tailwind 用于注入其生成样式的 Tailwind CSS 指令 添加到应用程序中的全局样式表中,例如:
@tailwind base;
@tailwind components;
@tailwind utilities;
三:CSS预处理器
Next.js 在安装相关包后,内置支持使用 .scss 和 .sass 扩展名集成 Sass。你可以通过 CSS Modules 使用组件级的 Sass,使用 .module.scss 或 .module.sass 扩展名。
首先安装
npm install --save-dev sass
如果你想配置 Sass 选项,可以在 next.config 中使用 sassOptions。
Sass 有不同的实现方式,最常用的有两种:
- Node Sass:基于 LibSass 的实现,使用 C++ 编写,性能较高,但已经不再维护。
- Dart Sass:基于 Dart 语言的实现,是 Sass 官方推荐的实现,支持最新的 Sass 特性。
默认情况下,Next.js 使用 sass 包,即Dart Sass
Next.js 支持从 CSS Module 文件导出 Sass 变量。
例如,使用导出的 primaryColor Sass 变量:
四:CSS-in-JS
CSS-in-JS 是一种将 CSS 样式与 JavaScript 代码结合的方式,允许在组件内定义样式。
需要运行时 JavaScript 的 CSS-in-JS 库目前不支持在服务器组件中使用。在新的 React 特性(如服务器组件和流式传输)中使用 CSS-in-JS,需要库作者支持最新版本的 React,包括 并发渲染。
以下库支持在 app 目录中的客户端组件中使用(按字母顺序排列):
ant-design
chakra-ui
@fluentui/react-components
kuma-ui
@mui/material
@mui/joy
pandacss
styled-jsx
styled-components
stylex
tamagui
tss-react
vanilla-extract
如果你想为服务器组件添加样式,官方推荐使用 CSS Modules 或其他输出 CSS 文件的解决方案,如 PostCSS 或 Tailwind CSS
配置 CSS-in-JS 是一个三步的选择性过程,包括:
- 一个样式注册表用于收集渲染中的所有 CSS 规则。
- 新的 useServerInsertedHTML hook,用于在可能使用这些规则的任何内容之前注入规则。
- 一个客户端组件,在初始服务器端渲染期间用样式注册表包装你的应用。
以styled-jsx
(v5.1.0 或更高版本)为例
首先,创建一个新的注册表:
"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { StyleRegistry, createStyleRegistry } from "styled-jsx";
export default function StyledJsxRegistry({
children,
}: {
children: React.ReactNode;
}) {
// 只创建一次样式表,使用延迟初始状态
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [jsxStyleRegistry] = useState(() => createStyleRegistry());
useServerInsertedHTML(() => {
const styles = jsxStyleRegistry.styles();
jsxStyleRegistry.flush();
return <>{styles}</>;
});
return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>;
}
然后,用注册表包装你的 根布局
import StyledJsxRegistry from "./registry";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
);
}
在这里查看示例