ReactでCSSを書くにはたくさんの方法があると思います。

その中でもNext.jsでそれらを使用するにはどうしたらよいかを一覧で書いてみました。

それぞれのフレームワークの記法にはあまり触れずに、Next.jsをプロダクションレディーにするための設定とGlobalなCSSの書き方に触れます。


CSS not in JS


Sass with CSS modules

Next.jsのconfigに以下を追加


next.config.js

const withSass = require('@zeit/next-sass')

module.exports = withSass({
cssModules: true
})

Sassファイルのstyles.scssを作成


styles.scss

$font-size: 50px;

.example {
font-size: $font-size;
}

コンポーネント内でclassNameとしてオブジェクトを引き出します


pages/index.js


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は効きません。


pages/_app.js

import "../styles/global.scss";


また、直書きで良いのであれば、 pages/_document.jsにテンプレートリテラルで書く方法もあります。


/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>
)
}
}


https://github.com/zeit/next.js/wiki/Global-styles-and-layouts


CSS in JS


styled-jsx

Next.jsを作ったZeitがstyled-jsxもOSSとして作っています。

なのでNext.jsではデフォルトでstyled-jsxがデフォルトでロードされていて、no configで実装が開始できます。


pages/index.js

export default () => (

<div>
Welcome to next.js!
<style jsx>{`
div {
background: red;
}
`
}</style>
</div>
);

詳しい記法などはこちらを参照して下さい。


Globalなスタイル

styled-jsx記法ではglobalというパラメータをつけると、書いたクラス名やタグがグローバルなものとして出力されます。これも同じく_app.js内で記載するとよいでしょう。


pages/_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


shell

npm i --save styled-components

npm i -D babel-plugin-styled-components


.babelrc

{

"presets": [
"next/babel"
],
"plugins": [
"styled-components"
]
}

styled-componentsをNext.jsで使用するためには、実はこれだけでは足りません。サーバーサイドレンダリングされる際にstyled-compoentnsが実行されないため、クライアントでReactが実行されてからスタイルが当たるようになっています。ですから、<head>タグにスタイルを入れるためにServerStyleSheet_document.jsで実行しましょう。こちらに例が載っています


pages/_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での開発ができるようになります。


pages/index.js

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に書くことでページ全体に適用されます。


pages/_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


shell

npm i --save @emotion/core @emotion/styled babel-plugin-emotion



.babelrc

{

"presets": [
"next/babel"
],
"plugins": [
["emotion"]
]
}

emotionはv10からno configでSSR対応までしてくれていますので以上で設定が完了です。

スタイルを当てた例が以下になります。


pages/index.js

/** @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コンポーネントを入れることで、ページ全体に適用されるスタイルが書けます。


pages/_app.js

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フレームワークを選んでいきましょう。