本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
群友问:Next.js 怎么支持 less?
答案很简单:Next.js 就是不支持 less。
不过,Next.js 支持了除 less 以外的其他多种样式方案,如:CSS-in-JS、全局CSS、CSS模块、Sass 和 Tailwind CSS,本文就来介绍一下这些方案。
CSS-in-JS
CSS-in-JS 是将 CSS 与 JavaScript 代码结合在一起的方式,能够充分利用 JavaScript 的模块化和封装特性来管理样式,规避样式冲突的问题。Next.js 支持多种 CSS-in-JS 库,如 styled-components
和 styled-jsx
。
不过,由于 Next.js 作为一个以服务端渲染为主的框架,某些 CSS-in-JS 库在 React 的服务器组件(Server Components)中使用可能会遇到兼容性问题;此外,CSS-in-JS 的另一个潜在问题是增加了 JavaScript 的体积,这可能对渲染性能产生影响。
鉴于这些因素,我个人不建议在 Next.js 项目中使用 CSS-in-JS 方案。
全局CSS
在 Next.js 项目中,使用全局 CSS 可以定义应用于整个项目的样式。例如,可以在 styles/globals.css
中定义全局样式,然后在 app 文件夹下的布局文件(layout.tsx)或页面文件(page.tsx)中导入它。
以下是一个示例:
css
/* styles/globals.css */
body {
color: black;
}
在 app/layout.tsx
中导入 globals.css
,则全局的 body
样式将应用黑色:
jsx
/* app/layout.tsx */
import '@/styles/globals.css'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
但如果新增加一个名为 login.css
的样式文件,在该文件中将 body
的 color
设置为蓝色:
css
/* styles/login.css */
body {
color: blue;
}
并在 app/login
文件夹内新增 layout.tsx
,并导入 login.css
:
jsx
/* app/login/layout.tsx */
import '@/styles/login.css' // 注释掉会应用globals.css的样式
export default function LoginLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
在这种情况下,登录页面的 body
文本颜色将变为蓝色。如果我们注释掉 import '@/styles/login.css'
这一行,文本颜色将恢复为黑色,因为上层 layout.tsx
中导入的 globals.css
将会生效。这就是所谓的"就近原则",即页面将根据与当前组件最接近的全局样式文件来应用样式。
因此,我建议尽可能只维护一个全局样式文件,其中包含可以全局应用的样式和CSS变量定义。
除此之外,Next.js 还支持从 node_modules
依赖包中导入样式文件,例如:
jsx
import 'bootstrap/dist/css/bootstrap.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="container">{children}</body>
</html>
)
}
但这种做法可能会导致样式冲突和不可预测的结果,因此也不建议使用。
CSS模块
Next.js 内置对 CSS 模块的支持,这是一种使用 .module.css
扩展名的局部作用域 CSS 方法。在不同的 CSS 模块文件中,即便样式类名相同,Next.js 也会自动生成唯一的类名,以避免样式冲突。这种方法尤其适用于组件级别的样式管理。
例如以下场景,我们有两个组件,每个组件都有自己的 CSS 模块文件:
组件 A 的 CSS 模块 (ComponentA.module.css
):
css
.button {
background-color: blue;
color: white;
}
组件 B 的 CSS 模块 (ComponentB.module.css
):
css
.button {
background-color: green;
color: black;
}
在这两个 CSS 模块中,都定义了 .button
类。
在组件中使用这些 CSS 模块时,应通过 import ... from ...
方式导入,Next.js 会自动处理它们,生成唯一的类名。
在组件 A 中使用 (ComponentA.jsx
):
jsx
import styles from './ComponentA.module.css';
function ComponentA() {
return <button className={styles.button}>Button A</button>;
}
在组件 B 中使用 (ComponentB.jsx
):
jsx
import styles from './ComponentB.module.css';
function ComponentB() {
return <button className={styles.button}>Button B</button>;
}
在构建过程中,Next.js 会为每个组件的 .button
类生成独特的标识符,如 .ComponentA_button__FR_sA
和 .ComponentB_button__2C5X
。
在生产环境中,Next.js 会自动对所有 CSS 模块文件进行处理。这包括将这些文件合并成多个压缩的 .css
文件,并实施代码分割。这种处理方式是根据应用中的热执行路径(hot execution paths)来优化的,意味着只会加载渲染应用所必需的最少量 CSS。这不仅优化了加载速度,还减少了不必要的资源消耗,从而提高了应用的整体性能和用户体验。
Sass
Sass 是一种广受欢迎的 CSS 预处理器,它通过引入变量、嵌套规则、混合体等功能来扩展 CSS 的能力。Sass 提供了两种语法:.sass
和 .scss
。
.sass
文件使用一种基于缩进的语法,不需要大括号和分号:
sass
#sidebar
width: 30%
background-color: #fafafa
而 .scss
文件则使用类似于传统 CSS 的语法:
scss
#sidebar {
width: 30%;
background-color: #fafafa;
}
我推荐使用 .scss
文件格式,因为它更符合大多数开发者编写 CSS 的习惯。
在 Next.js 中使用 Sass 非常简单。首先,需要安装 Sass 作为依赖:
bash
npm install --save-dev sass
# 或
yarn add sass
Next.js 使用 Sass 的方式与 CSS 模块类似。你可以将前一节提到的 .module.css
文件后缀更改为 .module.scss
来尝试。
此外,Next.js 还内置了对 Sass 模块的解析,简化了使用 @import
导入路径的过程。例如,假设有以下 Sass 文件结构:
markdown
/styles
|-- globals.scss
|-- _variables.scss
可以在 globals.scss
中这样使用 @import
导入:
scss
// styles/globals.scss
@import 'variables';
Next.js 的内置模块解析能力会在编译 Sass 文件时,在同一目录下查找并导入对应的 Sass 文件。
但是,如果需要从非同级目录导入 Sass 文件,就需要在 next.config.js
中添加自定义的 Sass 解析器配置:
jsx
const path = require('path')
module.exports = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')], // 配置 Sass 编译器
},
}
通过这样的配置,例如当有以下文件结构时:
jsx
/components
|-- componentA.scss
/styles
|-- _variables.scss
就可以在 componentA.scss
中正确地导入 _variables.scss
:
jsx
// components/componentA.scss
@import 'variables';
没有这种自定义的 Sass 编译配置时,从非同级目录导入 Sass 文件会导致编译错误。
Tailwind CSS
Tailwind CSS 是一个功能性的 CSS 框架,与传统的 CSS 框架(如 Bootstrap)有所不同。它不提供预设的组件样式,而是提供了一系列可组合的原子化样式类,让开发者能够灵活地创造所需的样式。
原子化的概念
平时我们会这样写样式:
html
<div class="content"></div>
<style>
.content {
font-size: 14px;
padding: 2px;
border: 1px solid #000;
}
</style>
而在 Tailwind CSS 中,原子化的写法更为简洁:
html
<div class="text-sm p-0.5 border"></div>
原子化 CSS 带来了诸多优势:
- 一致性和重用性:通过统一的样式类,整个项目中的样式更加一致。这种方法鼓励重用而非重复创建样式规则,减少了代码的冗余。
- 减少上下文切换:开发者可以直接在 HTML 中定义样式,避免在 HTML 和 CSS 文件之间频繁切换。
- 更小的样式文件体积:虽然 HTML 文件中的类名增多,但大量重用导致整体上 CSS 文件体积更小,尤其在大型项目中效果显著。
当然,Tailwind CSS 并不是完美的。一些开发者在刚接触Tailwind CSS时,可能因为需要记忆大量的样式类而犹豫。但请尝试一下,经过短暂的适应期后,你就会发现 Tailwind CSS 显著提高了样式编写的效率。这是"磨刀"与"砍柴"的关系,Tailwind CSS绝对值得学习。
在 Next.js 中使用 Tailwind CSS
如果通过 create-next-app
构建 Next.js 应用,可以选择自动集成 Tailwind CSS。例如,前文提到的项目结构中包含了 tailwind.config.ts
,这正是集成 Tailwind CSS 后的配置文件。
如果未在项目构建时选择 Tailwind CSS,也可以手动初始化配置:
bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
这将生成 tailwind.config.js
和 postcss.config.js
****两个文件。
下面是 Next.js 所需的基本 Tailwind 配置:
bash
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {},
},
plugins: [],
}
export default config
在实际项目中,可根据设计需求自定义主题(theme)或添加插件(plugins)。
💡 Tailwind主题定义包括定制响应式屏幕边界、颜色色值和字体名称等等可能大量使用的样式信息,插件则是一些能增强Tailwind样式的外部库。这些知识如果展开介绍篇幅会太长,如果你对Tailwind不熟悉,请到官方中文网站学习:https://www.tailwindcss.cn/。
要使 Tailwind 的样式生效,需要在全局 CSS 文件中导入相关指令:
css
/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
现在,可以在组件中直接使用 Tailwind CSS 的样式类:
jsx
export default function Page() {
return <h1 className="text-3xl font-bold underline">Hello, Next.js!</h1>
}
Tailwind CSS 的生态系统发展迅速,已被众多开源和商业项目采用。在 Next.js 的生态系统中,Tailwind CSS 占据着重要的位置,许多优秀的 UI 库也采用 Tailwind CSS 编写样式。因此,在 Next.js 项目中大胆使用 Tailwind CSS 吧!
结语
以上就是 Next.js 目前支持的所有样式方案了,你可以从中选择一个自己喜欢的或者擅长的方案来使用。
关于我
我是一名前端工程师,Next.js 手艺人,AI降临派。
今年致力于 Next.js 和 Node.js 领域的开源项目开发和知识分享。