Reactの特定コンポーネントだけに適用するCSSを作りたい(css in js)

プログラミング

Reactのコンポーネントってとっても細分化されますよね。

それに、ある特定のCSSを適用させたいときには、「そのコンポーネントのタグだけに適用させたい」と考える場面は当然あるでしょう。

ということで、特定コンポーネントだけに適用できる『css in js』をご紹介。

css in jsを実現するためのライブラリ

css in jsを実現するためには、ライブラリを使用します。

といったライブラリです。

この記事では、styled componentsを使って進めます。

styled componentsのインストール

npm install styled-componentsコマンド投入
npm install styled-components

styled componentsを使用するディレクトリで上記のnpmコマンドをインストールしましょう。

それだけです。

神谷
神谷

VSCodeを使っている方は『vscode-styled-components』という拡張機能をインストールすると、cssがハイライトされて便利!

スタイルを適用するjsxサンプル(App.js)

jsxはApp.jsに直接書きました。

import { useState } from 'react';

import styled from 'styled-components';

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
   {// ここにボタンのコンポーネントを書きます。}
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;

「// ここにボタンのコンポーネントを書きます。」の所に、styled componentsで作成したスタイルコンポーネントを書いていきます。

styled componentsのインポート

cssを当てたいコンポーネントのファイルにstyled componentsをインポートします。

今回の場合は、App.jsですね。

import styled from "styled-components";

インポートした「styled」の中に、HTMLのタグと同じだけのプロパティが用意されています。

試しに、

consol.dir(styled);

とコードを書いてstyledの中を表示させると、HTMLのタグに対応したプロパティが確認できます。

styled componentsの内容

styled componentsを適用する

スタイル付きのコンポーネント定義

styled componentsでは、コンポーネントの中にスタイル付きのコンポーネントが定義できます。

神谷
神谷

分かりにくいですが、当該記事の場合はAppコンポーネントの中にStyledButtonコンポーネントを定義したということですね。

例えば、ボタンにスタイルを付けたい場合には、こんな感じになります。

const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  `;

これは、ボタンタグにスタイルを付けた「StylesButton」というコンポーネントを定義していることになります。

これをjsx内に展開すると、スタイリングされたボタンが出現します。

import React from 'react';
import './App.css';

import { useState } from 'react';

import styled from 'styled-components';

// ----------------------------------------
// スタイル付きのタグ定義
const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  text-align: center;
  line-height: 60px;
  `;
//------------------------------------------

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
       {/* StyledButtonコンポーネントを追記 */}
      <StyledButton>ボタン</StyledButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;
styled componentsでスタイリングしたボタン

styled componentsにpropsを渡す

styled componentsにpropsを渡すこともできます。

つまり、処理次第で、スタイリングを変えることができるということですね。

import React from 'react';
import './App.css';

import { useState } from 'react';

import styled from 'styled-components';

// ----------------------------------------
const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  text-align: center;
  line-height: 60px;
// propsでボタンのbackground-colorを変える
  background-color: ${({ isSelected }) => isSelected ? 'skyblue' : ''}; 
  `;
//------------------------------------------

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
       {/* StyledButtonコンポーネントにpropsとクリックハンドラーを追加 */}
      <StyledButton isSelected={isSelected} onClick={clickHandler}>ボタン</StyledButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;

ボタンをクリックすると、ボタンの色がskyblueになる処理を書きました。

StyledButtonコンポーネントに「isSelected={isSelected}」というようにpropsを追加して、styled.button“のタグ付きテンプレートの中の「background-color: ${({ isSelected }) => isSelected ? ‘skyblue’ : ”};」でpropsを判断して、ボタンのbackground-colorをskyblueに変えています。

スタイリングコンポーネントの継承

styled componentsでは、コンポーネントの継承ができます。

同じような記述をしなくていいので助かりますね。

import React from 'react';
import './App.css';

import { useState } from 'react';

import styled from 'styled-components';

// ----------------------------------------
// スタイル付きのタグ定義
const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  text-align: center;
  line-height: 60px;
  background-color: ${({ isSelected }) => isSelected ? 'skyblue' : ''}; // propsでボタンのbackground-colorを変える
  `;

  // 継承を使った定義
  const YellowButton = styled(StyledButton)`
    background-color: ${({ isSelected }) => isSelected ? 'aqua' : 'yellow'};// StyledButtonを継承したコンポーネント
    :hover { color: red; }
  `;
//------------------------------------------

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
      <StyledButton isSelected={isSelected} onClick={clickHandler}>ボタン</StyledButton>
      {/* StyledButtonを継承したYellowButtonを追加 */}
      <YellowButton  isSelected={isSelected} onClick={clickHandler}>ボタン</YellowButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;

styled componentsの継承を使ってボタンを複製する
 const 「継承先コンポーネント」 = styled(「継承元コンポーネント」)`「継承先独自の定義」`;

というように継承先のコンポーネントを作ればいいのですね。

サンプルでは、「承先コンポーネント:YellowButton」、「継承元コンポーネント:StyledButton」となっており、background-colorと:hoverを追加して継承元と異なるようにしています。

メディアクエリーを使う

styled componentsはメディアクエリーも使用可能。

import React from 'react';
import './App.css';

import { useState } from 'react';

import styled from 'styled-components';

// ----------------------------------------
const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  text-align: center;
  line-height: 60px;
  background-color: ${({ isSelected }) => isSelected ? 'skyblue' : ''}; 

  //600px以下はボタンを四角にするメディアクエリーを追記
  @media (max-width: 600px) {
    border-radius: 0;
  }
  `;

  const YellowButton = styled(StyledButton)`
    background-color: ${({ isSelected }) => isSelected ? 'aqua' : 'yellow'};
    :hover { color: red; }
  `;
//------------------------------------------

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
      <StyledButton isSelected={isSelected} onClick={clickHandler}>ボタン</StyledButton>
      <YellowButton  isSelected={isSelected} onClick={clickHandler}>ボタン</YellowButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;

600px以下はボタンを四角形にします。

600pxより大きいと、角が取れます。

ネストを使う

styled componentsはネストも使えます。

import React from 'react';
import './App.css';

import { useState } from 'react';

import styled from 'styled-components';

// ----------------------------------------
const StyledButton = styled.button`
  margin-inline: auto;
  border-radius: 9999px;
  border: none;
  display: block;
  width: 120px;
  height: 60px;
  margin: 10px auto;
  font-weight: bold;
  cursor: pointer;
  text-align: center;
  line-height: 60px;
  background-color: ${({ isSelected }) => isSelected ? 'skyblue' : ''}; 
  // spanをネストしてStyledButtonコンポーネントの中のspanタグの中だけを0.5emにする
    span {
      font-size: 0.5em;
    }

  @media (max-width: 600px) {
    border-radius: 0;
  }
  `;

  const YellowButton = styled(StyledButton)`
    background-color: ${({ isSelected }) => isSelected ? 'aqua' : 'yellow'};
    :hover { color: red; }
    // spanをネストしてYellowButtonコンポーネントの中のspanタグの中だけを2emにする
    span {
      font-size: 2em;
    }
  `;
//------------------------------------------

function App() {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);
  return (
    <div className="App">
      <h2>「css in js」のテスト</h2>
      {/* ボタンの文字をspanタグで囲う */}
      <StyledButton isSelected={isSelected} onClick={clickHandler}><span>ボタン</span></StyledButton>
      <YellowButton  isSelected={isSelected} onClick={clickHandler}><span>ボタン</span></YellowButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </div>
  );
}

export default App;

StyledButton、YellowButtonそれぞれのスタイルコンポーネントの中に、spanタグをネストしてスタイルを定義。

同じspanタグでも、違ったスタイリングをしています。

styled componentsはタグをネストしてスタイリングできます。

そういえば、この記事を書いている頃、chromeでcssのネストが使えるようになったと話題だったな。

最後に

styled componentsは、まだいろいろできることがるようだけど、以上にあげたところを押さえておけば、けっこう使えるんじゃないかなと思うところです。

タイトルとURLをコピーしました