Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
styled-componentsの使い方(パッとわかりやすく、色々なパターンを説明することを目指しています)

styled-componentsの使い方(パッとわかりやすく、色々なパターンを説明することを目指す記事)

styled-compoents

本家ドキュメント

こちらはStyled-componentsの使い方、ユースケースを集めた端的なページです。
なにかの問題解決、参考になりましたらスターを押してくださいませ。励みになります。
随時更新中

更新情報

  • 2020/1/4
    • 絵を更新
  • 2020/1/3
    • backgroundでsvgを読み込む
    • .activeをクラスに追加した際のスタイル
    • attrsのpropsの渡し方を4.1.1で修正された内容に変更

index

  • styled-componentsを使う為の前提
  • styled-componentsの最小の指定
  • ``は何??
  • defaultPropsとして指定する
  • 呼び出し時指定する
  • styled-componentsの拡張の仕方
  • styleは一緒でタグだけ変えたい場合
  • styleは一緒でタグだけ変えた後拡張したい
  • componentからのpropsをstyledへのpropsに渡せる。連結させる。
  • styled-componentsとTypeScript
  • レイアウトの組み方の一例(how to layout with styled-components)
  • styled-componentsにおける擬似要素の指定方法
  • mixinやattrsなどaタグのhref設定
  • background指定する
  • isOpen(boolean)の時だけスタイルを追加する(.active)
  • styled-ComponentされたComponentをデバッグ時にDisplayNameとして表示させる設定
  • iconをstyled-components化する(background-image: url())
  • mediaQuery対応
  • お役立ちライブラリ

styled-componentsを使う為の前提

//importする
import styled from 'styled-components'

styled-componentsの最小の指定

styled

const Button = styled.button`
  color: red;
`
//render
<Button>ボタン</Button>

``は何??

styled-componentで使われているTaggedTemplateLiterals

styled.button`` styled.button()は同じ 違いは引数を渡すと値になるかだけ

const logArgs = (...args) => console.log(...args)

これはただの引数を渡したら渡された引数を出力する関数だ

単純に

logArgs('a', 'b');
//-> a b

じゃあtagged template literalで呼んでみよう

logArgs``
//-> [""]

続きWIP

defaultPropsとして指定する

const Button = styled.button`
  color: red;
  backgroun: ${(theme) => thme.main}
`
Button.defaultProps = {
  theme: {
      main: "#0088ee"
  }
}

呼び出し時指定する

const Button = styled.button`
  color: ${({theme}) => theme.main};
  border: 2px solid ${({theme})=> theme.main};
`
//render
<Button theme={{main: red}}></Button>

styled-componentsの拡張の仕方

const Button = styled.button`
  color: red;
`
const ButtonExtend = Button.extend`
  border-color: green
`

styleは一緒でタグだけ変えたい

const Button = styled.button`
  color: red;
`
const StyledLink = Button.withComponent('a')

//render
<Button>ボタン</Button>
<StyledLink>リンク</StyledLink>

styleは一緒でタグだけ変えた後拡張したい

withComponent

const Button = styled.button`
  color: red;
`
const StyledLink = Button.withComponent('a')
const StyledLinkEx = StyledLink.extend`
  color: red
`

componentからのpropsをstyledへのpropsに渡せる。連結させる。

attrs

  • 呼び出し時に渡したpropsを元に動的に変更する
  • staticなprops記述もできる
const Button = styled.button.attrs(props => ({
    type:'password',//staticなprops
    margin: props.size || '1em',//sizeとして受け取りmappingしている
    padding:props.size || '1em'//sizeとして受け取りmappingしている
    //共通部分はこの下に書く
}))`
    font-size: 1em;
    border-radius: 3px;
    margin: ${props => props.margin};//上で定義したmarginを受け取る
    padding: ${props => props.padding};//上で定義したpaddingを受け取る
`

//render
<Button>ボタン</Button>
<Button size="2em">ボタン</Button>

//最終的にViewされるHTML
<button type="password" margin="1em" padding="1em" class="sc-htpNat fTzOaU">ボタン</button>
<button type="password" margin="2em" padding="2em" class="sc-htpNat fTzOaU">ボタン</button>

styled-componentsとTypeScript

template literal内でのprops値によってstyleを変える際に出るcompileエラーを避ける

https://github.com/styled-components/styled-components/issues/630#issuecomment-315475109

レイアウトの組み方の一例(how to layout with styled-components)

Paddingというコンポーネントは全てのコンポーネントのpaddingに責務を持つ →Styleに依存しないミニマムなコンポーネントができる

例えば

export const Padding = styled.div`
  padding-top: ${(props) => props.top}px;
  padding-right: ${(props) => props.right}px;
  padding-bottom: ${(props) => props.bottom}px;
  padding-left: ${(props) => props.left}px;
`
Padding.defaultProps = {
  top: 0,
  right: 0,
  bottom: 0,
  left: 0
}

をutlisとして作り、

呼び出し側では

 <Padding top={30} right={20} bottom={20} left={20}>
    <Some />
 </Padding>
  <Padding top={10} right={10}>
    <Some />
 </Padding>

リアルに使っているユーティリティstyledコンポーネント

export const Padding = styled.div`
  padding-top: ${(props) => console.log("padding", props) || props.top}px;
  padding-right: ${(props) => props.right}px;
  padding-bottom: ${(props) => props.bottom}px;
  padding-left: ${(props) => props.left}px;
`
Padding.defaultProps = {
  top: 0,
  right: 0,
  bottom: 0,
  left: 0
}

export const Margin = styled.div`
  margin-top: ${(props) => props.top};
  margin-right: ${(props) => props.right};
  margin-bottom: ${(props) => props.bottom};
  margin-left: ${(props) => props.left};
`
Margin.defaultProps = {
  top: "0px",
  right: "0px",
  bottom: "0px",
  left: "0px"
}

export const Text = styled.span`
  display: ${props => props.disp};
  text-align: ${props => props.ta};
  font-size: ${props => props.fs};
  color: ${props => props.color};
  font-weight: ${props => props.fw};
  line-height: ${props => props.lh};
`
Text.defaultProps = {
  "display": "inline",
  "text-align": "left",
  "font-size": "12px",
  "color": "#4B5467",
  "font-weight": "normal",
  "line-height": "1px"
}

export const Border = styled.div`
  border-top: ${(props) => props.top} solid ${(props) => props.color};
  border-right: ${(props) => props.right} solid ${(props) => props.color};
  border-bottom: ${(props) => props.bottom} solid ${(props) => props.color};
  border-left: ${(props) => props.left} solid ${(props) => props.color};
`
Border.defaultProps = {
  top: "0px",
  right: "0px",
  bottom: "0px",
  left: "0px",
  color: "#c9d2db"
}

export const Strong = styled.span`
  font-size: ${props => props.fs};
  color: ${props => props.color};
  font-weight: 600;
`
Strong.defaultProps = {
  "font-size": "14px",
  "font-color": "#262626"
}

こうすることでSomeはpaddingに依存しない原子なComponentとしてどこにでも置ける

styled-componentsにおける擬似要素の指定方法

import styled from 'styled-components';

export const Paaan = styled.div`
  text-align: center;
  &::before,
  &::after {
    position: absolute;
    top: 0;
    some...
  }
  &::before {
    transform: skewX(25deg);
    left: 0;
  }
  &::after {
    transform: skewX(-25deg);
    right: 0;
  }
`

mixinやattrsなどaタグのhref設定

import styled, {css} from 'styled-components'

//ボタンの種類(border-colorと背景色)を定義
const colors = {
  secondary: {borderColor: '#8db909', bg: '#6c8d0a'}
}

//共通で使うプロパティ-値をmixinとして定義
const ButtonStyle = css`
  display: inline-block;
  width: 100%;
  padding: 0;
`

export const ButtonLink = styled.a.attrs({
  href: props => props.href//aタグなのでhrefをそのまま設定,
  target: props => (props.target === '_new' ? props.target : '_self')
})`
  ${ButtonStyle}//共通で使うプロパティをmixinを呼んでいる
  background-color: ${(props) => colors[props.type]["borderColor"]};//ここで種類によって分けている
  color: #fff;
  border-color: ${(props) => colors[props.type]["bg"]};
`

///use
<ButtonLink
  type="secondary"
  href={`https://some.jp`}
  target={'_new'}
>
  ボタン
</ButtonLink>

background指定する

import profile from 'assets/img/profile.svg'
.
.
.

const ProfileButton = styled.button`
  width: 100%;
  padding: 14px 0;
  color: #9b9b9b;
  &:before{
    content: url(${profile}); // here
    margin-right: 9px
  }
`

or

<Content img={ImagePath} />
.
.
.
const Content = styled.div`
    background-image: url(${props => props.img});
`;

isOpen(boolean)の時だけスタイルを追加する(.active)

<ProfileButton isOpen={props.isOpen} onClick={props.handleClickProfile}>
.
.
.
const ProfileButton = styled.button`
  width: 100%;
  padding: 14px 0;
  color: #9b9b9b;
  &:before{
    content: url(${profile});
    margin-right: 9px
  }
  ${({ isOpen }) => isOpen && `
      border-bottom: solid 2px #de552b;
      font-weight: bold;
      color: #000;
      background: #fff9ee;
  `}
`

or

     <Tab
            onClick={props.handleClickMatch(detail.matchDate)}
            className={detail.matchDate === props.matchTabId ? 'active' : ''}
          >
          
.
.
.

const Tab = styled.div`
  color: #9b9b9b;
  width: 100%;
  padding: 15px 0;
  &.active {
    border-bottom: solid 2px #de552b;
    color: #000000;
  }
`

Styled-ComponentされたComponentをデバッグ時にDisplayNameとして表示させる設定

下記該当箇所をbabel設定に多くはpackage.jsonやbabel設定ファイル

  "babel": {
    "presets": [
      "react-app"
    ],
    ///////////ここ//////////////
   "plugins": [
      ["babel-plugin-styled-components", {
        "displayName": true
      }]
    ]
    ///////////ここまで//////////////
  },

iconをstyled-components化する(background-image: url())

backgroundImageはfile自体をimportして設定する

//utils/styledComponent.js

import male from '../../assets/icon/male.png';//importする
import female from '../../assets/icon/female.png';//importする
.
.
.
export const IconEmployee = styled.span`
  width: 68px;
  height: 68px;
  border-radius: 100px;
  flex: 0 0 68px;
  background-color: #fff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  background-image: url(${({isMale}) => isMale ? male : female});
`

//someComponent.js

<IconEmployee isMail={gender === 1} />

mediaQuery

// style-utils.jsというutilsを作る
import { css } from 'styled-components';


export const media = {
  handheld: (...args) => css`
    @media (min-width: 1279px) {//ここにデバイス幅を指定
      ${css(...args)};
    }
  `,
  handheld320: (...args) => css`
    @media (max-width: 374px) {//375px未満
      ${css(...args)};
    }
  `
};

///////////////////
////読み込み側では
import styled from 'styled-components';
import { media } from '../Utils/style-utils';

export const Paaan = styled.div`
  text-align: center;
  ${media.handheld` //ここで使う
    width: 270px;
  `}
  font-weight: 700;
  position: relative;
  margin: 0 auto;
  .
  .
  .
  some

お役立ちライブラリ

mixinを呼び出してくれるpolishedのドキュメント

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment