Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

CSS-in-JS 辛くね?

Last updated at Posted at 2020-06-07

1. シンプルな例

<Title>hello</Title>
  • title を当てるとタイトルのスタイルになる
  • タイトルの色はテーマとして変更可能

SCSS

.title {
	font-size: 36px;
	color: $title-color;
}

CSS-in-JS

import styled from 'styled-components';

const Title = styled.h1`
  font-size: 36px;
  color: ${props => props.theme.titleColor};
`;

まだ辛くない

2. オプション的に見た目を変えたいとき(バリアント)

(
  <Button variant="primary" />
  <Button variant="secondary" />
)
  • primarysecondaryを指定すると、色が変わる
  • primarysecondaryの色はテーマとして変更可能
  • font-size: 12px は共通のスタイル

SCSS

.button {
  font-size: 12px;

  .primary {
    color: $primary-fg-color;
    background-color: $primary-bg-color;
  }

  .secondary {
    color: $secondary-fg-color;
    background-color: $secondary-bg-color;
  }
}

CSS-in-JS (Template literal)

import styled from 'styled-components';

const Button = styled.button`
  font-size: 12px;

  ${
    (props) => props.variant === 'primary'
      ? css`
        color: ${props.theme.primaryFgColor};
        background-color: ${props.theme.primaryBgColor};
      `
      : css`
        color: ${props.theme.secondaryFgColor};
        background-color: ${props.theme.secondaryBgColor}
      `;
  }
`;
  • 一気に複雑さが増す。
  • テンプレートリテラルの中でテンプレートリテラルを使っていて気持ち悪い
  • cssの中か外かで、関数で変数を選択するかそのまま使うか違っていて頭を使う
  • そもそもthemeに関してはネストした時点で2通りの書き方が存在してしまう。

CSS-in-JS (Object)

import styled from 'styled-components';

const Button = styled.button(
  {
    fontSize: '12px',
  },
  props => ({
    return props.variant === 'primary'
      ? {
          color: props.theme.primaryFgColor,
          backgroundColor: props.theme.primaryBgColor
        }
      : {
          color: props.theme.secondaryFgColor,
          backgroundColor: props.theme.secondaryBgColor
        };
	),
);
  • 上と比べるとテンプレートリテラルが無い分読みやすい
  • stylelintが動かなくなる

CSS-in-JS (styled-system)

import styled from 'styled-components';
import { variant } from 'styled-system';

const Button = styled.button(
  {
    fontSize: '12px',
  },
  variant({
    prop: 'variant',
    variants: {
      primary: {
        color: 'colors.primaryFg',
        backgroundColor: 'color.primaryBg',
      },
      secondary: {
        color: 'colors.secondaryFg',
        backgroundColor: 'colors.secondaryBg',
      },
    },
  }),
);
  • variant === 'primary' みたいなボイラープレートがなくなってだいぶ読みやすい
  • styled.something() の引数は prop → CSS にもできるから、型は付けられる。
  • stylelintが動かない

CSS-in-JS (xstyled)

import styled from 'styled-components';
import { varinat, css } from '@xstyled/system';

const Button = styled.button`
  font-size: '12px',
  ${variant({
    default: 'primary',
    variants: {
      primary: css`
        color: primaryFg,
        backgroundColor: primaryBg,
      `,
      secondary: css`
        color: secondaryFg,
        backgroundColor: secondaryBg,
      `,
    },
  })},
);
  • styled-systemのバリアントとだいたい同じ
  • デフォルト値が付けられる
  • css関数が使えるのでかろうじてstylelintが動く

3. 子要素をオーバーライドしたいとき

<Article>
  <Button />
</Article>
  • .button.article がある
  • .article > .button は、フォントサイズが2px分大きくなる

SCSS

.button {
  font-size: 12px;
}

.article {
  .button {
    font-size: 14px;
  }
}

CSS-in-JS

import styled from 'styled-components';

const Button = styled.button`
  font-size: 12px;
`;

const Article = styled.article`
  ${Button} {
    font-size: 12px;
  }
`;
  • Emotionはbabel pluginが必要になる

CSS-in-JS (Buttonが少しでもロジックを持っている場合)

import styled from 'styled-components';

const Wrapper = styled.button`
  font-size: 12px;
`;

const Button = ({ children, ...rest }) => {
  const submit = useSubmit();

  return (
    <Wrapper {...rest} onClick={submit}>
      {children}
    </Wrapper>
  );
}

const Article = styled.article`
  ${Wrapper} {
    font-size: 12px;
  }
`;
  • Component selectorが使えるのはstyled component限定なので、コンポーネントがstyledか否かを把握しないといけない。
  • SFCの外から拡張したいときに、Wrapperの存在が漏れてしまうので、カプセル化できていない
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?