如何使用 CSS-in-JS 函式庫
警告:在 Next.js 中使用 CSS-in-JS 搭配 React 新功能(如伺服器元件和串流)需要函式庫作者支援最新版本的 React,包括 並行渲染 (concurrent rendering)。
以下函式庫在 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
目錄的函式庫新增更多範例。
在 app
中設定 CSS-in-JS
設定 CSS-in-JS 是一個三步驟的選擇性過程,包括:
- 一個 樣式註冊表 (style registry) 來收集渲染中的所有 CSS 規則。
- 新的
useServerInsertedHTML
鉤子 (hook) 來在可能使用這些規則的任何內容之前注入規則。 - 一個客戶端元件,在初始伺服器端渲染期間用樣式註冊表包裹您的應用程式。
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>
}
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
export default function StyledJsxRegistry({ children }) {
// 僅使用延遲初始狀態建立樣式表一次
// 參考: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>
)
}
import StyledJsxRegistry from './registry'
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}
查看範例。
Styled Components
以下是設定 styled-components@6
或更新版本的範例:
首先,在 next.config.js
中啟用 styled-components。
module.exports = {
compiler: {
styledComponents: true,
},
}
然後,使用 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>
)
}
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({ children }) {
// 僅使用延遲初始狀態建立樣式表一次
// 參考: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>
)
}
import StyledComponentsRegistry from './lib/registry'
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
查看範例。
須知:
- 在伺服器渲染期間,樣式將被提取到全域註冊表中並刷新到 HTML 的
<head>
中。這確保了樣式規則被放置在可能使用它們的任何內容之前。未來,我們可能會使用即將推出的 React 功能來確定注入樣式的位置。- 在串流期間,每個區塊的樣式將被收集並附加到現有樣式中。客戶端水合 (hydration) 完成後,
styled-components
將像往常一樣接管並注入任何進一步的動態樣式。- 我們特別在樹的頂層使用客戶端元件作為樣式註冊表,因為這樣提取 CSS 規則更有效率。它避免了在後續的伺服器渲染上重新生成樣式,並防止它們被發送到伺服器元件載荷中。
- 對於需要設定 styled-components 編譯的個別屬性的進階用例,您可以閱讀我們的 Next.js styled-components API 參考 以了解更多資訊。