逆引きstyled-components 共通コンポーネントをうまく作る5つの小技
ここのところstyled-componentsでのAtomicDesignの実装を考えていた。共通コンポーネント(Atomっぽいの)を書くときに役立つTips。 それ以外のときはあまり役立たないかもしれない。基本TypeScriptで真価を発揮すると思っています。(エディタ補完的な意味で)
react-routerのLinkにstyled-componentsを使いたい
styled.h1
, styled.p
みたいにHTMLにもともと存在するタグにstyled-componentsを使うのはよくある。Linkはどうなの?って聞かれたのでその時の見せた例。
調べてみたらDocsのstyling-any-componentsに書いてあった。
import styled from 'styled-components'
import { Link } from 'react-router-dom'
const StyledLink = styled(Link)`
text-decoration: none;
`
const HogeComponent = (props) => (
<StyledLink to='/'>No underline</StyledLink>
)
複数のボタンやバリエーションをキレイに書きたい
よくあるケース、ボタンみたいなバリエーションを作りたい時は、ベースとなるスタイルを定義して、継承させて別スタイルを当ててexportする。 Docsのextending-stylesで記載されている例。
import styled from 'styled-components'
const BaseButton = styled.a`
padding: 8px 16px;
color: white;
`
export const SuccessButton = BaseButton.extend`
background-color: green;
`
export const DisabledButton = BaseButton.extend`
background-color: gray
`
もう一つpropsで管理する方法もあるが、可読性的には上記のextendが好み。3項演算子が増えてくるとしんどい。
import styled from 'styled-components'
const BaseButton = styled.a`
padding: 8px 16px;
color: white;
background-color: ${props => props.primary ? 'blue': 'gray'};
`
同じスタイルを別のタグで使いまわしたい
styled-componentsで作ったコンポーネントにwithCompoent
を使うとベースのタグが変えられる。a => span
とかh1 => h2, h3, h4
とかのケース。
import styled from 'styled-components'
import { Link } from 'react-router-dom'
const MenuLInkItem = styled(Link)`
border-bottom: 3px solid transparent;
padding: 15px 12px 12px;
`
const MenuActiveItem = MenuLInkItem.withComponent('span').extend`
color: red;
border-bottom-color: #red;
`
定数や色を管理したい
別ファイルを作ってimportして使う。
export default {
primary: '#0a9b94',
secondary: '#efede0'
success: '#08837d',
warning: '#bf7600',
text: '#3c4a60'
}
styled-componentsのcssでスニペットみたいなのも作れる。font-familyとかSCSSでいうmixinみたいなものを定義しておくと良さげ。
import { css } from 'styled-components'
export const fontFamily = css`
font-family: "Lato", Arial, Emoji, "ヒラギノ角ゴPro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, "MS Pゴシック", sans-serif
`
export const fontFamilyDreamOrphans = css`
font-family: "DreamOrphans", Arial, sans-serif
`
export const truncateMultiLine = (lines) => css`
display: -webkit-box;
-webkit-line-clamp: ${lines};
-webkit-box-orient: vertical;
overflow: hidden;
`
Text系のスタイルが乱立するのでまとめたい
冗長と思う人もいるかもしれないが、1ファイルにまとめていくのがいいんじゃないかと思ってる。 Interface Inventoryっていう既存サイトの同じようなスタイルをまとめて一覧化するみたいな手法がある。それを模したコードを意識したらこのファイル構造になった。 既存サイトがあってデザインがバラバラみたいなシチュエーション(ある?)ではデザインガイドを作る時にこういったファイルが役立つのではないかと思っている。 共通化のスタート地点としてのファイル。
ここではcssで共通スタイルを書いて、それを各コンポーネントで読む方式で書いた。
import styled from 'styled-components'
const headingBaseStyle = css`
font-weight: 600;
color: #3c5064;
`
const BaseHeading1 = styled.h1`
${headingBaseStyle}
font-size: 20px;
letter-spacing: 1px;
`
export const Post = BaseHeading.extend`
margin-top: 6px;
`
export const PostSection = styled.h2`
${headingBaseStyle}
font-size: 20px;
margin-bottom: 16px;
`
export const Card = styled.h3`
${headingBaseStyle}
font-size: 13px;
`
正直AtomicDesignはエンジニアとデザイナーが協力しても難しいトピックなので自分の中でもあまり明確なゴールは描けていない。 AtomicDesignのボイラープレートみたいなものがあって、それをエンジニアとデザイナーでこなしていけば完成みたいな銀の弾丸はないだろうか?(いや、ない) 現状は、今あるデザインを共通箇所を見つけていって小さくしていくことが多そう。デザイナー的にこれを意識しながらAtomから作っていくのはしんどそう。
ただ、styled-componentsはAtomic Designでなくても使えるので便利に使っていきたいと思う。