CSS-in-JS
警告:目前伺服器元件尚不支援需要執行階段 JavaScript 的 CSS-in-JS 函式庫。若要在伺服器元件和串流等較新的 React 功能中使用 CSS-in-JS,函式庫作者需要支援最新版本的 React,包含並行渲染。
我們正與 React 團隊合作開發上游 API,以支援 React 伺服器元件和串流架構來處理 CSS 和 JavaScript 資源。
以下函式庫在 app
目錄中的客戶端元件中受到支援(依字母順序排列)
ant-design
chakra-ui
@fluentui/react-components
kuma-ui
@mui/material
@mui/joy
pandacss
styled-jsx
styled-components
stylex
tamagui
tss-react
vanilla-extract
目前以下項目正在開發支援中:
注意事項:我們正在測試不同的 CSS-in-JS 函式庫,並將為支援 React 18 功能和/或
app
目錄的函式庫新增更多範例。
如果您想要設定伺服器組件的樣式,我們建議使用 CSS 模組 或其他輸出 CSS 檔案的解決方案,例如 PostCSS 或 Tailwind CSS。
在 app
中設定 CSS-in-JS
設定 CSS-in-JS 是一個需要三個步驟的選擇性加入程序,包含:
- 一個樣式註冊表 (style registry),用於在渲染過程中收集所有 CSS 規則。
- 新的
useServerInsertedHTML
hook,用於在任何可能使用 CSS 規則的內容之前注入這些規則。 - 一個客戶端組件,在初始伺服器端渲染期間使用樣式註冊表包裝您的應用程式。
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 參考 以了解更多資訊。
這有幫助嗎?