クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【React】styled-componentsでCSS in JSを事始める

Reactの続きです。前回はCSS ModulesでCSSとSass(SCSS)のローカルスコープを作りました。今回はstyled-componentsでCSS in JSを事始めてみます。CSS Modulesと同様にランダムな文字列がclass名が振られる形ですが、CSSファイル読み込みではなくJSファイル内でCSSを設定できます。それではいきましょう!

【目次】

※参考:前回記事
【React】CSS ModulesでCSSとSass(SCSS)のローカルスコープを作る - クモのようにコツコツと

※参考:Reactを習得するためにやったことまとめ
qiita.com

前回のおさらい

CSS Modules事始め。CSSだけでなくSass(SCSS)でもローカルスコープが作れた!

https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201211/20201211064543.jpg

詳細は前回の記事を参照。

※参考:【React】CSS ModulesでCSSとSass(SCSS)のローカルスコープを作る - クモのようにコツコツと

その他のReactのCSS設定方法

※参考:ReactのCSS設定方法について調べたこと(className属性、style属性、CSS Modules、CSS in JS、UIフレームワーク) - クモのようにコツコツと

CSS in JSとは

CSS in JSはReactのCSS設定方法の一つでCSS構文の形でJS内に設定する方法。

※参考:ReactのCSS設定方法について調べたこと(className属性、style属性、CSS Modules、CSS in JS、UIフレームワーク) - クモのようにコツコツと

styled-componentsがよく使われている。

※参考:styled-components

styled-componentsの参考記事

※参考:styled-componentsの採用と既存資産を捨てた理由 - Cybozu Inside Out | サイボウズエンジニアのブログ
※参考:Free-Style のススメ ~ CSS Modules は解決策ではない - Qiita
※参考:CSS in JS(Elm)したら想像以上に良かった - ジンジャー研究室

Create React Appをインストール

今回もCreate React App環境で導入したい。こちらの記事を参考に。

※参考:React: styled-componentsでスタイルをJavaScriptの中に定める - Qiita

まずはCreate React Appのインストール。プロジェクト名は「css-in-js-test」にする。

$ npx create-react-app css-in-js-test

「css-in-js-test」というフォルダが作られる

フォルダに移動

$ cd css-in-js-test

Create React Appを起動

$ npm start

ブラウザのlocalhostの3000番が開く
f:id:idr_zz:20201215062707j:plain
Reactロゴがクルクル!

「Control + C」でいったん停止する。

styled-componentsインストール

次に「styled-components」をインストールする

$ npm install --save styled-components

package.jsonを確認

  "dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.2.2",
    "@testing-library/user-event": "^12.5.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "styled-components": "^5.2.1", // 追加!
    "web-vitals": "^0.2.4"
  },

追加された!

styled-components設定

styled-componentsをインポート

前回のCSS Modulesと同様に「App.js」で設定する。

※参考:【React】CSS ModulesでCSSとSass(SCSS)のローカルスコープを作る - クモのようにコツコツと

「App.js」の冒頭でstyled-componentsをインポートする。

import styled from 'styled-components';

styledという名前で。

テンプレートリテラル

このような形で設定する。

const コンポーネント名 = styled.セレクタ`
  プロパティ: 値;
`;
  • 変数名がコンポーネント名になる
  • インポート名styledにピリオドでセレクタをつなげる
  • テンプレートリテラル(` `)で囲った中にCSSの設定を書く

「テンプレートリテラル」はCSS in JS独自の書き方ではなくJSに元々ある複数行を挿入するための書き方のようだ!

テンプレートリテラルは、組み込み式を扱うことができる文字列リテラルです。複数行の文字列や文字列挿入機能を使用することができます。

※参考:テンプレートリテラル (テンプレート文字列) - JavaScript | MDN

styled-componentsを設定

このように設定してみた

const CssInJsTest = styled.p`
  color: red;
`;
  • CssInJsTestというコンポーネントがpタグになる想定
  • 文字色を赤に

コンポーネント設定

App()の中でCssInJsTestコンポーネントを設定する

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <!-- 中略 -->
        <CssInJsTest>
          CSS in JSテストですと。
        </CssInJsTest>
      </header>
    </div>
  );
}

中に「CSS in JSテストですと。」というテキストを入れている。

動作確認

Create React Appを起動

$ npm start

でけた! f:id:idr_zz:20201215065944j:plain

変数を使う

プレースホルダー

次に、CSSスタイルの中に変数を使ってみたい。色やサイズなど共通化したい値はあると思うので。

変数は「プレースホルダー」を使う。

const コンポーネント名 = styled.セレクタ`
  プロパティ: ${変数名};
`;

「プレースホルダー」もCSS in JSの書き方ではなくJSに元々ある書き方!

テンプレートリテラルにはプレースホルダーを含めることができます。プレースホルダーはドル記号と波括弧 (${expression}) で示されます。

※参考:テンプレートリテラル (テンプレート文字列) - JavaScript | MDN

変数を設定

このように設定した。

const keyColor = 'yellow';

const CssInJsTest2 = styled.p`
  color: ${keyColor};
`;
  • 変数keyColorの値をyellow
  • CssInJsTest2コンポーネントはpタグ
  • 文字色をkeyColor

さっきとは別名のコンポーネントを新たに作った。うまくいけば文字色は黄色になるはず。

コンポーネント設定

CssInJsTest2コンポーネントを設定

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <!-- 中略 -->
        <CssInJsTest>
          CSS in JSテストですと。
        </CssInJsTest>
        <CssInJsTest2>
          CSS in JSテスト2ですと。
        </CssInJsTest2>
      </header>
    </div>
  );
}

CssInJsTestコンポーネントの下に配置。テキストは「CSS in JSテスト2ですと。」

動作確認

ブラウザを見ると
f:id:idr_zz:20201215071232j:plain おお、黄色い文字が表示されている!!

擬似クラス(:hover)の設定

擬似クラスの書き方(&)

次に擬似クラスを設定してみる。入れ子構造で&で繋ぐ

const コンポーネント名 = styled.セレクタ`
  プロパティ: 値;
  &:擬似クラス {
    プロパティ: 値;
  }
`;

※参考:styled-components: API Reference

この入れ子構造や&でつなぐ書き方はSass(SCSS)と同じ!

※参考:【メタ言語】BEMによるclass名をSass(SCSS)とEJSで書いてみる(モジュール事始め) - クモのようにコツコツと

擬似クラス(:hover)を設定

CssInJsTest2に擬似クラス(:hover)を設定する

const CssInJsTest2 = styled.p`
  color: ${keyColor};
  &:hover {
    background: rgba(255,255,255,0.3);
  }
`;
  • :hover設定を&でつなぐ
  • 背景色を白の不透明度30%に

動作確認

ブラウザで確認
f:id:idr_zz:20201215080452j:plain

カーソルを重ねると背景色が変わった!

子要素の設定

子要素の書き方

先ほどの擬似クラスと同じ&で繋ぐ書き方で子要素も設定できる。

const CssInJsTest2 = styled.p`
  color: ${keyColor};
  &:hover {
    background: rgba(255,255,255,0.3);
  }
  & span {
    font-weight: bold;
  }
`;
  • :hoverの下にspan要素の設定を追加
  • span要素の文字の太さをbold

ひと繋がりのセレクタではないのでspanの前に半角スペースを入れている。

※参考:styled-components: API Reference

子要素を設定

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <!-- 中略 -->
        <CssInJsTest>
          CSS in JSテストですと。
        </CssInJsTest>
        <CssInJsTest2>
          CSS in JS<span>テスト2</span>ですと。
        </CssInJsTest2>
      </header>
    </div>
  );
}
  • CssInJsTest2コンポーネントのテキスト「テスト2」をspanタグで囲う

動作確認

ブラウザを見ると「テスト2」だけ太字になった! f:id:idr_zz:20201216043803j:plain

コンポーネントの入れ子構造

親コンポーネントの設定

先ほどは子要素を追加したが、今度は親要素。コンポーネントの入れ子構造にしてみる。

const Block = styled.div`
  margin: 20px;
  padding: 0 20px;
  background: #333;
  border-radius: 10px;
`;
  • 親コンポーネントBlockdivタグ
  • Blockのスタイル設定(余白設定、背景は濃グレー、角丸設定)

親コンポーネントを追加

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <!-- 中略 -->
        <Block>
          <CssInJsTest>
            CSS in JSテストですと。
          </CssInJsTest>
          <CssInJsTest2>
            CSS in JS<bold>テスト2</bold>ですと。
          </CssInJsTest2>
        </Block>
      </header>
    </div>
  );
}
  • CssInJsTestCssInJsTest2を囲う形でBlockを配置

動作確認

ブラウザを見ると背景色が表示された! f:id:idr_zz:20201216044802j:plain

レンダリングされたHTMLとclass名

Dev-toolsで見ると下記のHTMLがレンダリングされている。独自のclass名が振られている。 f:id:idr_zz:20201216044922j:plain

<div class="sc-bdfBwQ jeuXIP">
    <p class="sc-gsTCUz wIMML">CSS in JSテストですと。</p>
    <p class="sc-dlfnbm eyXUGc">CSS in JS<bold>テスト2</bold>ですと。</p>
</div>

2番目に付いているclass名がCSSと紐づいているようだ。 f:id:idr_zz:20201216045145j:plain

  • Block -> .jeuXIP
  • CssInJsTest -> .wIMML
  • CssInJsTest2 -> .eyXUGc

このランダムな文字列によってCSSがグローバルスコープになるわけか。ランダムな文字列が振られるのはCSS Modulesと同じだな。

※参考:【React】CSS ModulesでCSSとSass(SCSS)のローカルスコープを作る - クモのようにコツコツと


今回作ったソースコード全体(GitHub)

※参考:GitHub - ryo-i/css-in-js-test

最後に

ということでstyled-componentsでCSS in JSを事始めることができました。この方法は自分的には結構いい印象を受けました!

  • JSXと同一ファイル内でコンポーネント名でCSSを設定できる
  • JSのオブジェクト(連想配列)と違ってCSSの書式そのままで書ける
  • 共通化したい値は変数として外部から読み込める
  • Sass(SCSS)のようなインデントの入れ子や&で繋ぐ書き方ができる
  • 擬似クラス、擬似要素も設定できる

CSS in JSに比べるとCSS Modulesは外部ファイルを読み込むため、ちょっとコードの見通しは悪いかなー。逆にJSとCSSの設定が両方複雑で完全に別々で管理した方がいい場合はCSS Modulesの方がいいのかもしれない。

次回はUIフレームワーク「Material UI」を触ってみようと思います。

それではまた!


続き書きました!

※参考:【React】UIフレームワークMaterial UIでマテリアルデザインを事始める - クモのようにコツコツと


※参考:Reactを習得するためにやったことまとめ
qiita.com