基本

動機

styled-componentsは、Reactコンポーネントシステム用のCSSをどのように強化できるかを考えた結果です。単一のユースケースに焦点を当てることで、開発者にとってのエクスペリエンスとエンドユーザーにとっての出力を最適化することができました。

styled-componentsは、開発者向けのエクスペリエンスの向上とは別に、以下を提供します。

  • 自動クリティカルCSS:styled-componentsは、ページにどのコンポーネントがレンダリングされているかを追跡し、そのスタイルだけを完全に自動的に挿入します。コード分割と組み合わせることで、ユーザーは必要な最小限のコードをロードすることになります。
  • クラス名バグなし:styled-componentsはスタイルに対して一意のクラス名を生成します。重複、オーバーラップ、スペルミスについて心配する必要はありません。
  • CSSの削除が容易:クラス名がコードベースのどこかで使用されているかどうかを知るのが難しい場合があります。styled-componentsでは、すべてのスタイル設定が特定のコンポーネントに関連付けられているため、明確になります。コンポーネントが未使用(ツールで検出可能)で削除された場合、そのスタイルもすべて削除されます。
  • シンプルな動的スタイル:propsやグローバルテーマに基づいてコンポーネントのスタイルを調整するのは、数十のクラスを手動で管理する必要がなく、簡単で直感的です。
  • 痛みのないメンテナンス:コンポーネントに影響を与えるスタイルを見つけるために異なるファイルを検索する必要がないため、コードベースがどれほど大きくてもメンテナンスは簡単です。
  • 自動ベンダープレフィックス:CSSを現在の標準に合わせて記述し、残りはstyled-componentsに任せます。

これらの利点はすべて、あなたが知っていて愛しているCSSを個々のコンポーネントにバインドしたまま書き続けることができます。

インストール

styled-componentsのインストールは1つのコマンドで完了し、すぐに使い始めることができます。

# with npm
npm install styled-components

# with yarn
yarn add styled-components

yarnのような、"resolutions" package.jsonフィールドをサポートするパッケージマネージャーを使用する場合は、メジャーバージョン範囲に対応するエントリを追加することを強くお勧めします。これにより、プロジェクトに複数のバージョンのstyled-componentsがインストールされている場合に発生する問題全体を回避できます。

package.json

{
  "resolutions": {
    "styled-components": "^5"
  }
}

Babelプラグインも使用することを強くお勧めします(必須ではありません)。より判読しやすいクラス名、サーバーサイドレンダリングの互換性、バンドルの縮小など、多くのメリットがあります。

代替のCDNインストール手順については、こちらをクリックしてください

モジュールバンドラーやパッケージマネージャーを使用していない場合は、unpkg CDNでホストされているグローバル(「UMD」)ビルドもあります。HTMLファイルの最後に次の<script>タグを追加するだけです。

<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>

styled-componentsを追加すると、グローバル変数window.styledにアクセスできるようになります。

const Component = window.styled.div`
  color: red;
`

このスタイルの使用には、react CDNバンドルと、react-is CDNバンドルが(styled-componentsスクリプトの前に)ページにある必要もあります。

はじめに

styled-componentsは、タグ付きテンプレートリテラルを使用してコンポーネントのスタイルを設定します。

コンポーネントとスタイルの間のマッピングを削除します。これは、スタイルを定義するときに、実際にはスタイルが添付された通常のReactコンポーネントを作成していることを意味します。

この例では、いくつかのスタイルが添付された、ラッパーとタイトルの2つの簡単なコンポーネントを作成します

Hello World!

これはライブエディターなので、コードを試して、styled-componentsを操作するのがどのようなものかを感じてください!

CSSルールには自動的にベンダープレフィックスが付き、styled-componentsがその面倒を見てくれます!

styled-componentsは、CSSルールのプレフィックス処理にstylis.jsパッケージを内部で使用しています。

stylis.jsでサポートされているプレフィックスの詳細については、リポジトリをご覧ください。

propsに基づいた適応

styledコンポーネントのテンプレートリテラルに関数(「インターポレーション」)を渡して、propsに基づいて適応させることができます。

このボタンコンポーネントには、色を変更するプライマリ状態があります。$primary propをtrueに設定すると、背景色とテキストの色が入れ替わります。

スタイルの拡張

頻繁に、コンポーネントを使用したいが、1つのケースでわずかに変更したい場合があります。ここで、インターポレーションされた関数を渡して、propsに基づいて変更できますが、一度スタイルをオーバーライドするのはかなり手間がかかります。

別のスタイルのスタイルを継承する新しいコンポーネントを簡単に作成するには、styled()コンストラクターでラップするだけです。ここでは、前のセクションのボタンを使用して、色関連のスタイルを追加して拡張した特別なボタンを作成します

新しいTomatoButtonは、2つの新しいルールを追加しただけですが、Buttonに似ていることがわかります。

場合によっては、スタイルのあるコンポーネントがレンダリングするタグまたはコンポーネントを変更したい場合があります。これは、たとえば、アンカーリンクとボタンが混在しているが、同じようにスタイルを設定する必要があるナビゲーションバーを作成する場合によくあります。

このような場合は、エスケープハッチがあります。"as"ポリモーフィックpropを使用して、作成したスタイルを受け取る要素を動的に交換できます

これは、カスタムコンポーネントでも完全に機能します!

あらゆるコンポーネントのスタイル設定

styledメソッドは、渡されたclassName propをDOM要素にアタッチする限り、独自のコンポーネントまたはサードパーティのコンポーネントすべてで完全に機能します。

react-nativeを使用している場合は、classNameの代わりにstyleを使用することを忘れないでください。

styled("div")のように、タグ名をstyled()ファクトリー呼び出しに渡すこともできます。実際、styled.tagnameヘルパーは、同じことを行うエイリアスにすぎません。

渡されたprops

styledのターゲットが単純な要素(例:styled.div)である場合、styled-componentsは既知のHTML属性をDOMに渡します。カスタムReactコンポーネント(例:styled(MyComponent))の場合、styled-componentsはすべてのpropsを渡します。

この例では、React要素の場合と同様に、InputコンポーネントのすべてのpropsがマウントされているDOMノードに渡される方法を示しています。

$inputColor propがDOMに渡されず、typedefaultValueが渡されるのはなぜですか?styled関数は、非標準属性を自動的にフィルタリングするのに十分なほどスマートです。

CSSからの移行

Styled Componentsはコンポーネント内でどのように機能しますか?

もしコンポーネントにCSSをインポートすること(例:CSSModulesなど)に慣れているなら、次のようなことをするのに慣れているでしょう。

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


export default class Counter extends React.Component {
  state = { count: 0 };


  increment = () => this.setState({ count: this.state.count + 1 });
  decrement = () => this.setState({ count: this.state.count - 1 });


  render() {
    return (
      <div className={styles.counter}>
        <p className={styles.paragraph}>{this.state.count}</p>
        <button className={styles.button} onClick={this.increment}>
          +
        </button>
        <button className={styles.button} onClick={this.decrement}>
          -
        </button>
      </div>
    );
  }
}

Styled Componentは、要素とそれをスタイルするルールの組み合わせであるため、Counter はこのように記述します。

import React from 'react';
import styled from 'styled-components';


const StyledCounter = styled.div`
  /* ... */
`;
const Paragraph = styled.p`
  /* ... */
`;
const Button = styled.button`
  /* ... */
`;


export default class Counter extends React.Component {
  state = { count: 0 };


  increment = () => this.setState({ count: this.state.count + 1 });
  decrement = () => this.setState({ count: this.state.count - 1 });


  render() {
    return (
      <StyledCounter>
        <Paragraph>{this.state.count}</Paragraph>
        <Button onClick={this.increment}>+</Button>
        <Button onClick={this.decrement}>-</Button>
      </StyledCounter>
    );
  }
}

StyledCounter に "Styled" という接頭辞を追加したのは、Reactコンポーネント Counter とStyled Component StyledCounter の名前が衝突しないようにするためですが、React Developer ToolsとWeb Inspectorで簡単に識別できるようにするためです。

Styled Componentsをrenderメソッドの外で定義する

Styled Componentsをrenderメソッドの外で定義することが重要です。そうしないと、すべてのrenderパスで再作成されることになります。renderメソッド内でstyled componentを定義すると、キャッシュが無効になり、レンダリング速度が大幅に低下するため、避けるべきです。

推奨される方法でstyled componentを記述する

const StyledWrapper = styled.div`
  /* ... */
`;


const Wrapper = ({ message }) => {
  return <StyledWrapper>{message}</StyledWrapper>;
};

代わりに

const Wrapper = ({ message }) => {
  // WARNING: THIS IS VERY VERY BAD AND SLOW, DO NOT DO THIS!!!
  const StyledWrapper = styled.div`
    /* ... */
  `;


  return <StyledWrapper>{message}</StyledWrapper>;
};

推奨される読み物: Talia Marcassa は、Styled Components: To Use or Not to Use? で、多くの確かな実践的な洞察や代替案との比較を特徴とする、実際の使用状況に関する優れたレビューを執筆しました。

擬似要素、擬似セレクタ、ネスト

使用しているプリプロセッサであるstylisは、スタイルの自動ネストのためにscssのような構文をサポートしています。

このプリプロセスを通じて、styled-componentsはいくつかの高度なセレクタパターンをサポートしています。

  • & 単一のアンパサンドは、コンポーネントのすべてのインスタンスを参照します。これは、広範なオーバーライドを適用するために使用されます。

    Hello world!
    How ya doing?
    The sun is shining...
    Pretty nice day today.
    Don't you think?
    Splendid.
  • && 二重アンパサンドは、コンポーネントの1つのインスタンスを参照します。これは、条件付きスタイルオーバーライドを実行していて、特定のコンポーネントのすべてのインスタンスにスタイルを適用したくない場合に役立ちます。

  • && 二重アンパサンド単独には「優先度ブースト」と呼ばれる特別な動作があります。これは、スタイルが競合する可能性がある、styled-componentsとバニラCSSが混在する環境を処理している場合に役立ちます。

    I'm blue, da ba dee da ba daa

アンパサンドなしでセレクタを記述すると、コンポーネントの子を参照します。

追加のpropsのアタッチ
v2

レンダリングされたコンポーネントまたは要素にいくつかのpropsを渡すだけの不要なラッパーを避けるために、.attrs コンストラクタを使用できます。これにより、コンポーネントに追加のprops(または「属性」)をアタッチできます。

このようにして、たとえば、静的なpropsを要素にアタッチしたり、activeClassNameのようなサードパーティのpropsをReact RouterのLinkコンポーネントに渡したりできます。さらに、より動的なpropsをコンポーネントにアタッチすることもできます。.attrs オブジェクトは、コンポーネントが受け取るpropsを受け取る関数も受け取ります。戻り値も結果のpropsにマージされます。

ここでは、Input コンポーネントをレンダリングし、いくつかの動的および静的な属性をアタッチします。


ご覧のとおり、補間では新しく作成されたpropsにアクセスでき、type 属性は要素に渡されます。

.attrsのオーバーライド

styled componentsをラップする場合、.attrs は最も内側のstyled componentから最も外側のstyled componentに適用されることに注意してください。

これにより、各ラッパーは、stylesheetで後で定義されたCSSプロパティが以前の宣言をオーバーライドするのと同様に、.attrs のネストされた使用をオーバーライドできます。

Input.attrs が最初に適用され、次に PasswordInput.attrs が適用されます。


これが、PasswordInput'password' タイプでありながら、Input$size 属性を使用している理由です。

アニメーション

@keyframes を使用したCSSアニメーションは、単一のコンポーネントにスコープされているわけではありませんが、名前の衝突を避けるためにグローバルにしたくはありません。そのため、アプリ全体で使用できる一意のインスタンスを生成する keyframes ヘルパーをエクスポートしています。

< 💅🏾 >

Keyframesはreact-nativeではサポートされていません。代わりに、ReactNative.Animated APIを使用してください。

Keyframesは使用時に遅延して挿入されます。これは、コード分割できる理由であり、共有スタイルフラグメントにはcss ヘルパーを使用する必要があります。

const rotate = keyframes``


// ❌ This will throw an error!
const styles = `
  animation: ${rotate} 2s linear infinite;
`


// ✅ This will work as intended
const styles = css`
  animation: ${rotate} 2s linear infinite;
`

これは、keyframesをコード分割していなかったv3以下では機能していました。v3からアップグレードする場合は、共有スタイルフラグメントがすべて css ヘルパーを使用していることを確認してください!

React Native

styled-componentsは、React Nativeで同じように、また同じimportで使用できます。ExpoのSnackでこの例を試してみてください。

import React from 'react'
import styled from 'styled-components/native'


const StyledView = styled.View`
  background-color: papayawhip;
`


const StyledText = styled.Text`
  color: #BF4F74;
`


class MyReactNativeComponent extends React.Component {
  render() {
    return (
      <StyledView>
        <StyledText>Hello World!</StyledText>
      </StyledView>
    )
  }
}

また、通常は配列となる、より複雑なスタイル(transformなど)や、css-to-react-nativeのおかげで、省略形(marginなど)もサポートしています!

flexプロパティは、React Nativeのレガシーなflexプロパティではなく、CSSの省略形のように動作することに注意してください。flex: 1を設定すると、flexGrow1 に設定することに加えて、flexShrink1 に、flexBasis0 に設定します。

React Nativeでプロパティをどのように記述するかを想像し、それをCSSにどのように転送するかを推測すれば、おそらく正しいでしょう。

const RotatedBox = styled.View`
  transform: rotate(90deg);
  text-shadow-offset: 10px 5px;
  font-variant: small-caps;
  margin: 5px 7px 2px;
`

Web版との違いの一部は、React Nativeがkeyframesまたはグローバルスタイルをサポートしていないため、keyframes および createGlobalStyle ヘルパーを使用できないことです。また、メディアクエリを使用したり、CSSをネストしたりすると、警告が表示されます。

v2では、パーセンテージをサポートしています。これを可能にするには、すべての省略形の単位を強制する必要があります。v2に移行している場合は、codemodが利用可能です

metro bundlerによる簡単な使用法

styled-components/native の代わりに styled-components をimportしたい場合は、resolverMainFields 構成"react-native" を含めることができます。これは、デフォルトではmetroでサポートされていましたが(現在、haulでは機能しますが)、ある時点で削除されたようです。

次のページに進んでください

高度な内容