跳至內容

CSS-in-JS

警告:目前伺服器元件尚不支援需要執行階段 JavaScript 的 CSS-in-JS 函式庫。若要在伺服器元件和串流等較新的 React 功能中使用 CSS-in-JS,函式庫作者需要支援最新版本的 React,包含並行渲染

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

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

目前以下項目正在開發支援中:

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

如果您想要設定伺服器組件的樣式,我們建議使用 CSS 模組 或其他輸出 CSS 檔案的解決方案,例如 PostCSS 或 Tailwind CSS

app 中設定 CSS-in-JS

設定 CSS-in-JS 是一個需要三個步驟的選擇性加入程序,包含:

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

styled-jsx

在客戶端組件中使用 styled-jsx 需要使用 v5.1.0 版本。首先,建立一個新的註冊表:

app/registry.tsx
'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.dev.org.tw/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>
}

然後,使用註冊表包裝您的 根佈局

app/layout.tsx
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 或更新版本的方式範例:

首先,在 next.config.js 中啟用 styled-components。

next.config.js
module.exports = {
  compiler: {
    styledComponents: true,
  },
}

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

lib/registry.tsx
'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.dev.org.tw/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

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

在此處查看範例.

注意事項:

  • 在伺服器渲染期間,樣式將會被提取到一個全域註冊表,並添加到 HTML 的 <head> 中。這確保了樣式規則會被放置在任何可能使用它們的內容之前。未來,我們可能會使用即將推出的 React 功能來決定樣式的注入位置。
  • 在串流處理期間,每個區塊的樣式將會被收集並附加到現有的樣式中。在用戶端完成水合作用後,styled-components 將會照常接管並注入任何其他的動態樣式。
  • 我們特別在樹狀結構的頂層使用用戶端元件作為樣式註冊表,因為以這種方式提取 CSS 規則更有效率。它避免了在後續的伺服器渲染中重新生成樣式,並防止它們在伺服器元件有效負載中被發送。
  • 對於需要配置 styled-components 編譯個別屬性的進階使用案例,您可以閱讀我們的 Next.js styled-components API 參考 以了解更多資訊。