CSS-in-JS

警告:目前伺服器元件 (Server Components) 不支援需要執行時 JavaScript 的 CSS-in-JS 函式庫。將 CSS-in-JS 與 React 新功能 (如伺服器元件和串流) 一起使用,需要函式庫作者支援最新版本的 React,包括 並行渲染 (concurrent rendering)

我們正與 React 團隊合作開發上游 API,以處理 CSS 和 JavaScript 資源,並支援 React 伺服器元件和串流架構。

以下函式庫在 app 目錄中的客戶端元件 (Client Components) 受支援 (按字母順序排列):

以下函式庫目前正在開發支援:

須知:我們正在測試不同的 CSS-in-JS 函式庫,並將為支援 React 18 功能和/或 app 目錄的函式庫新增更多範例。

如果您想為伺服器元件添加樣式,建議使用 CSS 模組 (CSS Modules) 或其他輸出 CSS 檔案的解決方案,如 PostCSS 或 Tailwind CSS

app 中配置 CSS-in-JS

配置 CSS-in-JS 是一個三步驟的選擇性過程,包括:

  1. 一個 樣式註冊表 (style registry) 用於收集渲染中的所有 CSS 規則。
  2. 新的 useServerInsertedHTML 鉤子 (hook) 用於在可能使用這些規則的任何內容之前注入規則。
  3. 一個客戶端元件,在初始伺服器端渲染期間用樣式註冊表包裹您的應用程式。

styled-jsx

在客戶端元件中使用 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
}) {
  // 僅使用惰性初始狀態建立樣式表一次
  // 參考: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>
}

然後,用註冊表包裹您的 根佈局 (root layout)

import StyledJsxRegistry from './registry'

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

查看範例

Styled Components

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

首先,使用 styled-components API 建立一個全域註冊表元件,用於收集渲染期間生成的所有 CSS 樣式規則,以及一個返回這些規則的函式。然後使用 useServerInsertedHTML 鉤子將註冊表中收集的樣式注入到根佈局的 <head> HTML 標籤中。

'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
}) {
  // 僅使用惰性初始狀態建立樣式表一次
  // 參考:https://reactjs.org/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

import StyledComponentsRegistry from './lib/registry'

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

查看範例

須知

  • 在伺服器渲染期間,樣式將被提取到全域註冊表並刷新到 HTML 的 <head> 中。這確保了樣式規則在使用它們的任何內容之前被放置。未來,我們可能會使用即將推出的 React 功能來確定注入樣式的位置。
  • 在串流期間,每個區塊的樣式將被收集並附加到現有樣式中。客戶端水合 (hydration) 完成後,styled-components 將像往常一樣接管並注入任何進一步的動態樣式。
  • 我們特別在樹的頂層使用客戶端元件作為樣式註冊表,因為這樣提取 CSS 規則更有效率。它避免了在後續伺服器渲染時重新生成樣式,並防止它們被發送到伺服器元件負載中。

On this page