OpenAINext.js2019/03/28 12:50

Styling Next.js with Styled JSX

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

openaijamodel: gpt-5-mini-2025-08-07

Styled JSXでNext.jsをスタイリングする

Key Points

  • 組み込みで使える
  • コンポーネント単位のスコープ
  • 動的スタイル対応

Summary

Styled JSXはNext.jsに組み込まれたCSS-in-JSライブラリで、コンポーネント単位でスコープされた標準CSSを書けます。基本はコンポーネント内に<style jsx>を置くこと。グローバルスタイルは<style jsx global>で、アプリ全体にはレイアウトコンポーネントやpages/_app.jsを通して適用します。外部ファイルへ分離するにはstyled-jsx/cssを使い、:global()で子コンポーネントの一部を上書きできます。動的なスタイルはpropsを使って切り替え、静的/動的部分を分けておくと再レンダリングコストを抑えられます。

Key Points

  • Next.jsはデフォルトでStyled JSXを提供。使用は<style jsx>をコンポーネントのルートに置くだけ。
  • グローバルCSSは<style jsx global>を使い、共通はLayoutやpages/_app.jsでまとめて読み込む。
  • 外部スタイルはimport css from 'styled-jsx/css'で定義→<style jsx>{globalStyles}</style>で適用。
  • 子コンポーネントの一部だけ上書きする場合は:global(.class)を使う(ワンオフのグローバルセレクタ)。
  • 動的スタイルはpropsを使って条件分岐するか、クラス切替で実装。動的部分は別の<style jsx>に分離すると効率的。
  • テーマは変数オブジェクト(colors, fontFamily等)を作成してimportし、スタイル内で参照する。

実装上の注意: 汎用セレクタでもスコープされるため意図しない影響を避けられるが、グローバル適用や外部子の上書きは明示的に行うこと。

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

openaijamodel: gpt-5-mini-2025-08-07

Styled JSXでNext.jsをスタイリング

ブログに戻る — 2019年3月28日(木)

Styled JSXでNext.jsをスタイリング

Styled JSXはコンポーネント向けにカプセル化されスコープされたCSSを書けるCSS-in-JSライブラリです。あるコンポーネントに追加したスタイルは他のコンポーネントに影響を与えないため、意図しない副作用を気にせずにスタイルの追加・変更・削除ができます。

はじめに

Next.jsにはデフォルトでStyled JSXが含まれているため、既存のReact要素内に <style jsx> タグを追加してCSSを書くだけで開始できます。例えば:

pages/index.js
function Home () {
  return (
    <div className="container">
      <h1>Hello Next.js</h1>
      <p>Let's explore different ways to style Next.js apps</p>
      <style jsx>{ `
        .container { margin: 50px; }
        p { color: blue; }
      ` }</style>
    </div>
  );
}
export default Home;

この例ではコンポーネントのコンテナ要素と段落のためのスタイルを含めています。汎用的なセレクタを使っていても、これらのスタイルは他のコンポーネントの同名のクラスや <p> タグに影響しません。Styled JSXはスタイルをこのコンポーネントにのみスコープする(スタイルを適用する要素に追加のユニークなクラス名を付与する)ためです。

<style jsx> 属性を <style> 要素に追加するだけで、標準的なCSSを書け、ベンダープレフィックス付与やコンポーネント単位での自動スコープが行われます。<style jsx> 要素はコンポーネントのルート要素の中に置くべきです。

グローバルスタイルの追加

ほとんどのプロジェクトでは body 要素やリセット用のグローバルスタイルが必要になります。Styled JSXでは <style jsx global> を使ってグローバルスタイルを追加できます。例えば:

pages/index.js
function Home () {
  return (
    <div className="container">
      <h1>Hello Next.js</h1>
      <p>Let's explore different ways to style Next.js apps</p>
      <style jsx>{ `
        .container { margin: 50px; }
        p { color: blue; }
      ` }</style>
      <style jsx global>{ `
        p { font-size: 20px; }
      ` }</style>
    </div>
  );
}
export default Home;

この例ではこのページ内のすべての <p> タグに対して font-size: 20px が適用されます。アプリ内のすべてのページにグローバルスタイルを適用したい場合は、グローバルスタイルを含むレイアウトコンポーネントを作成し、すべてのページをそのレイアウトでラップするのが良い方法です。レイアウトコンポーネントを使うことで、あるページ群には特定のスタイルを適用しつつ、別のページには別のスタイルを与える柔軟性が得られます。

components/Layout.js
function Layout (props) {
  return (
    <div className="page-layout">
      {props.children}
      <style jsx global>{ `
        body {
          margin: 0;
          padding: 0;
          font-size: 18px;
          font-weight: 400;
          line-height: 1.8;
          color: #333;
          font-family: sans-serif;
        }
        h1 { font-weight: 700; }
        p { margin-bottom: 10px; }
      ` }</style>
    </div>
  );
}
export default Layout;

Next.jsでは pages/_app.js にカスタムAppコンポーネントを作成し、Layoutを読み込んでレンダーに追加することで、全ページでレイアウトを一度だけ読み込むことができます:

pages/_app.js
import React from 'react';
import App, { Container } from 'next/app';
import Layout from '../components/Layout';

class MyApp extends App {
  render () {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </Container>
    );
  }
}
export default MyApp;

外部ファイルにスタイルを書く

コンポーネントの外部にスタイルを分離して書くこともできます。例えば、Layoutコンポーネントからグローバルスタイルを別ファイルに移動するには:

styles/global.js
import css from 'styled-jsx/css';
export default css.global `
  body {
    margin: 0;
    padding: 0;
    font-size: 18px;
    font-weight: 400;
    line-height: 1.8;
    color: #333;
    font-family: sans-serif;
  }
  h1 { font-weight: 700; }
  p { margin-bottom: 10px; }
`;

そしてそのスタイルをLayoutにインポートして使います:

components/Layout.js
import globalStyles from '../styles/global.js';
function Layout (props) {
  return (
    <div className="page-layout">
      {props.children}
      <style jsx global>{globalStyles}</style>
    </div>
  );
}
export default Layout;

一時的なグローバルセレクタ

<style jsx> でコンポーネントに追加したスタイルはそのコンポーネント内の要素にのみ影響し、子コンポーネントには影響を与えません。場合によっては子コンポーネントの特定のスタイルを上書きしたいことがあります。そのような場合、Styled JSXは :global() を提供しており、ワンオフのグローバルセレクタにアクセスできます。例えば、<Widget> コンポーネントに btn クラスのボタンがあり、ホームページ上でそのボタンの色だけを変えたい場合は次のようにします:

pages/index.js
import Widget from '../components/Widget';
function Home () {
  return (
    <div className="container">
      <h1>Hello Next.js</h1>
      <Widget />
      <style jsx>{ `
        .container { margin: 50px; }
        .container :global(.btn) { background: #000; color: #fff; }
      ` }</style>
    </div>
  );
}
export default Home;

この例では .container :global(.btn) により、Widget の内部にある .btn に対してのみスタイルを適用しています。

動的スタイル

コンポーネントのスタイルを props に基づいて変更できることはCSS-in-JSの大きな利点のひとつです。Styled JSXでは次のようにできます:

components/Alert.js
function Alert (props) {
  return (
    <div className="alert">
      {props.children}
      <style jsx>{ `
        .alert { display: inline-block; padding: 20px; border-radius: 8px; }
      ` }</style>
      <style jsx>{ `
        .alert { background: ${props.type == 'warning' ? '#fff3cd' : '#eee'}; }
      ` }</style>
    </div>
  );
}
export default Alert;

例えば <Alert type="warning">This is an important message</Alert> のように typewarning を渡すと、オレンジ色の背景になります。type を指定しない場合はデフォルトのグレー背景になります。

動的なスタイルは別の <style jsx> タグに分けて置くことを推奨します。これは必須ではありませんが、静的な部分と動的な部分を分離することで props が変化したときに再計算されるのを最小限にできます。

別のアプローチとして、props の値に応じて異なるクラス名を適用する方法もあります:

components/Alert.js
function Alert (props) {
  return (
    <div className={props.type == 'warning' ? 'alert warning' : 'alert'}>
      {props.children}
      <style jsx>{ `
        .alert { display: inline-block; padding: 20px; border-radius: 8px; background: #eee; }
        .alert.warning { background: #fff3cd; }
      ` }</style>
    </div>
  );
}
export default Alert;

サイトテーマの作成

テーマはアプリでよく使う変数をまとめたシンプルなオブジェクトにできます:

styles/theme.js
const theme = {
  fontFamily: {
    sansSerif: '-apple-system, "Helvetica Neue", Arial, sans-serif',
    mono: 'Menlo, Monaco, monospace',
  },
  colors: {
    text: '#333',
    background: '#fff',
    link: '#1eaaf1',
    linkHover: '#0d8ecf',
    border: '#ddd',
    warning: '#fff3cd',
    success: '#d4edda',
  },
};
export default theme;

このテーマファイルをコンポーネントでインポートし、ハードコードされた値を変数に置き換えます:

components/Layout.js
import theme from '../styles/theme';
function Layout (props) {
  return (
    <div className="page-wrapper">
      {props.children}
      <style jsx global>{ `
        body { background: ${theme.colors.background}; color: ${theme.colors.text}; font-family: ${theme.fontFamily.sansSerif}; }
      ` }</style>
      <style jsx global>{ `
        body { margin: 0; padding: 0; font-size: 18px; font-weight: 400; line-height: 1.8; }
        h1 { font-weight: 700; }
        p { margin-bottom: 10px; }
      ` }</style>
    </div>
  );
}
export default Layout;

components/Alert.js
import theme from '../styles/theme';
function Alert (props) {
  return (
    <div className="alert">
      {props.children}
      <style jsx>{ `
        .alert { display: inline-block; padding: 20px; border-radius: 8px; }
      ` }</style>
      <style jsx>{ `
        .alert { background: ${props.type == 'warning' ? theme.colors.warning : theme.colors.light}; }
      ` }</style>
    </div>
  );
}
export default Alert;

まとめ

本投稿ではStyled JSXの基本的な使い方を紹介しました。追加の機能について詳しくは、GitHub をチェックしてください。