ReactでCSSを書くにはたくさんの方法があると思います。
その中でもNext.jsでそれらを使用するにはどうしたらよいかを一覧で書いてみました。
それぞれのフレームワークの記法にはあまり触れずに、Next.jsをプロダクションレディーにするための設定とGlobalなCSSの書き方に触れます。
CSS not in JS
Sass with CSS modules
Next.jsのconfigに以下を追加
const withSass = require('@zeit/next-sass')
module.exports = withSass({
cssModules: true
})
Sassファイルのstyles.scssを作成
$font-size: 50px;
.example {
font-size: $font-size;
}
コンポーネント内でclassName
としてオブジェクトを引き出します
import css from "../styles.scss"
export default () => <div className={css.example}>Hello World!</div>
これでスコープドなCSSが書けます。
Globalなスタイル
Next.jsではクライアントの全ページで使用されるのはpages/_app.js
なので、こちらでimportすればOKです。pages/_document.js
でのimportは効きません。
import "../styles/global.scss";
また、直書きで良いのであれば、 pages/_document.js
にテンプレートリテラルで書く方法もあります。
import Document, { Head, Main, NextScript } from 'next/document'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<html>
<Head>
{/* このようにテンプレートリテラルで直書きする */}
<style>{`body { margin: 0 } /* custom! */`}</style>
</Head>
<body className="custom_class">
<Main />
<NextScript />
</body>
</html>
)
}
}
CSS in JS
styled-jsx
Next.jsを作ったZeitがstyled-jsxもOSSとして作っています。
なのでNext.jsではデフォルトでstyled-jsxがデフォルトでロードされていて、no configで実装が開始できます。
export default () => (
<div>
Welcome to next.js!
<style jsx>{`
div {
background: red;
}
`}</style>
</div>
);
Globalなスタイル
styled-jsx記法ではglobalというパラメータをつけると、書いたクラス名やタグがグローバルなものとして出力されます。これも同じく_app.js
内で記載するとよいでしょう。
import React from "react";
import App, { Container } from "next/app";
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Component {...pageProps} />
<style jsx global>{`
body {
background-color: green;
}
`}</style>
</Container>
);
}
}
styled-components
npm i --save styled-components
npm i -D babel-plugin-styled-components
{
"presets": [
"next/babel"
],
"plugins": [
"styled-components"
]
}
styled-componentsをNext.jsで使用するためには、実はこれだけでは足りません。サーバーサイドレンダリングされる際にstyled-compoentnsが実行されないため、クライアントでReactが実行されてからスタイルが当たるようになっています。ですから、<head>
タグにスタイルを入れるためにServerStyleSheet
を_document.js
で実行しましょう。こちらに例が載っています
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps (ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
ctx.renderPage = () => originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
})
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps, styles: [...initialProps.styles, ...sheet.getStyleElement()] }
}
}
以上でstyled-componentsでの開発ができるようになります。
import React from 'react'
import styled from 'styled-components'
const Title = styled.h1`
color: red;
font-size: 50px;
`
export default () => <Title>My page</Title>
Globalなスタイル
createGlobalStyle
や、ThemeProvider
など全体に関わるものは_app.js
に書くことでページ全体に適用されます。
import React from "react";
import App, { Container } from "next/app";
import { createGlobalStyle, ThemeProvider } from "styled-components";
const GlobalStyle = createGlobalStyle`
body {
background: ${p => p.theme.backgroundColor};
color: red;
}
`;
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<ThemeProvider theme={{ backgroundColor: "yellow" }}>
<Container>
<GlobalStyle />
<Component {...pageProps} />
</Container>
</ThemeProvider>
);
}
}
emotion
npm i --save @emotion/core @emotion/styled babel-plugin-emotion
{
"presets": [
"next/babel"
],
"plugins": [
["emotion"]
]
}
emotionはv10からno configでSSR対応までしてくれていますので以上で設定が完了です。
スタイルを当てた例が以下になります。
/** @jsx jsx */
import { jsx, css } from "@emotion/core";
import styled from "@emotion/styled";
const style = css`
color: hotpink;
`;
const StyledParagraph = styled.p`
color: red;
font-size: 40px;
`;
export default () => (
<div css={style}>
Welcome to
<StyledParagraph>Next.js!</StyledParagraph>
</div>
);
Globalなスタイル
例に漏れず、pages/_app.js
にGlobalコンポーネントを入れることで、ページ全体に適用されるスタイルが書けます。
import React from "react";
import App, { Container } from "next/app";
import { css, Global } from "@emotion/core";
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Global
styles={css`
body {
background: green;
}
`}
/>
<Component {...pageProps} />
</Container>
);
}
}
おわりに
CSSは、たかがCSSされどCSSだと思います。プロジェクトに合ったCSSフレームワークを選んでいきましょう。