Skip to main content

JS 中的 CSS

警告:服务器组件当前不支持需要运行时 JavaScript 的 CSS-in-JS 库。将 CSS-in-JS 与服务器组件和流等较新的 React 功能一起使用需要库作者支持最新版本的 React,包括 并发渲染

¥Warning: CSS-in-JS libraries which require runtime JavaScript are not currently supported in Server Components. Using CSS-in-JS with newer React features like Server Components and Streaming requires library authors to support the latest version of React, including concurrent rendering.

我们正在与 React 团队合作开发上游 API,以处理 CSS 和 JavaScript 资源,并支持 React 服务器组件和流架构。

¥We're working with the React team on upstream APIs to handle CSS and JavaScript assets with support for React Server Components and streaming architecture.

app 目录中的客户端组件支持以下库(按字母顺序排列):

¥The following libraries are supported in Client Components in the app directory (alphabetical):

目前正在开展以下支持工作:

¥The following are currently working on support:

很高兴知道:我们正在测试不同的 CSS-in-JS 库,并将为支持 React 18 功能和/或 app 目录的库添加更多示例。

¥Good to know: We're testing out different CSS-in-JS libraries and we'll be adding more examples for libraries that support React 18 features and/or the app directory.

如果你想设置服务器组件的样式,我们建议使用 CSS 模块 或其他输出 CSS 文件的解决方案,例如 PostCSS 或 Tailwind CSS

¥If you want to style Server Components, we recommend using CSS Modules or other solutions that output CSS files, like PostCSS or Tailwind CSS.

app 中配置 CSS-in-JS

¥Configuring CSS-in-JS in app

配置 CSS-in-JS 是一个三步选择过程,涉及:

¥Configuring CSS-in-JS is a three-step opt-in process that involves:

  1. 用于收集渲染中所有 CSS 规则的样式注册表。

    ¥A style registry to collect all CSS rules in a render.

  2. 新的 useServerInsertedHTML 钩子可在任何可能使用规则的内容之前注入规则。

    ¥The new useServerInsertedHTML hook to inject rules before any content that might use them.

  3. 一个客户端组件,在初始服务器端渲染期间使用样式注册表封装你的应用。

    ¥A Client Component that wraps your app with the style registry during initial server-side rendering.

styled-jsx

在客户端组件中使用 styled-jsx 需要使用 v5.1.0。首先,创建一个新的注册表:

¥Using styled-jsx in Client Components requires using v5.1.0. First, create a new registry:

'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
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://react.nodejs.cn/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>
}
'use client'

import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'

export default function StyledJsxRegistry({ children }) {
// Only create stylesheet once with lazy initial state
// x-ref: https://react.nodejs.cn/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>
}

然后,用注册表封装你的 根布局

¥Then, wrap your root layout with the registry:

import StyledJsxRegistry from './registry'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}
import StyledJsxRegistry from './registry'

export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}

在此处查看示例

¥View an example here.

样式组件

¥Styled Components

以下是如何配置 styled-components@6 或更高版本的示例:

¥Below is an example of how to configure styled-components@6 or newer:

首先,在 next.config.js 中启用样式组件。

¥First, enable styled-components in next.config.js.

module.exports = {
compiler: {
styledComponents: true,
},
}

然后,使用 styled-components API 创建一个全局注册表组件来收集渲染期间生成的所有 CSS 样式规则,以及一个返回这些规则的函数。然后使用 useServerInsertedHTML 钩子将注册表中收集的样式注入到根布局中的 <head> HTML 标签中。

¥Then, use the styled-components API to create a global registry component to collect all CSS style rules generated during a render, and a function to return those rules. Then use the useServerInsertedHTML hook to inject the styles collected in the registry into the <head> HTML tag in the root layout.

'use client'

import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://react.nodejs.cn/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())

useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})

if (typeof window !== 'undefined') return <>{children}</>

return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}
'use client'

import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

export default function StyledComponentsRegistry({ children }) {
// Only create stylesheet once with lazy initial state
// x-ref: https://react.nodejs.cn/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())

useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})

if (typeof window !== 'undefined') return <>{children}</>

return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}

使用样式注册表组件封装根布局的 children

¥Wrap the children of the root layout with the style registry component:

import StyledComponentsRegistry from './lib/registry'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
import StyledComponentsRegistry from './lib/registry'

export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}

在此处查看示例

¥View an example here.

很高兴知道:

¥Good to know:

  • 在服务器渲染期间,样式将被提取到全局注册表并刷新到 HTML 的 <head>。这可确保样式规则放置在可能使用它们的任何内容之前。将来,我们可能会使用即将推出的 React 功能来确定在何处注入样式。

    ¥During server rendering, styles will be extracted to a global registry and flushed to the <head> of your HTML. This ensures the style rules are placed before any content that might use them. In the future, we may use an upcoming React feature to determine where to inject the styles.

  • 在流式传输期间,每个块的样式将被收集并附加到现有样式中。客户端水化完成后,styled-components 将照常接管并注入任何进一步的动态样式。

    ¥During streaming, styles from each chunk will be collected and appended to existing styles. After client-side hydration is complete, styled-components will take over as usual and inject any further dynamic styles.

  • 我们专门在样式注册表树的顶层使用客户端组件,因为通过这种方式提取 CSS 规则会更有效。它避免在后续服务器渲染上重新生成样式,并防止它们在服务器组件有效负载中发送。

    ¥We specifically use a Client Component at the top level of the tree for the style registry because it's more efficient to extract CSS rules this way. It avoids re-generating styles on subsequent server renders, and prevents them from being sent in the Server Component payload.

  • 对于需要配置样式组件编译的各个属性的高级用例,你可以阅读我们的 Next.js 样式组件 API 参考 以了解更多信息。

    ¥For advanced use cases where you need to configure individual properties of styled-components compilation, you can read our Next.js styled-components API reference to learn more.