介绍
Next.js (React) 和Nuxt.js (Vue) 有助于简化将应用视图渲染到服务器的过程。
您仍然需要一个解决方案,以适应开发的方式在 React 组件中渲染 CSS。您还需要一个在服务器上呈现 CSS 的解决方案,以便样式可用。
在本文中,我们将讨论渲染 CSS 的挑战,然后在 Next.js 项目中在服务器上使用styled-components
和styled-jsx
。
先决条件
要完成本教程,您需要:
- Node.js 的本地开发环境。遵循如何安装 Node.js 并创建本地开发环境。
本教程已通过 Node v16.2.0、npm
v7.14.0、react
v17.0.2、react-dom
v17.0.2、next
v10.2.3 和styled-compnents
v5.3.0 验证。
理解 React 中的样式模式
在 React 中编写 CSS 的常用方法很少,它们都有效。根据您的情况,您可以通过以下方式之一将样式应用到 React 应用程序:
全局样式
全局样式是包含本地或内容交付网络 (CDN) 托管样式表的模式。
下面是一个例子:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
这是不太受欢迎的样式模式,因为它不鼓励组件重用。它也不鼓励样式组合。
这些 CSS 规则不直接作用于特定元素或组件。当组件以通过导入、嵌套或扩展未预料到的方式进行交互时,很可能会发生冲突。
但是,在某些情况下,您可以全局包含样式,例如字体包含和 CSS 重置和默认值。
内联样式
内联样式使用 Reactstyle
属性直接应用于 DOM 元素或 React 组件。实现很像 HTML 内联style
属性,但使用 JavaScript element.style
API。
下面是一个例子:
const titleStyle = {
fontSize: '4rem';
lineHeight: '1.6';
color: '#222';
}
<h1 style={titleStyle} {...props}>{props.children}<h1>
这种模式鼓励样式和组件组合以及重用。
但是,内联样式并没有为您提供一种方法来处理具有伪类和目标伪元素的焦点状态悬停。对于更大和复杂的项目,您可能需要更强大的解决方案。
组件样式
组件样式鼓励重用并帮助您更好地组合样式和组件。您将需要一个实用程序或库来帮助您完成此操作。样式加载器、styled-components
、Glamour等是支持组件样式的工具示例。
styled-components
是实现 CSS-in-JS 的流行解决方案。它们是内联组件样式,但更有能力执行复杂(伪)选择、嵌套等操作。
步骤 1 – 设置项目
首先,打开您的终端并为您的项目创建一个新文件夹:
- mkdir css-ssr-next-example
接下来,切换到新的项目目录:
- cd css-ssr-next-example
然后运行以下命令对其进行初始化:
- npm init -y
这将创建一个package.json
文件,您将使用该文件来跟踪依赖项。
然后,安装 Next.js、React 和 React DOM:
- npm install next@10.2.3 react@17.0.2 react-dom17.0.2
此时,您将拥有一个包含 Next.js、React 和 React DOM 的新项目。
注意:自发布以来,创建 Next.js 项目的更现代方法可以使用create-next-app
.
现在,更新package.json
以使用dev
脚本启动 Next.js 应用程序:
{
"name": "css-ssr-next-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "next"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"next": "^10.2.3",
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}
然后,创建一个pages
目录:
- mkdir pages
在这个目录下,添加一个index.js
文件,内容如下:
import React from 'react';
const Index = () => <h1>Hi, new Next.js project</h1>;
export default Index;
现在运行dev
脚本来启动服务器:
- npm run dev
如果您localhost:3000
在网络浏览器中打开,您将看到:
OutputHi, new Next.js project
首先,使用Head
Next 中的组件来规范化样式normalize.css
:
import React from 'react';
import Head from 'next/head';
const Index = () =>
<div>
<Head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" />
</Head>
<h1>Hi, new Next.js project</h1>
</div>;
export default Index;
接下来,static
在 Next.js 项目的根目录上创建一个文件夹:
- mkdir static
在此目录中,添加base.css
具有以下 CSS 内容的文件:
body {
font-family: 'Raleway', sans-serif;
color: #222;
}
base.css
在索引页面导入文件:
// ...
<Head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" />
<link rel="stylesheet" href="/static/base.css" />
</Head>
// ...
在浏览器中,字体将从默认字体明显更改为 Raleway。
此时,您有一个具有全局样式的 Next.js 项目。
第 2 步 – 使用样式化组件
让我们使用styled-components
库来设置组件的样式。
首先,安装styled-components
:
- npm install styled-components@5.3.0
接下来,创建一个components
目录:
mkdir components
在此目录中,添加一个Button.js
文件并使用以下内容更新该文件:
import React from 'react';
import styled from 'styled-components';
const ButtonBase = (props) => <button {...props}>{props.children}</button>
const Button = styled(ButtonBase)`
/* Rectangle 2: */
background: #0077E2;
box-shadow: 0 2px 7px 0 rgba(120,137,149,0.25);
border-radius: 3px;
text-transform: uppercase;
padding: 10px;
color: #fff;
border: #0077E2;
`
export default Button;
我们正在使用styled-components
import asstyled
来样式 a Button
。ButtonBase
返回按钮的骨架,同时Button
返回带有样式的组件ButtonBase
。
Button
在索引页面导入并使用组件:
import React from 'react';
import Head from 'next/head';
import Button from '../components/Button'
const Index = () => <div>
<Head>
....
</Head>
<h1>Hi, new Next.js project</h1>
<Button>Clicker</Button>
</div>;
export default Index;
保存更改并在浏览器中观察应用程序。文本下方将是一个新样式的按钮。
但是,在硬刷新后,按钮的样式不再符合预期。
按钮样式似乎丢失了,但不知何故,基本样式完好无损。使用 Web 开发人员工具检查页面源。
内容呈现给服务器,但它不会在页面上与按钮相关的任何位置显示任何样式。另一方面,从应用的字体样式中可以看出,我们知道外部文件已成功渲染到服务器。
那么组件样式出了什么问题呢?看一下控制台:
OutputWarning: Prop `className` did not match. Server: "sc-gtsrHT kbmjhF" Client: "sc-bdnxRM kbyRfM"
您可以观察到一个错误,显示类名中的不匹配。这是因为,当您重新加载时,首先从服务器获取内容。
不幸的是,styled-components
不会呈现给服务器,这使它们当时不可用。
注:自发布以来,styled-components
支持服务端渲染。
您也可以参考Next.js 的with-styled-components
示例。
让我们来看看一个解决方案。
第 3 步 – 使用样式化 JSX
致力于 Next.js 的团队引入了一个名为styled-jsx
帮助控制缓解此问题的库。该库确保您编写的样式在服务器和浏览器上呈现,而不仅仅是在浏览器上呈现。
它已经与 Next.js 捆绑在一起,所以你不需要安装任何东西。
重新访问Button
组件并修改它以使用styled-jsx
:
import React from 'react';
const Button = props => (
<button {...props}>
{props.children}
<style jsx>{`
background: #0077e2;
box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25);
border-radius: 3px;
text-transform: uppercase;
padding: 10px;
color: #fff;
border: #0077e2;
`}</style>
</button>
);
export default Button;
在我们想要设置样式的组件中根元素的结束标记之前,您可以创建一个style
具有该jsx
属性的元素。在style
元素中,打开一个包含模板字符串的花括号。字符串应该是有效的 CSS 样式和服务器作为您的组件样式。
styled-jsx
如果您的组件不是仅由一个元素组成,您还可以使用选择器:
import React from 'react';
const TitleAndButton = props => (<div {...props}>
<h1 className="title">Hi Title</h1>
<button>Clicker</button>
<style jsx>{`
h1.title {
color: #222
}
button {
background: #0077e2;
box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25);
border-radius: 3px;
text-transform: uppercase;
padding: 10px;
color: #fff;
border: #0077e2;
}
`}</style>
</div>);
export default TitleAndButton;
现在,您可以TitleAndButton
在“索引”页面中导入和使用该组件。这两个元素都将按预期设置样式。
注意:您也可以参考Next.js 的with-styled-jsx
示例。
styled-jsx
是在 Next.js 项目中将样式渲染到服务器的一种方法。
结论
在本文中,您了解了渲染 CSS 的挑战,然后在 Next.js 项目中使用styled-components
和styled-jsx
在服务器上。
如果您想了解有关 Next.js 的更多信息,请尝试我们的Next.js技术入门讲座,或查看我们的 Next.js 主题页面以获取练习和编程项目。