こんにちは、Baseconnectのエンジニアインターンの大島です。 この記事では私が主に開発を行っているMusubuのフロントエンドの技術スタック、特にCSSフレームワークに注目して紹介したいと思います。
Musubuのスタイリング
Musubuの開発ではCSSフレームワークに、styled-componentsとxstyledを用いて開発を行っています。
今回は聞き馴染みがない方が多いであろうxstyled
について注目し、Baseconnectでの使われ方も合わせて紹介したいと思います。
xstyledとは
xstyledはReact開発におけるpropsベースのCSS in JSフレームワークです。 styled-componentsやemotionに互換性があり、すでにこれらのCSS in JSを用いて開発を行っているプロダクトには簡単に導入ができます。
コンポーネント例
import { x } from '@xstyled/styled-components' type ButtonProps = typeof x.button.defaultProps & { leftIcon?: React.ReactNode } const Button = ({children, disabled, leftIcon, ...props}: ButtonProps) => { return ( <x.button w="60px" fontWeight="bold" backgroundColor={disabled ? 'blue-500' : 'blue-400'} {...props} > {leftIcon && <IconWrapper>{lefIcon}</IconWrapper>} {children} </x.button> ) }
xstyledを使うことによるメリット
- utility first
- 命名コストがない
- presentational componentなのか、styled-componentなのか迷わない
- レスポンシブ対応や擬似クラスも容易に対応可能
- 開発速度の向上
などが挙げられます。一つずつ見ていきます。
1. utility first
xstyledでは、各タグに<x.*>
をつけることでpropsでスタイルを当てることができます。そのため、事前にスタイルを当てるためのCSSを宣言する必要はありません。
また、カスタムCSSを一行も記述することなく、完全にカスタム化されたコンポーネントデザインを実装することができます。
たとえば、spaceX
propsであれば、通常以下のCSSを記述する必要がありますが、xstyledなら、1行で済みます。
--x-space-x-reverse: 0; margin-right: calc({space} * var(--x-space-x-reverse)); margin-left: calc({space} * calc(1 - var(--x-space-x-reverse)));
2. 命名コストがない
これは私としてはかなり大きいメリットだと感じています。 styled-componentでは、それぞれstyleに対して命名する必要があるかと思います。これは開発者にとって脳に無駄なリソースを割くことになるため精神安定上良くないと思っています。 xstyledでは先の例で示したとおり、propsに渡すことでスタイルを当てることができるため命名の必要がありません。
これが解決できるだけでも十分なメリットがあると感じています。
3. presentational componentなのか、styled-componentなのか迷わない
styled-componentを使って開発を行っていると、これがstyled-componentなのか、presentationalなコンポーネントなのかがわからないということが頻繁に起こります。そのたびに、そのコンポーネントを参照してどちらなのかを確認することが必要になります。
命名規則をもたせることで解決できることもあるかもしれないですが、規則があったとしても命名コストはつきまとってきます。
xstyledならどのタグにどのスタイルがあたっているか一目瞭然となり見通しも良くなります。
4. レスポンシブ対応や擬似クラスも容易に対応可能
Musubuでは詳細な企業情報を扱ったり、営業リストを作成する機能を備えているため、モバイル端末をメインで扱っていません。 しかし、あらゆるユーザーを想定し、最低限のレスポンシブ対応を行っています。その際にxstyledは非常に容易に定義できます。
styled-componentの場合、メディアクエリを用いて以下のように定義する必要があるかと思います。
const Wrapper = styled.div` display: "block"; background-color: "#fff"; &:hover { background-color: "#000"; } @media (min-width: 768px) { display: "flex"; } ` const ExampleComponent = () => { return ( <Wrapper> <div>...</div> <div>...</div> </Wrapper> ) }
xstyledを用いることで簡潔に記述することができます。
// xstyledの場合 const ExampleComponent = () => { return ( <x.div display={{ _: "block", md: "flex" }} bg={{ _: "#fff", hover: "#000" }} > <x.div>...</x.div> <x.div>...</x.div> </x.div> ) }
5. 開発速度の向上
xstyledはTypeScriptで開発されているため、型の恩恵を受けられます。そのため、styled-componentでよくあるtypoによってstyleが付与されないという問題を解決することができます。
また、styled-componentの場合、条件によって付与するスタイルが異なる場合、かなり冗長なコードになると思います。しかし、xstyledはpropsベースのため、条件分岐を簡単に書くことができます。
さらに、特に個人で開発を行う際など、colorやspaceなど全て自分で決めるのは少々面倒なこともあります。xstyledでは、v2以降TailwindCSSに影響を受けているため、デフォルトでいい感じのThemeファイルを用意してくれています。
xstyledのデメリット
ここまでメリットについて述べてきましたが、デメリットについてもいくつか上げたいと思います。
これらの理由により、ある程度の規模のプロダクトでxstyled単体での利用は難しいと感じています。 そのため、styled-componentやemotionと併用して用いることで快適なフロントエンド開発を行えると思います。
Musubuでの活用事例
ここからは、Musubuでのxstyledの活用事例について紹介したいと思います。
theme file
xstyledではデフォルトでいい感じのthemeファイルを用意してくれています。 Musubuではデフォルトのthemeファイルを使わず、オーバーライドすることでデザインシステムを構築しています。
styled-component と xstyledの使い分け
Musubuではxstyledをベースに開発を行っています。しかし、先に述べたとおり、疑似要素を扱えないためbefore
やnot(:first-child)
などを使いたいときにstyled-componentを使っています。
さらに、styled-componentを作成する際に@xstyled/styled-component
からimportすることで、xstyledの恩恵を受けながらstyled-componentで複雑な疑似要素を扱えるようになります。
import styled, { x } from '@xstyled/styled-component' const Wrapper = styled(x.div)` &:before { ... } ` const ExampleComponent = () => { return ( <Wrapper w="1200px" bg="gray-100"> ... </Wrapper> ) }
これにより最大限見通しを良くした状態でstyleを当てることが可能になります。
最後に
ここまで読んでいただきありがとうございます。Musubuのフロントエンド開発で用いられるCSSフレームワークについて書いてきました。
styled-component
やemotion
に辛みを感じている方にとって、何か役に立てましたら嬉しいです。
もし今後の技術選定に関わっていきたい方や、もう少し詳しい話を聞いてみたいという方、ぜひカジュアルにお話ししましょう! Baseconnectではエンジニアメンバーも絶賛募集しています。