比较 Next.js 中的样式方法
已发表: 2022-03-10您可能知道,关于 CSS-in-JS 有许多不同的观点,而且我们对这个主题的看法可能与框架作者的看法完全不同。
Next.js是创建新 React 应用程序时推荐的工具链之一。 像 Next 这样的工具有一个简单的目标,即在编写 React 应用程序时抽象出常见的冗余任务。 这有助于开发人员更多地专注于编写代码,而不是重新发明轮子。 虽然这通常是一件好事,但开始时也可能有点乏味。 一方面,学习抽象有一个障碍需要跨越,虽然 Next 中有一大堆(路由、数据获取……),但一个经常被忽视的是样式。
为了服务更广泛的受众,Next.js 支持多种方式来设置组件样式。 无论你是属于 Utility 优先还是 CSS-in-JS 党都不是 Next 关心的问题,它关心的是你如何将你的选择注入到它的 API 中。
本文的目的是帮助您了解如何在 Next 应用程序中设置样式。 我们将使用不同的方法来处理比较。 我们将在我设置的图书应用程序中实现不同类型的样式。 我们将要研究的样式方法包括:
- 全球 CSS,
- SASS/SCSS,
- 组件级 SASS/SCSS,
- 组件级 CSS(CSS 模块),
- 样式化组件,
- 样式化的 JSX,
- 情感。
先决条件
在我们开始我们的造型之旅之前,您需要了解一些 Next 细微差别。
-
_app.js
这是一个位于 pages 文件夹中的自定义组件。 Next.js 使用这个组件来初始化页面。 -
_document.js
与_app.js
一样,_document.js
是 Next.js 用来增强应用程序<html>
和<body>
标记的自定义组件。 这是必要的,因为 Next.js 页面跳过了周围文档标记的定义。 -
_.babelrc
如果存在,Next.js 使用此文件作为某些内部配置的单一事实来源,并授予您扩展它的权限。
请记住,如果在添加_app.js
文件之前您的服务器正在运行,那么您需要重新启动它。
使用create-next-app
使用create-next-app
创建 Next 应用程序非常简单,只需执行以下步骤:
- 全局安装
create-next-app
。
yarn global add create-next-app // Installs create-next-app globally
- 创建一个名为style-in-next的新 Next 应用。
create-next-app styling-in-next // Creates a new Next app named styling-in-next
- 将目录更改为新站点。
cd styling-in-next // Switch directory into the new Next app
- 运行站点。
yarn dev -p 3000 // Instruct Next to run on port 3000
有关创建和运行 Next 应用程序的更多信息,请参阅文档。
该应用程序现在应该在https://localhost:3000
上运行。
演示库
随着我们的进展,我们将通过对每本书应用不同的样式方法来构建一个人为的书架。 最终结果将如下所示:
上图显示了 6 本书; 每本书都有自己的组件,然后我们将为每本特定的书应用特定的样式类型,即,书 1 将使用全局样式,而书 2 将使用另一个样式。 通过这种方式,我们将了解这些样式中的每一个如何工作以及如何使用它们。 这将帮助您更好地决定选择什么选项。
为简单起见,我搭建了一个 GitHub 存储库供您学习。 你可以在这里抓住它。
对create-next-app
生成的默认启动器也进行了一些更改。 诸如情感、全局、模块、样式组件等文件夹已添加到styles
文件夹中——及其相应的样式文件——以及包含多个组件的components
目录。
修改了index.js
文件以import
和render
所需的components
,并且每个组件的结构都类似于下图所示。
如果您克隆并运行了演示存储库,您的页面应该如下所示:
把所有这些都排除在外,让我们开始造型吧。
全球风格
当你开始一个新的 web 项目时,你通常会做的一件常见的事情是重置或规范化你的 CSS,以便在浏览器之间有一个统一的起始位置。 这是一个使用全局 CSS 而不用担心范围的完美示例。
- 使用扩展的 Minimal CSS Reset 更新
styles/global/globals.css
。
/* styles/global/globals.css */ html { box-sizing: border-box; font-size: 16px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } *, *:before, *:after { box-sizing: inherit; } body, h1, h2, h3, h4, h5, h6, p, ol, ul { margin: 0; padding: 0; font-weight: normal; } h1, h2, h3, h4, h5, h6 { font-weight: bold; } ol, ul { list-style: none; } img { max-width: 100%; height: auto; } a { color: inherit; text-decoration: none; }
- 在
pages/_app.js
中导入 CSS 重置styles/global/globals.css
/global/globals.css。
// pages/_app.js import "../styles/global/globals.css"; function MyApp({Component, pageProps}) { return <Component {...pageProps} />; } export default MyApp;
全局样式只能在pages/_app.js
中导入。 这是直接合乎逻辑的,因为这些样式将应用于应用程序中的所有pages
和components
——无论你在哪里导入它们——所以最好有一个单一的 [import] 事实来源,以保持事情简单明了,和/或如果出现问题错误的。
在这一点上,我们的书架没有太多的视觉变化,因为我们只进行了标准化更改。 您可能会注意到的一件事是字体和间距的变化。
SASS/SCSS
Next.js 还允许使用带有.sass
或.scss
扩展名的 SASS 进行样式设置。 安装 Sass 是必需的。 就像全局样式一样,它们只能在pages/_app.js
中导入。
- 安装 Sass 包。
yarn add sass
- 更新
styles/scss/bookshelf.scss
。
// styles/scss/bookshelf.scss .the-bookshelf { width: 100vw; height: 100vh; background-color: #e3e3e3; display: flex; justify-content: center; align-items: center; .bookshelf-wrap { > .bookshelf { box-shadow: inset 0 -20px #7b5019; padding-bottom: 20px; display: flex; align-items: flex-end; } [class*="book"] { font-size: 32px; letter-spacing: -0.045em; display: flex; transition: 0.2s; &:hover { transform: none; } } .book-info { text-transform: uppercase; writing-mode: sideways-rl; display: flex; justify-content: space-around; flex: 1; align-items: center; font-weight: bold; padding: 16px 0; .title { font-weight: inherit; font-size: 20px; } .author { font-weight: inherit; font-size: 15px; } } } }
- 同时更新
styles/sass/bookone.sass
和styles/sass/booktwo.sass
,如下所示:
// styles/sass/bookone.sass .book-one color: #f00 width: 78px height: 350px transform: rotate(-4deg) margin-left: 16px margin-right: 23px background-color: black
// styles/sass/booktwo.sass .book-two color: #781e0b width: 38px height: 448px margin-right: 23px background-color: #ffab44
SASS ( .sass
) 基于缩进。 为了使格式化更容易,您可以安装此 VSCode Extension for SASS 文件支持(格式化、语法高亮...)
- 在
pages/_app.js
中导入三个样式文件styles/scss/bookshelf.scss
bookshelf.scss、styles/sass/bookone.sass
和styles/sass/booktwo.sass
booktwo.sass。
// pages/_app.js import "../styles/globals.css"; import "../styles/scss/bookshelf.scss"; import "../styles/sass/bookone.sass"; import "../styles/sass/booktwo.sass"; function MyApp({Component, pageProps}) { return ; } export default MyApp;
// pages/_app.js import "../styles/globals.css"; import "../styles/scss/bookshelf.scss"; import "../styles/sass/bookone.sass"; import "../styles/sass/booktwo.sass"; function MyApp({Component, pageProps}) { return ; } export default MyApp;
我们的书架开始成型。 应用样式后,第一本书和第二本书应按预期设置样式和显示。
CSS 模块
CSS Modules 是一个组件级的 CSS,它内置在 Next 中,可以通过使用.module.css
扩展名命名样式文件来激活。 也可以使用带有.module.sass
或.module.scss
扩展名的 SASS/SCSS 的 CSS 模块。
让我们用它来设置components/BookThree.js
组件的样式。
- 更新
styles/modules/BookThree.module.css
。
/* styles/modules/BookThree.module.css */ .book-three { color: #df66c3; width: 106px; height: 448px; margin-right: 23px; background-color: #153086; transform: rotate(-4deg); }
- 在
components/BookThree.js
中导入styles/modules/BookThree.module.css
BookThree.module.css,并应用.book-three
类。
// components/BookThree.js import BookThreeStyles from "../styles/modules/BookThree.module.css"; export default function BookThree() { return ( <div className={BookThreeStyles["book-three"]}> <div className="book-info"> <p className="title">the revolt of the public</p> <p className="author">Martin Gurri</p> </div> </div> ); }
在 CSS 模块中访问类名类似于 JavaScript 中的属性访问器——使用点或括号表示法。 这里我们导入BookThreeStyles
,然后使用括号符号来应用我们在styles/modules/BookThree.module.css
文件中的样式。
如果选择器(在本例中为类名)被正确访问,那么现在应该设置第三本书的样式。
情感
Emotion 是一个 CSS-in-JS 库,与任何其他 CSS-in-JS 一样,允许您使用 JavaScript 编写 CSS 样式。
让我们用它来设置components/BookFour.js
组件的样式。
- 安装包:
@emotion/core
、@emotion/styled
、emotion
、emotion-server
。
yarn add @emotion/core @emotion/styled emotion emotion-server
- 更新
styles/emotion/StyledBookFour.js
。
// styles/emotion/StyledBookFour.js import styled from "@emotion/styled"; export const StyledBookFour = styled.div` color: white; width: 38px; height: 400px; margin-left: 20px; margin-right: 10px; background-color: #2faad2; transform: rotate(4deg); `;
从@emotion/styled
导入styled
后,我们导出StyledBookFour
样式组件——不要与其他 CSS-in-JS 样式组件混淆——使用styled.div
中的styled
情感方法增强。 然后我们可以在下面的下一步中使用<StyledBookFour/>
。
了解有关情感样式化功能的更多信息。
- 使用
<StyledBookFour/>
类似于使用任何其他 React 组件。 在components/BookFour.js
中导入styles/emotion/StyledBookFour.js
StyledBookFour.js,并应用StyledBookFour
组件。
// components/BookFour.js import {StyledBookFour} from "../styles/emotion/StyledBookFour"; export default function BookFour() { return ( <StyledBookFour className="book-four"> <div className="book-info"> <p className="title">the man died</p> <p className="author">wole soyinka</p> </div> </StyledBookFour> ); }
有了足够的情感,第四本书应该是这样的风格。
样式化的 JSX
与 Global CSS 和 CSS-Modules 一样,Styled-JSX 无需任何额外设置即可与 Next.js 一起使用。 如果有帮助,Styled-JSX 也是 Vercel 提供的基于组件的 CSS,Next.js 的创建者也是如此。
让我们用它来设置components/BookFive.js
组件的样式。
为了简单起见,我们在这里使用 styled-jsx 的内部模式。 通过将jsx
传递给<style/>
组件,我们可以像使用.book-five
一样编写尽可能多的 CSS,并且样式被本地化到<BookFive/>
组件的额外好处。
// components/BookFive.js export default function BookFive() { return ( <div className="book-five"> <div className="book-info"> <p className="title">there was a country</p> <p className="author">Chinua Achebe</p> </div> <style jsx>{` .book-five { color: #fff; width: 106px; height: 448px; margin-right: 23px; background-color: #000; transform: rotate(4deg); } `}</style> </div> ); }
就这样,第五本书采用了它的样式。
样式化的组件
Styled-Component 和 Emotion 一样,也是一个 CSS-in-JS 库,允许您使用 JavaScript 编写 CSS 样式。 设置它有点复杂。
- 首先,安装
babel-plugin-styled-components
和styled-components
。
yarn add babel-plugin-styled-components styled-components
- 在应用的根目录下创建一个
.babelrc
文件,以及一个pages/_document.js
文件,如下图之前(左)和之后(右)所示。
- 更新
.babelrc
文件以包含next/babel
预设并包含styled-components
插件,并启用服务器端渲染(ssr)。
// .babelrc { "presets": ["next/babel"], "plugins": [ [ "styled-components", { "ssr": true } ] ] }
- 通过将服务器端呈现的样式注入
<head>
来更新pages/_document.js
。
请记住,下面的代码片段 ( pages/_document.js
) 是 styled-components 与 Next.js 一起使用的必需逻辑。 您几乎无需执行任何操作,只需复制 styled-components 文档中指出的逻辑即可。
// pages/_document.js import Document from "next/document"; import {ServerStyleSheet} from "styled-components"; export default class MyDocument extends Document { static async getInitialProps(ctx) { const sheet = new ServerStyleSheet(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />), }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ), }; } finally { sheet.seal(); } } }
在更新.babelrc
和pages/_document.js
,我们现在可以开始使用 styled-components。
- 更新
styles/styled-components/StyledBookSix.js
。
styled
是一种内部实用方法,可将样式从 JavaScript 转换为实际的 CSS。 <StyledBookSix/>
可以用作任何其他 React 组件。
// styles/StyledBookSix.js import styled from "styled-components"; const StyledBookSix = styled.div` color: #fff; width: 106px; height: 448px; margin-right: 23px; background-color: rebeccapurple; `; export default StyledBookSix;
了解有关如何在 React 中使用样式化组件的更多信息。
- 在 components/BookSix.js 中导入
styles/styled-components/StyledBookSix.js
components/BookSix.js
,使用导入的 styled-components<StyledBookSix/>
。
// components/BookSix.js import StyledBookSix from "../styles/styled-components/StyledBookSix"; export default function BookSix() { return ( <StyledBookSix className="book-six"> <div className="book-info"> <p className="title">purple hibiscus</p> <p className="author">chimamanda ngozi adichie</p> </div> </StyledBookSix> ); }
第一步到第六步完成后,第六步应该样式化,书架完成:
而已。
如果一切顺利,那么您应该拥有完整的书架,其中包含等待阅读的书籍。
- 您可以在 GitHub 上获取完整代码 →
结论
在我自己使用 Next.js 时,全局样式和样式组件通常就足够了。 但毫无疑问,所有这些方法都有其优点和缺点。 当你决定使用什么方法时,请记住:最后,它都是 CSS。 在这一点上,我相信您可以确定在您的下一个项目中哪种模式最适合您。
资源
我发现要学习使用 Next.js 设置样式方法,没有比它的官方文档更好的地方了。
但也有各种样式方法的特定存储库。 您可以通过各种存储库了解更多信息,或检查更新,因为事情可能会隐身更改。
- 顺风 CSS
- CSS 模块
- 较少的
- 手写笔
- 带有情感的 Tailwind CSS
- Styletron
- 魅力
- CXS
- 阿芙罗狄蒂
- 费拉
- 样式化的 JSX