styled-componentsで変わるReactコンポーネントのスタイリング

2017/06/02

Chris Laughlin

58

Articles in this issue reproduced from SitePoint
Copyright © 2017, All rights reserved. SitePoint Pty Ltd. www.sitepoint.com. Translation copyright © 2017, KADOKAWA ASCII Research Laboratories, Inc. Japanese syndication rights arranged with SitePoint Pty Ltd, Collingwood, Victoria,Australia through Tuttle-Mori Agency, Inc., Tokyo

Reactアプリの開発でちょっとやっかいなのが、スタイルシートの扱いです。さまざまな手法の中から、いま注目のstyled-componentsを使った方法を紹介します。

Reactによるアプリケーションの構築手法は標準化がだいぶ進んでいます。しかし、「スタイリング」においては標準的な実装方法がまだ定まっていません。それぞれの方法に長所と短所があり、どれがベストか言えない状況です。

この記事では、ReactコンポーネントにおけるWebアプリケーションのスタイリングがどこまで進歩しているかを解説します。また、styled-componentsについて簡単に紹介します。

JavaScriptにおけるスタイリングの進化

CSSは1996年のリリース以降、あまり大きく変わっていません。メジャーリリースを3回実施し、4度目のリリースが進められている現在まで、CSSは新たな機能を追加することで成長し続け、Web技術の基盤として確固たる地位を築いてきました。CSSはこれからもWebコンポーネントのスタイリングにおいて標準であり続けるでしょう。しかし、使用方法は日々変化しています。

画像を継ぎ接ぎしてWebサイトを構築していた時代から、画像と同じものをCSSで実装できる時代に至るまで、CSSはJavaScriptやWebの発展とともに進化してきました。

2013にReactがリリースされてから、コンポーネントを組み立ててWebアプリケーションを開発するのが当たり前になりました。一方で、CSSの実装は疑問視されるようになりました。CSSとReactを一緒に実装するのは関心の分離(Separation of concerns: SoC)の観点で批判されています。SoCはプログラムを各セクションに分離し、セクションごとに異なる関心を処理する設計原則です。この原則は、スタイル(CSS)、マークアップ(HTML)、ロジック(JavaScript)3つの主要なWeb技術を別のファイルに分けて開発する場合に使います。

ReactにJSXが導入されたことで状況は変わりました。開発チームは、これまでやってきたことは関心の分離ではなく技術の分離だった、と主張しました。JSXによってマークアップがJavaScriptのコードに移動したのに、スタイルを分離する必要はあるのでしょうか?

スタイルとロジックを引き離すこととは対照的に、同じ行にまとめるという考え方もあります。以下がその例です。

<button style="background: red; border-radius: 8px; color: white;">Click Me</button>

このインラインスタイルではCSSの定義をCSSファイルから移動します。従って、ファイルをインポートする必要が無く、帯域幅を節約できます。しかし、可読性、保守性、スタイルの継承が犠牲になります。

CSS Modules

button.css

.button {
    background: red;
    border-radius: 8px;
    color: white;
}

button.js

import styles from './button.css';
document.body.innerHTML = `<button class="${styles.button}">test</button>`;

上のサンプルコードでは、まだ専用ファイルにCSSを書いています。しかし、CSS ModulesをWebpackやそのほかの最新のバンドラーでバンドルすると、スクリプトタグとしてHTMLファイルに追加できるようになります。また、クラス名をハッシュすることでより細かなスタイリングが可能になり、CSSの問題点を克服できます。

ハッシュ化の処理で、クラス名に代わるユニークな文字列が生成されます。クラス名「btn」の場合、ハッシュ「DhtEg」が生成されます。これでスタイルのカスケードを防止できます。また目的外の要素にスタイルが適用されることを防ぎます。

index.html

<style>
.DhtEg {
    background: red;
    border-radius: 8px;
    color: white;
}
</style>

.....

<button class="DhtEg">test</button>

上の例ではCSS Modulesで、ハッシュされたクラス名を持つstyleタグ要素を追加し、DOM要素からそのハッシュを利用しています。

Glamor

GlamorはCSSをJavaScriptと同じファイル内で宣言するための、CSS-in-JSライブラリーです。Glamorもクラス名をハッシュします。Glamorを利用すれば、簡潔な構文でJavaScript上にスタイルシートを作成できます。

スタイルは、JavaScriptの変数を使って各属性をキャメルケースで定義します。CSSではトレインケースですべての属性を定義するのでキャメルケースが重要なポイントになります。キャメルケースで属性名が変わることがあるため、CSSをアプリケーションのほかの場所、またはCSSのサンプルからコピー&ペーストするときに問題になります。たとえば、overflow-yがoverFlowYになります。この違いのおかげでGlamorはメディアクエリーやshadow要素のサポートが可能になり、より強力なスタイリングを実現します。

button.js

import { css } from 'glamor';

const rules = css({
    background: red;
    borderRadius: 8px;
    color: 'white';
});

const button = () => {
    return <button {...rules}>Click Me</button>;
};

styled-components

styled-componentsはReactコンポーネントとスタイルをまとめて書くことを目的とした新たなライブラリーです。styled-componentsはReactとReact Nativeのスタイリング用に簡潔で使いやすいインターフェイスを提供しており、実装のあり方や、Reactコンポーネントをスタイリングするための考え方も変えつつあります。

styled-componentsはnpm経由でインストールできます。

npm install styled-components

標準的なnpmパッケージと同じようにインポートします。

import styled from 'styled-components';

インストールが完了したら、Reactコンポーネントを楽しくスタイリングするだけです。

Reactコンポーネントの基本的なスタイルを作る

Reactコンポーネントをスタイリングする方法は多数あります。styled-componentsライブラリーにある複数のパターンを利用すれば、優れたユーザーインターフェイスのアプリケーションが作成できます。ボタン、インプット、タイポグラフィ、タブといった小さなUIコンポーネントを組み合わせることで、統一感のある、整ったアプリケーションができるのです。

styled-componentsを使って、前述のボタンサンプルのような「通常のボタン」を作成します。

const Button = styled.button`
    background: red;
    border-radius: 8px;
    color: white;
`;

class Application extends React.Component {
  render() {
    return (
      <Button>Click Me</Button>
    )
  }
}

CSSとJavaScriptをまとめて書いたボタンを作成します。styled-componentsにはスタイリングのための要素が幅広く備わっています。これらの要素は、直接参照するか標準関数に文字列を渡すことで利用できます。

const Button = styled.button`
    background: red;
    border-radius: 8px;
    color: white;
`;

const Paragraph = styled.p`
  background: green;
`;

const inputBg = 'yellow';
const Input = styled.input`
  background: ${inputBg};
  color: black;
`;

const Header = styled('h1')`
  background: #65a9d7;
  font-size: 26px;
`

class Application extends React.Component {
  render() {
    return (
      <div>
        <Button>Click Me</Button>
        <Paragraph>Read ME</Paragraph>
        <Input 
          placeholder="Type in me"
        />
        <Header>I'm a H1</Header>
      </div>
    )
  }
}

styled-componentsによるスタイリングには、純粋なCSSを書ける利点があります。ただしGlamorでは、CSSの属性名をJavaScriptオブジェクトの属性として処理するためキャメルケースに変更しなければなりませんでした。

styled-componentsはReactと相性の良いプリミティブ型を生成します。プリミティブ型は既存の要素と同様に動作します。CSSの力を最大限発揮してコンポーネントをスタイリングするには、JavaScriptのテンプレートリテラルを使いこなすことが必要です。たとえば、上のインプット要素のサンプルのように、JavaScriptの変数を外部に定義して、その変数をスタイルに適用します。

こうしたシンプルなコンポーネントで、アプリケーションのスタイルガイドを容易に構築できます。しかし、外部要因に基づいて変化可能な、より複雑なコンポーネントが必要になる場面も数多くあります。

カスタマイズ可能な、Reactコンポーネントのスタイル

カスタマイズ性が高いのはstyled-componentsの大きな強みです。コンテキストに応じてスタイルを変えられるボタンを作るときに、この強みが効果を発揮します。ここでは、大小2つのボタンを作成します。以下は純粋なCSSを使った方法です。

CSS

button {
    background: red;
    border-radius: 8px;
    color: white;
}

.small {
    height: 40px;
    width: 80px;
}

.medium {
    height: 50px;
    width: 100px;
}

.large {
    height: 60px;
    width: 120px;
}

JavaScript

class Application extends React.Component {
  render() {
    return (
      <div>
        <button className="small">Click Me</button>
        <button className="large">Click Me</button>
      </div>
    )
  }
}

styled-componentsを使って再構築するには、標準的なスタイルのButtonコンポーネントをバックグラウンドに作成します。このコンポーネントはReactコンポーネントと同じように動作するので、propsを利用して出力するスタイルを変更できます。

const Button = styled.button`
  background: red;
  border-radius: 8px;
  color: white;
  height: ${props => props.small ? 40 : 60}px;
  width: ${props => props.small ? 60 : 120}px;
`;

class Application extends React.Component {
  render() {
    return (
      <div>
        <Button small>Click Me</Button>
        <Button large>Click Me</Button>
      </div>
    )
  }
}

高度な利用方法

styled-componentsでは既存のJavaScriptのパターンを組み合わせることで、複雑で高度なコンポーネントを作成できます。コンポーネントの作り方を以下の例で説明します。基本的なスタイルは同じで背景色が異なる通知メッセージです。基本的なスタイルのコンポーネントを組み合わせることで高度なコンポーネントを作成します。

const BasicNotification = styled.p`
    background: lightblue;
    padding: 5px;
    margin: 5px;
    color: black;
`;

const SuccessNotification = styled(BasicNotification)`
    background: lightgreen;
`;

const ErrorNotification = styled(BasicNotification)`
    background: lightcoral;
    font-weight: bold;  
`;

class Application extends React.Component {
  render() {
    return (
      <div>
        <BasicNotification>Basic Message</BasicNotification>
        <SuccessNotification>Success Message</SuccessNotification>
        <ErrorNotification>Error Message</ErrorNotification>
      </div>
    )
  }
}

styled-componentsには標準的なDOM要素やほかのコンポーネントを渡せます。これで基本的な要素を組み合わせて高度な機能を作成できます。

コンポーネントの構造

基本的なサンプルと高度なサンプルを作成しました。次はコンポーネント構造を作成します。一般的なReactのアプリケーションの大半はコンポーネントディレクトリを持っています。今回は、スタイリングしたコンポーネントをstyledComponentsディレクトリに配置します。ディレクトリ内に基本的なコンポーネント、組み合わせコンポーネントをすべて格納し、アプリケーションが使用する表示用コンポーネントにこれらのファイルをインポートさせます。ディレクトリのレイアウトは次以下の通りです。

src/
  components/
    addUser.js
    styledComponents/
      basicNotification.js
      successNotification.js
      errorNotification.js

最後に

コンポーネントをスタイリングする方法は多岐にわたり、決定的な手法はありません。記事では、styled-componentsの登場で要素のスタイリングが前進したと説明しました。また、styled-componentsがこれまでのスタイリングの考え方に一石を投じたことも紹介しました。

私を含め、すべての開発者は自分なりの方法を持っています。しかし、自分が携わるアプリケーションに関連する手法を学ぶのは良いことです。システムやプログラミング言語のスタイリングは近年大きく進歩しました。そして、将来さらに発展し、変わっていくでしょう。フロントエンド開発はとても刺激的でおもしろい時期を迎えています。

本記事はVildan Softicが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。

(原文:Quick Tip: How to Style React Components with styled-components

[翻訳:薮田佳佑/編集:Livit

Copyright © 2017, Chris Laughlin All Rights Reserved.

Chris Laughlin

Chris Laughlin

北アイルランドのベルファスト在住のアプリケーション開発者です。フロントエンド、特にJavaScriptの開発に注力しています。2010年からソフトウェアの開発に携わり、いまも毎日学び、知識をシェアしています。

Loading...