関連

styled

styled-componentsからstyled(default)をインポートして使います。styled[htmlタグ名]にはそれぞれタグ付けテンプレート構文になっているのでここに CSS を書いていくだけでスタイル付けした要素を作ることができます。実際には

  1. 定義した CSS にstyled-componentsが適当なクラス名を振る

  2. それを実際に使っている要素のclassNameに指定する

といった感じのことをやっています。

以下はスタイル付けdiv要素を作っている例です。

import styled from 'styled-components';

const StyledDiv = styled.div`
  padding: 1em;
`;

foo

作られた要素はそのまま React コンポーネントとして使うことができます。

動的スタイル・動的属性

普通の React コンポーネントがpropsを渡せるようにstyled-componentsで作った要素にもpropsを扱える仕組みがあります。それにはタグ付けテンプレート構文の中に関数を埋め込みます。関数を埋め込むとそれにはpropsが渡ってくるのでそれを好きなように触って目的の値を返すようにします。

const MARGIN = '1em';

const StyledDiv = styled.div`
  padding: ${props => props.padding || 0};
  margin: ${MARGIN};
`;

foo
// padding: 1em;
// margin: 1em;

ちなみに埋め込みには関数以外を指定するとそのまま出力されます。

属性の場合は、attrsというメソッドがあるのでこれでpropsを受け取るコールバックを定義します。以下はtitle属性値を少し編集してる例ですが、このように好きな属性値のオブジェクトを返すようにするといいです。

const StyledDiv = styled.div.attrs(props => {
  return {
    title: `edited ${props.title}`
  }
})`
  // ...
`;

共通スタイル

styled-componentsが提供しているcssヘルパーを使うことで共通部分を分けることができます。特にpropsを扱いたいときの共通部分の切り出しには必須です。

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

const common = css`
  padding: ${props => props.padding || 0};
`;

const StyledFooDiv = styled.div`
  ${common};
  margin: 1em;
`;

const StyledBarDiv = styled.div`
  ${common};
  margin: 2em;
`;

テーマ

親階層でThemeProviderコンポーネントを使うことでそれ以下のすべてのstyled要素のprops.themeに値を渡せます。全体を通して一貫した動的な値を渡すことができます。

import styled, {ThemeProvider} from 'styled-components';

const StyledDiv = styled.div`
  padding: ${props => props.theme.padding || 0};
`;

const App = () => (
  
);

const Root = () => (
  
    
  
);

styledに対して既存の Styled なコンポーネントを渡すと、その要素のスタイルに加えて当たらなスタイルを当てた新しい要素を作れます。渡す時は関数の引数として渡します。

const BaseElement = styled.div`
  font-size: 14px;
`;

const ColorOrangeElement = styled(BaseElement)`
  color: orange;
`;

上記のColorOrangeElementは、

  • タグは<div>

  • スタイルはfont-size: 14px; color: orange;

な要素になっています。

もし<div>タグも変えたい場合は Styled なコンポーネントが持つwithComponentメソッドで変えることができます。例えば以下のようにすると<span>に変更できます。

const ColorOrangeElement = styled(
  BaseElement.withComponent('span')
)`
  color: orange;
`;

styledの引数に React コンポーネントを渡すとレンダリング時、そのプロパティに Styled Components がランダムに生成したclassNameが渡されます。

const Foo = props => {
  return 
...
}; const StyledFoo = styled(Foo)` color: orange; `; // ...

コンポーネントの構造が複雑な時、それら全てにclassNameをクラスに付与することで.scope.my-classNameのようなスコープを付きのセレクタでスタイル付けできるようになります。

またその時styledの中で.scope&と書くことができるので、実際には&.my-classNameと書くことができます。

const Foo = props => {
  return (
    
...
); }; const StyledFoo = styled(Foo)` &.first { color: orange; } &.second { width: 980px; margin: 0 auto; } &.third { display: inline-flex; } `;

cssをラップするとメディアクエリが楽に書けるようになります。

css

この関数は、styled[element]テンプレートリテラルの中でさらに同じような書き方で書いたスタイルを埋め込みたい時につかいます。共通部分のスタイルを外部にまとめたいときとか便利なやつです。

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

const margin = css`
  ${props => props['data-margin'] || '10px'};
`;

const Div = styled.div`
  margin: ${margin};
`;

marginstyled.divmarginprops

css${desktop...}...

const desktop = (first, ...interpolations) => css`
  @media (max-width: ${sizes[label]}px) {
    ${css(first, ...interpolations)}
  }
`;

media.desktopmedia.tablet

import {css} from 'styled-components';

const sizes = {
  desktop: 992,
  tablet: 768,
  phone: 576,
};

const media = Object.keys(sizes).reduce(
  (acc, label) => {
    acc[label] = (first, ...interpolations) => css`
      @media (max-width: ${sizes[label]}px) {
        ${css(first, ...interpolations)}
      }
    `;

    return acc;
  },
  {},
);

import {css, CSSObject, SimpleInterpolation} from 'styled-components';

const sizes: {[index: string]: number} = {
  desktop: 992,
  tablet: 768,
  phone: 576,
};

const media = Object.keys(sizes).reduce(
  (acc, label) => {
    acc[label] = (
      first: TemplateStringsArray | CSSObject,
      ...interpolations: SimpleInterpolation[]
    ) => css`
      @media (max-width: ${sizes[label]}px) {
        ${css(first, ...interpolations)}
      }
    `;

    return acc;
  },
  {} as {[index: string]: Function},
);

createGlobalStyleを使います。これはタグテンプレートになっていて、 CSS を書いて実行するとGlobalStyle(名前はなんでもいい)をコンポーネントを返します。これはレンダリング時にタグテンプレートに渡した CSS を<head>領域に追加してくれます。

createGlobalStylestyled-componentsから取り込めます。

import {createGlobalStyle} from 'styled-components';

あとはstyled.divのあとのようにスタイルを書くだけです。コンポーネントの中(children)には何も入れてはいけません。

const GlobalStyle = createGlobalStyle`
  html,
  body {
    height: 100%;
  }
`;

() => (
  <>
    
    
      
    
  
);

スナップショットテストをする時は、そのままでは毎回ランダムなクラス名が設定され2回目以降毎回失敗するようになってしまいます。

Jest 環境ではjest-styled-componentsを使う事で、Styled Components が生成したクラス名を静的にレンダリングされた結果から取り除いてくれます。

使うにはまずこれをインストールし、

yarn add -D jest-styled-components

テストファイルでただ読み込みます。

import Foo from './foo-component';
import 'jest-styled-components';

test(...args);

jest-styled-componentsモジュールを使うことで「このコンポーネントはcolororangeで持ってるはず」をテストできます。

使うにはスナップショットの時などと同じくjest-styled-componentsをただインポートすれば、toHaveStyleRuleというマッチャーが使えるようになります。

ここでは@testing-library/reactと共に使い方を見ていきます。

使い方

toHaveStyleRulesは styled-components のルートとなる要素に対して使用するマッチャーです。

基本

@testing-library/reactを使っているので軽く説明すると、以下のコードは`、

  1. queryByRole<button>

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled.button`
  color: orange;
`;

test("the color of the component is orange", () => {
  const renderResult = render(

<button>#toHaveStyleRule("color", "orange")color: orange

colorexpectexpect.anycolor

expect(renderResult.queryByRole("button")).toHaveStyleRule(
  "color",
  expect.any(String)
);

styled-components
button { }

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled(({ className }) => {
  return 

modifier

color: bluecolor: orange

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled(({ className }) => {
  return 

media

styled-components

const Span = styled.span``;

const Button = styled.button`
  ${Span} {
    color: orange;
  }
`;

import React from "react";
import styled, { css } from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Span = styled.span``;

const Button = styled(({ className }) => {
  return (
    
  );
})`
  ${Span} {
    color: orange;
  }
`;

test("the color of the component is orange", () => {
  const renderResult = render(

modifierstyled-componentscss

git cloneyarn && yarn test

JavaScript で飯食べたい歴約 9 年、 純( nju33 ) によるノートサイトです。

このサイトではドリンク代や奨学金返済の為、広告などを貼らせて頂いてますがご了承ください。

Change Log