styled-components で共通プロパティをまとめる4つの方法
※本記事は、ChatGPTとの対話をもとに生成AIを活用して執筆していますが、全体の構成と主張は筆者自身の考えによるものです。
React × styled-components でスタイルを記述していると、「同じスタイル何回も書いてるな…」と感じること、ありませんか?
この記事では、styled-components を使っているプロジェクトで「共通プロパティをどうまとめるか」について、代表的な方法を4つ紹介します。それぞれの特徴や使うと嬉しいシチュエーションもあわせて解説します。
css
ヘルパーで共通スタイルを定義
1. 最もシンプルな方法が styled-components
に含まれる css
ヘルパーを使う方法です。
// styles/common.ts
import { css } from 'styled-components';
export const commonButtonStyle = css`
padding: 8px 16px;
border-radius: 8px;
font-weight: bold;
`;
// components/Button.tsx
import styled from 'styled-components';
import { commonButtonStyle } from '../styles/common';
const PrimaryButton = styled.button`
${commonButtonStyle};
background-color: blue;
color: white;
`;
const SecondaryButton = styled.button`
${commonButtonStyle};
background-color: gray;
color: black;
`;
2. ベースコンポーネントを作成して拡張
共通スタイルをベースの styled コンポーネントに持たせて、それを継承する方法です。
// components/BaseButton.tsx
import styled from 'styled-components';
export const BaseButton = styled.button`
padding: 8px 16px;
border-radius: 8px;
font-weight: bold;
`;
// components/PrimaryButton.tsx
import styled from 'styled-components';
import { BaseButton } from './BaseButton';
export const PrimaryButton = styled(BaseButton)`
background-color: blue;
color: white;
`;
✅ ポイント
ベースコンポーネントでは、スタイルに加えて「HTMLタグや属性の共通化」も可能です。
たとえば、BaseButton
を a
タグや div
タグとして使いたい場合、as
属性を使ってタグの差し替えができます。
as="a"
を使うとは?
以下のように記述すると、HTML上では <a>
タグとして出力されます:
<BaseButton as="a" href="/about">About</BaseButton>
出力されるHTML:
<a href="/about" class="...">About</a>
スタイルは BaseButton
のまま、タグだけが a
に変わるため、
「見た目はボタン、動作はリンク」 のようなUIも簡単に実現できます。
as
は styled-components 独自の機能
補足:as
属性は React の標準機能ではありません。
これは styled-components(や Emotion などの CSS-in-JS ライブラリ)独自の機能で、
as
に渡されたタグ名やコンポーネントを使って動的に JSX を出力しています。
そのため、通常の React コンポーネントに as="..."
を指定しても動作しません。
as
を使えるのは、styled-components でラップされたコンポーネントに限られます。
3. テーマを使って共通スタイルを変数化
ThemeProvider
を使えば、デザインのトークン(色・サイズなど)をアプリ全体に渡すことができます。
// theme.ts
export const theme = {
button: {
padding: '8px 16px',
borderRadius: '8px',
fontWeight: 'bold',
},
};
// Button.tsx
import styled from 'styled-components';
const Button = styled.button`
padding: ${({ theme }) => theme.button.padding};
border-radius: ${({ theme }) => theme.button.borderRadius};
font-weight: ${({ theme }) => theme.button.fontWeight};
`;
ThemeProvider
の使い方
テーマを使うには、アプリのルート付近で ThemeProvider を使ってテーマを提供する必要があります。
import { ThemeProvider } from 'styled-components';
import { theme } from './theme';
import { Button } from './Button';
function App() {
return (
<ThemeProvider theme={theme}>
<Button>Click me</Button>
</ThemeProvider>
);
}
これによって、styled-components の中で props.theme にアクセスできるようになります。
4. mixin化(関数化)して再利用
細かいスタイルや条件付きで使いたいものは、mixin(スタイルの関数化)すると便利です。
import { css } from 'styled-components';
export const ellipsis = css`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
export const responsiveFontSize = (size: number) => css`
font-size: ${size}px;
@media (max-width: 768px) {
font-size: ${size * 0.8}px;
}
`;
const Title = styled.h1`
${responsiveFontSize(24)};
`;
補足:方法4は方法1の派生テクニック
方法4(mixin)は、方法1(cssヘルパー)を関数化して柔軟性を持たせた進化形です。
最初は方法1で共通化しておいて、あとから条件分岐やパラメータが必要になったときに方法4へスケールアップする、というのが自然な流れです。
4つの手法の比較表
方法 | 特徴 | 採用を検討すべきケース |
---|---|---|
css ヘルパー |
スタイルの断片をそのまま再利用できる | 同じ見た目のUIを複数のコンポーネントで使い回したいとき |
ベースコンポーネント | HTMLタグや属性も含めて共通化できる | UIの種類ごとにタグや属性、スタイルをまとめて再利用したいとき |
テーマ | デザインのトークン管理や切り替えに強い | デザイナーと連携した設計や、テーマの切り替えが必要なとき |
mixin(関数) | 引数で柔軟にスタイルを出し分けられる | サイズや状態によってスタイルを調整したいとき |
おわりに
styled-components を使っていると「このスタイル、他でも使いたいな」と思うことがよくあります。
まずは css
で共通化 → 条件付きになったら mixin にスケールアップ
レイアウト構造も含めてまとめたくなったらベースコンポーネント化
さらにデザイン全体で共通化したくなったらテーマへ…
というように、状況に応じて段階的に使い分けていくのがオススメです!
参考リンク
-
styled-components ドキュメント
基本的な使い方から高度な活用方法までを網羅した公式ドキュメント。 -
Theming(styled-components公式)
ThemeProvider
を使ったテーマ管理の方法について解説しているセクション。 -
Extending Styles(styled-components公式)
既存の styled-components を拡張して再利用する方法についての公式解説。
Discussion