homehome

First step in styled-components(CSS in JS)

Published

TocMenu目次

CSS-in-JSはCSSをコンポーネントレベルで抽象化します。特定のライブラリを指すわけではないため、実装に関してはどのライブラリを選択するかによりアプローチは異なります。共通しているのはJavascriptを使うという点だけです。

CSS in JSを検索するとCSSの設計視点の話がよく見られると思います。ここではそういうのは置いておき、とりあえず触ってみようぜ!って感じの内容です。

本記事ではReactでよく利用されるstyled-componentsを使用します。とりあえず最初にこれだけ覚えとけばいいかなというものを列挙しました。

導入準備

パッケージをインストールします。

yarn add styled-components

もしVSCodeを使用している場合は、vscode-styled-componentsというプラグインをインストールするのをお勧めします。CSSプロパティの補完を受けられます。

簡単な例

styled.要素の後にCSSをバッククォートで囲み定義します。擬似要素やメディアクエリも標準のCSSの記述方法で定義でき、必要なベンダープレフィックスも自動挿入されます。

import styled from 'styled-components';

const MyComponent = styled.div`
	font-size: 1em;
    color: #000;
`;

const App = () => <MyComponent>CSS in JS</MyComponent>

実際のブラウザでのレンダリングでは、ユニークなクラス名が付与されます。併せて対応するスタイルが定義された<style>が挿入されます。クラス名やスタイルの衝突を意識する必要はなくなります。

<head>
  <style data-styled data-styled-version="4.2.0">
  /* sc-component-id: sr-bdVaJa */
  .fdjasQ{font-size:1em:color:#000;}</style>
</head>
<body>
  <div id="root">
    <div class="sc-bdVaJa fdjasQ">CSS in JS</div>
  </div>
</body>

ReactはファイルベースのCSS、inline CSS、CSS Moduleなどのスタイル定義方法をサポートしています。お勧めはしませんが、styled-componentsと併用は可能です。

props

propsを経由してスタイルを変更できます。

const Headline = styled.h1`
	color: ${props => props.color};
`;

// render()内
<Headline color="red">Headline</Headline>

変数

外部ファイルに定数を定義しておき、それを読み込み値として使用できます。

// .style.js
export const redColor = "#ff0000";

// App.js
import { redColor } from "./style";

const MyComponent = styled.div`
	color: ${redColor};
`;

入れ子

Sassのようにネストされたスタイルも定義できます。

const Container = styled.div`
  width: 200px;
  ul {
    list-style: square;
    li {
      color: blueviolet;
    }
  }
`;

function App() {
  return (
    <Container>
      <ul>
        <li>item1</li>
        <li>item2</li>
      </ul>
    </Container>
  );
}

ただし、通常は各コンポーネントで独立させた方が汎用性は高まります。

const Container = styled.div`width: 200px`;
const List = styled.ul`list-style: square`;
const ListItem = styled.li`color: blueviolet`;

function App() {
    return (
    	<Container>
        	<List>
                <ListItem>item1</ListItem>
                <ListItem>item2</ListItem>
            </List>
        </Container>
    );
}

拡張する

既存コンポーネントのスタイルを継承することもできます。


const Button = styled.button`
  background-color: green;
  color: red;
  border: none;
  padding: 1em 2em;
`;

/* background-colorは上書きできる */
const YellowButton = styled(Button)`
  cursor: pointer;
  background-color: yellow;
`;

多態性(ポリモーフィズム)

asを使うとスタイルは利用したままタグだけを変更することができます。

const Headline = styled.h1`
  font-size: 2em;
`;

// render()内
// 通常はh1でレンダリングされるが、以下はh5としてレンダリングされる
<Headline as="h5">Head</Headline>

CSSの生成

cssヘルパー関数を使うとテンプレートリテラルからCSSを生成できます。以下はtest propsに応じて生成されたCSSがコンポーネントに挿入されます。

const Headline = styled.h1`
	${props => props.test && css`
		color: red;
	`};
`;

// render内
<Headline test>Head</Headline>

styled-componentsはクラスではなくpropsに基づいたスタイル変更を推奨(強制)しています。従来のクラスのような使い方をしたい場合は、上記のような記述が必要になります。

クラスの挿入

CSSフレームワークとの併用でコンポーネントにクラスを挿入したい場合もあるでしょう。

Q&Aに記載されているようにattrを使います。この関数は他の属性定義にも使えます。

const Headline = styled.h1.attrs({
  className: "test"
})`
  font-size: 2em;
  /* testクラスのプロパティを定義しています */
  &.test {
    color: blue;
  }
`;

// render()内での利用
<Headline>Head</Headline>

挿入されるクラス名は.ランダム値.testとなります。

グローバルスタイル

グローバルなスタイルを定義したい場合は、createGlobalStyleを利用します。以下のようなファイルを別途作成します。

// globalStyle.js
import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
  body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    color: #333;
    margin: 0;
    padding: 0;
  }
`;

export default GlobalStyle

このコンポーネントをメインコードで使用するだけです。

import GlobalStyle from './globalStyle.js';

function App() {
  return (
    <>
      <GlobalStyle />
	  ...
    </>
  )
}

createGlobalStyleは、ここまでの例と異なりユニークなクラス名は付与されません。通常のCSSファイル同様に記述内容がそのまま<style>に挿入されます。

おわりに

CSS in JSではCSSモデルをドキュメントベースではなく、コンポーネントレベルで考えていくことになります。複数のCSSファイルを管理する必要はなくなります。更にはBEMなどを導入する必要なく、プロパティの汚染もスルーできます。

その他のAPIはドキュメントで!