styled components documentation日本語訳①ーBasicsー

1pt   2018-11-09 02:38
IT技術情報局

概要

styled componentsのdocumentation日本語訳がなかったので翻訳する。
Basics、Advancedは翻訳確実、ほかは気が向いたら翻訳する。
以下翻訳。

Basics

Motivation

styled-componentはReact componentシステムにおけるCSSをどうやったら強化できるだろうかと悩んだ結果である。
個々の利用例にフォーカスし、開発者とエンドユーザの両方にとって最適な体験を構築することができた。

開発者向けに改善された体験に加えて、styled-componentsは以下の特徴を提供する。

  • Automatic critical CSS:
    styled-componentsはページにどのcomponentsがrenderされたかを追跡するとともに、彼らが保持するstyleだけを注入する。完全に自動的に。コードが分離できることにより、ユーザーは必要に応じて最小限のコードのみをロードする。

  • No class name bugs:
    styled-componentsは各々のスタイルにユニークなnameを生み出す。重複について心配する必要はもうない。

  • Easier deletion of CSS:
    コードベースのどこかであるクラス名が使われているかを知ることは難しい。styeld-componentsはこれを明らかにする。なぜならどのstylingもある特定のcomponentに紐付いているからだ。
    もしcomponentが利用されなくなり(toolingが特定できる)、デリートされたとき、componentとともに紐づくstyleもすべてデリートされる。

  • Simple dynamic styling:
    componentのstyleをpropsやglobal themeに基づいて適用することはたくさんのclassesを手動で管理する必要のないシンプルで直感的なものである。

  • Painless maintenance:
    ファイルをまたいでcomponentに影響するstyleを探し出す必要はもうない。したがってどれだけコードベースが大きくてもメンテナンスは朝飯前だ。

  • Automatic vendor prefixing:
      現行基準のCSSを書き、残りはstyled-coponentsにまかせてしまおう。

各々のcomponentsに紐付けるだけで、熟知した愛すべきCSSを書いていることがこれらすべての恩恵を受けられる。

Installation

訳す価値ないので飛ばす。
ここを見てください。

Gettin Started

styled-componetsはcomponentsをsylingするためにタグのリテラルを利用する。
これによりcomponentとstyle間のマッピングが不要になる。
すなわち、styleを定義するとき実際には普通のReact componentを作っているのと変わらない。ただし、それはstyleを持っている。

この例はwrapperとtitleという2つのシンプルなstyle付きcomponentを作成している。

// Create a Title component that'll render an <h1> tag with some styles const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `; // Create a Wrapper component that'll render a <section> tag with some styles const Wrapper = styled.section` padding: 4em; background: papayawhip; `; // Use Title and Wrapper like any other React component – except they're styled! render( <Wrapper> <Title> Hello World! </Title> </Wrapper> );

68747470733a2f2f71696974612d696d6167652d

documentationでは実際にコードに触れるので遊んで見てほしい。以下同様。

注意:ベンダープレフィックスはstyled-componentsよって自動適用されている。

Adapting based on props

functionをテンプレート構文を用いてstyled-componentsのリテラルに渡し、propsに基づいてstyleを適用することができる。

このボタンはirowo kaerutameno
primary stateを持っている。
primary propをtrueに設定すると、backgroundとtext colorをスワップすることができる。

const Button = styled.button` /* Adapt the colors based on primary prop */ background: ${props => props.primary ? "palevioletred" : "white"}; color: ${props => props.primary ? "white" : "palevioletred"}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; render( <div> <Button>Normal</Button> <Button primary>Primary</Button> </div> );

68747470733a2f2f71696974612d696d6167652d

Extending Styles

たった一回の使用のためだがわずかにcomponentを変化させ使いたいというときが頻繁にあると思う。
今まではテンプレート構文でfunctionを渡し、いくつかのpropsに基づきcomponentを変化させていたはずだ。
しかしそれにはstyleを一回変えるだけに多大な労力を要している。

別のcomponentをstyleを受け継ぐ新しいcomponentを簡単に作成するためには、ただstyled() constructorでラップしてあげれば良い。
ここでは一つ前の章で作ったボタンをベースに色のcolorのstyleを拡張した特別なボタンを作ってみる。

// The Button from the last section without the interpolations const Button = styled.button` color: palevioletred; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; // A new component based on Button, but with some override styles const TomatoButton = styled(Button)` color: tomato; border-color: tomato; `; render( <div> <Button>Normal Button</Button> <TomatoButton>Tomato Button</TomatoButton> </div> );

68747470733a2f2f71696974612d696d6167652d

2つのruleを付け加えるだけで、Buttonに似ている新しいTomatoButtonを作ることができた。

いくつかの場面でstyled componentがrenderするtagやcomponent
を変えたいときがある。
個々にstylingされているanchor linkやbuttonが入り交じるnavigation barを構築するときなどが典型例だ。

こういう場合のため回避法を用意している。
“as”というポリモーフィックを司るpropを使えば作成したstyleを受け取る要素を動的に変更することができる。

const Button = styled.button` display: inline-block; color: palevioletred; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; const TomatoButton = styled(Button)` color: tomato; border-color: tomato; `; render( <div> <Button>Normal Button</Button> <Button as="a" href="/">Link with Button styles</Button> <TomatoButton as="a" href="/">Link with Tomato Button styles</TomatoButton> </div> );

68747470733a2f2f71696974612d696d6167652d

カスタムcomponentに対しても完璧に動作する!

const Button = styled.button` display: inline-block; color: palevioletred; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; const ReversedButton = props => <button {...props} children={props.children.split('').reverse()} /> render( <div> <Button>Normal Button</Button> <Button as={ReversedButton}>Custom Button with Normal Button styles</Button> </div> );

68747470733a2f2f71696974612d696d6167652d

Styled Component

styleのターゲットが単純な要素(styled.divなど)なら、styled-componentsはHTMLの属性と知られるすべての値をDOMにパスする。
カスタムReact component(styled(Mycomponent)など)なら、styled-componentsはすべてのpropsをパスする。

この例はReact elements同様、Input componentのすべてのpropsがどのようにしてマウントされたDOM nodeに受け渡されるかを示している。

// Create an Input component that'll render an <input> tag with some styles const Input = styled.input` padding: 0.5em; margin: 0.5em; color: ${props => props.inputColor || "palevioletred"}; background: papayawhip; border: none; border-radius: 3px; `; // Render a styled text input with the standard input color, and one with a custom input color render( <div> <Input defaultValue="@probablyup" type="text" /> <Input defaultValue="@geelen" type="text" inputColor="rebeccapurple" /> </div> );

68747470733a2f2f71696974612d696d6167652d

これがinputColor propがDOMに渡されないが、typeとdefaultValueはDOMに渡される仕組みである。
それが自動的に標準でないattributesをフィルタしてくれるstyled-componentsである。

Coming from CSS

How do Styled Components work within a component?

もし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はstyleするelementとruleの組み合わせだから、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> ) } }

ここで”Styled”という接頭辞をStyledCounterに加えたことに注意してほしい。
これはReact componentのCounterとStyled ComponentのStyledCounterの名前が衝突せず、かつRect Developer ToolsとWeb Inspectorで用意に判別できるようにするためのものである。

Define Styled Components outside of the render method

renderメソッドの外でstyled componentsを定義することが重要である。
さもなければrenderの過程ごとに作り直されることになる。
renderメソッドの中にstyled componentを定義することはキャッシュを妨げrenderのスピードを劇的に低下させる。
したがって回避すべきことだ。

このようにstyled componentsを書くことが推奨される。
“javascript
const StyledWrapper = styled.div
/* … */
`

const Wrapper = ({ message }) => {
return {message}
}
“`

こんな感じではなく。

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

Recommended reading: Talia Marcassaが実際の利用法について有益な実践的洞察、代替案との比較について述べた素晴らしいレビューを書いている。
Styled Components: To Use or Not to Use?

Pseudoelements, pseudoselectors, and nesting

私達が使用しているプリプロセッサのstylisはネストするstylingに自動的に対応するためのscssライク文法をサポートしている。
例を出そう。

const Thing = styled.div` color: blue; `

疑似セレクターと疑似要素はこれ以上の改良を必要とせずcomponentに適用される。

const Thing = styled.button` color: blue; ::before { content: '🚀'; } :hover { color: red; } ` render( <Thing>Hello world!</Thing> )

68747470733a2f2f71696974612d696d6167652d

より複雑なセレクターには&を使うとcomponentそれ自身を参照できる。
考えられるいくつかの例をあげよう。

const Thing = styled.div.attrs({ tabIndex: 0 })` color: blue; &:hover { color: red; // <Thing> when hovered } & ~ & { background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it } & + & { background: lime; // <Thing> next to <Thing> } &.something { background: orange; // <Thing> tagged with an additional CSS class ".something" } .something-else & { border: 1px solid; // <Thing> inside another element labeled ".something-else" } ` render( <React.Fragment> <Thing>Hello world!</Thing> <Thing>How ya doing?</Thing> <Thing className="something">The sun is shining...</Thing> <div>Pretty nice day today.</div> <Thing>Don't you think?</Thing> Splendid. </React.Fragment> )

68747470733a2f2f71696974612d696d6167652d

セレクターを&なしで使用した場合にはcomponentのchildrenを参照することになる。

const Thing = styled.div` color: blue; .something { border: 1px solid; // an element labeled ".something" inside <Thing> display: block; } ` render( <Thing> <label htmlFor="foo-button" className="something">Mystery button</label> <button id="foo-button">What do I do?</button> </Thing> )

68747470733a2f2f71696974612d696d6167652d

最後に、&はcomponentへのruleの明確性を増すためにも使用できる。
これはstyled-componentsとバニラCSSが入り交じりstyleが競合する可能性のある環境で有用である。

const Thing = styled.div` && { color: blue; } ` const GlobalStyle = createGlobalStyle` div${Thing} { color: red; } ` render( <React.Fragment> <GlobalStyle /> <Thing> I'm blue, da ba dee da ba daa </Thing> </React.Fragment> )

68747470733a2f2f71696974612d696d6167652d

Attaching additional props v2

ただpropsをrenderされるcomponentやelementにわたすだけの不要なラッパーを取り除くために、.attrs constructorを使うことができる。
これにより追加のprops(もしくは”attributes”)をcomponentに適用することができる。

このようにスタティックなpropsと要素に適用したり、React RouterのLink componentへのactiveClassNameのような外部からのpropsを渡すことができる。
更により動的なpropsをcomponentに適用することもできる。
.attrs objectは関数も受け取ることができ、その関数はcomponentが受け取るpropsを引数として取ることができる。
その戻り値はその下で用いられるprops(例ではmarginとpaddingで用いられるprops)にマージされる。

Input Comonentにいくつかのスタティックattributeと動的なattributeを追加してみよう。

const Input = styled.input.attrs({ // we can define static props type: "password", // or we can define dynamic ones margin: props => props.size || "1em", padding: props => props.size || "1em" })` color: palevioletred; font-size: 1em; border: 2px solid palevioletred; border-radius: 3px; /* here we use the dynamically computed props */ margin: ${props => props.margin}; padding: ${props => props.padding}; `; render( <div> <Input placeholder="A small text input" size="1em" /> <br /> <Input placeholder="A bigger text input" size="2em" /> </div> );

68747470733a2f2f71696974612d696d6167652d

ご覧の通り.attrの中で作られた新たなpropsにアクセスすることができ、そしてtype attributeは要素に受け渡される。

Animations

@keyframesを用いたCSSアニメーションは一つのcomponentのscopeに限られていないが、それでも名前の衝突を防ぐためglobalスコープにしたくないと考えられる。
これがappを通してユニークなインスタンスを作るkeyframesヘルパーを導入した理由である。

// Create the keyframes const rotate = keyframes` from { transform: rotate(0deg); } to { transform: rotate(360deg); } `; // Here we create a component that will rotate everything we pass in over two seconds const Rotate = styled.div` display: inline-block; animation: ${rotate} 2s linear infinite; padding: 2rem 1rem; font-size: 1.2rem; `; render( <Rotate>&lt; 💅 &gt;</Rotate> );

注意:keyfmesはreact-nativeではサポートされていないので、代わりにReactNative.Animated APIを使おう。

keyframesは使用されたとき初めて遅延評価され、そうしてコードの分離を実現している。
そしてこういった場合shared style fragments向けのcss helperを使用しなければならない。

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; `

注意:v3以下のバージョンではkeyframesを用いたコード分離は行っておらず、上のエラーは起こらない。
v3より上のバージョンにアップグレードする場合には、必ずcss helperを使うようにしなければならない。

React Native

styled-componentsはReact Nativeでも同じ仕様法、import方法で利用できる。
以下の例をSnack by Expoを用いて実行してみてほしい。

import React from 'react' import styled from 'styled-components/native' const StyledView = styled.View` background-color: papayawhip; ` const StyledText = styled.Text` color: palevioletred; ` class MyReactNativeComponent extends React.Component { render() { return ( <StyledView> <StyledText>Hello World!</StyledText> </StyledView> ) } }

また普通arrayになるようなより複雑なstyles(transformなど)や、省略記法もcss-to-react-nativeのおかげでサポートできている。

注意:flex propertyはReact NativeではReact Nativeのレガシーなflex propertyではなく、CSSの省略記法として振る舞う。
flex: 1と設定することはflexShrink: 1とすることに等しい。

React Nativeのプロパティをどう書けばいいか、それをCSSに翻訳する方法を推測したなら、それは多分正しい。

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

webのstyled-componentsとの違いは、keyframesとcreateGlobalStyleヘルパーが使えないことだ。
なぜならReact Nativeはその両方をサポートしてないからだ。
またもしmediaクエリかネストさせたCSSを使用するときにも注意が必要だ。

注意:v2バージョンではパーセンテージ記法をサポートしている。
これを可能にするためすべての省略記法に向けunitを強化しなければならなかった。
もしv2に移行しているならば、codemodが使用できる。

Simpler usage with the metro bundler

styled-components/nativeの代わりに単純にstyled-componentsをimportしたいなら、"react-native"を含んだresolverMainFields configurationを使用しても良い。
これはデフォルトでmetroによってサポートされていたが(今はhaulでも動く)、どうやらいくつかの点で取り除かれてしまっているようだ。

まとめ

超速で訳したので間違いあれば言ってほしい。
疲れた。

Source: Javascriptタグが付けられた新着投稿

   ITアンテナトップページへ
情報処理/ITの話題が沢山。