styled-componentsは、Reactコンポーネントシステム用の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プラグインも使用することを強くお勧めします(必須ではありません)。より判読しやすいクラス名、サーバーサイドレンダリングの互換性、バンドルの縮小など、多くのメリットがあります。
モジュールバンドラーやパッケージマネージャーを使用していない場合は、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でサポートされているプレフィックスの詳細については、リポジトリをご覧ください。
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
ヘルパーは、同じことを行うエイリアスにすぎません。
styledのターゲットが単純な要素(例:styled.div
)である場合、styled-componentsは既知のHTML属性をDOMに渡します。カスタムReactコンポーネント(例:styled(MyComponent)
)の場合、styled-componentsはすべてのpropsを渡します。
この例では、React要素の場合と同様に、InputコンポーネントのすべてのpropsがマウントされているDOMノードに渡される方法を示しています。
$inputColor
propがDOMに渡されず、type
とdefaultValue
が渡されるのはなぜですか?styled
関数は、非標準属性を自動的にフィルタリングするのに十分なほどスマートです。
もしコンポーネントに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メソッドの外で定義することが重要です。そうしないと、すべての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を渡すだけの不要なラッパーを避けるために、.attrs
コンストラクタを使用できます。これにより、コンポーネントに追加のprops(または「属性」)をアタッチできます。
このようにして、たとえば、静的なpropsを要素にアタッチしたり、activeClassName
のようなサードパーティのpropsをReact RouterのLinkコンポーネントに渡したりできます。さらに、より動的なpropsをコンポーネントにアタッチすることもできます。.attrs
オブジェクトは、コンポーネントが受け取るpropsを受け取る関数も受け取ります。戻り値も結果のpropsにマージされます。
ここでは、Input
コンポーネントをレンダリングし、いくつかの動的および静的な属性をアタッチします。
ご覧のとおり、補間では新しく作成されたpropsにアクセスでき、type
属性は要素に渡されます。
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
ヘルパーを使用していることを確認してください!
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
を設定すると、flexGrow
を 1
に設定することに加えて、flexShrink
を 1
に、flexBasis
を 0
に設定します。
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が利用可能です。
styled-components/native
の代わりに styled-components
をimportしたい場合は、resolverMainFields
構成 に "react-native"
を含めることができます。これは、デフォルトではmetroでサポートされていましたが(現在、haulでは機能しますが)、ある時点で削除されたようです。