Css in Js is 何
- CSS in JSは、JavaScriptの中にCSSの記述を取り込んでしまう手法
- styled-compornent,glamorous,Emotion,Linariaなどのライブラリが存在
- 最も有名なのが、今回ご紹介するstyled-compornent
事前準備
インストール
npm install --save styled-components
// with Ts
npm install @types/styled-components
// or
yarn add styled-components
任意のjsxファイル内でimport
import styled from 'styled-components';
基本的な特徴
- CSSで表現できるおおよその内容はstyled-componentsでも実現可能
- スタイルごとにclass名を考えるコストが無くなる
- 最終的に、styled componentsが生成するclassセレクタは、ユニークな文字列でできている。
(例.sc-hogehoge)
※classNameをpropsでわたせば、任意のclass名を付与することは可能 - vendor prefixは自動付与されるので、-webkit-・・のようなautoprefixerは不要
- スタイルをあてることが可能なHTML要素であれば、styled componentsでコンポーネントとして作成可能
- CSSプリプロセッサとしてstylisが組み込まれているため、SassのSCSS記法のような書き方も可能(ネストやベンダープレフィックス)
- サポートするブラウザや対象とするバージョンの範囲を任意に指定することは不可。Reactのバージョンに応じたブラウザサポートに準拠する
最も基本的な書き方
大きく2パターンありますが、直感的にわかりやすいのは前者かと思います。
タグ付きテンプレートリテラルで記述する
- CSSのsyntax(構文)がそのまま使える
- styledを用い、タグ付きテンプレートリテラルを受け取ってstyled componentを返す関数を生成する
- styled.要素名`CSS` のように指定する
- ケバブケース(文字区切りにハイフンを使用)(font-size
- 末尾はセミコロン
import React from 'react'
import styled from 'styled-components'
const Button = styled.button`
height: 100%;
color: #fff;
font-size: 12px;
...
`
const BasicButton = (props) => {
return (
<Button>
{props.buttonName}
</Button>
)
}
export default BasicButton
オブジェクトリテラルで記述する
- styled.span({ })のように、オブジェクト形式で記述する
- キャメルケース(fontSize
- 末尾はカンマ
- CSSファイルからstyled-componentsにコピー&ペースト(あるいはその逆)できない ←重要
import React from 'react'
import styled from 'styled-components'
const Button = styled.button({
fontSize: '12px',
height: '100%',
color: '#fff'
})
const BasicButton = (props) => {
return (
<Button bg={props.bg} className={props.className} onClick={props.onClick}>
{props.buttonName}
</Button>
)
}
export default BasicButton
応用的な書き方
&でネストする
Scssのようなネスト記法(使いすぎるとコンポーネント指向の設計が無意味になりかねないので注意.)
const Container = styled.div`
width: 100vw;
height: 100vh;
div{
width: 40%;
h1{
color: #646464;
}
p{
color: #646464;
}
疑似クラス
hoverのような疑似クラス
※疑似要素と疑似クラスの違い
擬似要素は文章の中の1行・1文字単位の変更を加えることや、要素に文章や画像などを付け加えるために使用されますが、擬似クラスは、マウスホバーなどの文章構造の範囲外にある情報や、偶数のpタグにだけスタイルを指定するなどの、単体のセレクタでは表現できないものを選択をするために使用されます。
const Button = styled.button`
...
&:hover {
text-decoration: none;
opacity: 0.7;
box-shadow: 0 0 10px rgba(0 0 0 / 0);
}
...
`
疑似要素
after,beforeなどのような疑似要素
const ... `
::after{
content: '';
...
}
`
動的なスタイルの切り替え
propsによる動的なスタイルの切り替え
テンプレートリテラル
import React from 'react'
import styled from 'styled-components'
const bgList = {
BLUE: '#3283BB',
GREEN: '#46A6AE',
PURPLE: '#C129D1',
YELLOW: '#FDB515'
}
const Button = styled.button`
color: #fff;
font-size: 12px;
background: ${(props) => bgList[props.bg]}; // 動的な背景色の切り替え
`
const BasicButton = (props) => {
return (
<Button bg={props.bg}>
{props.buttonName}
</Button>
)
}
export default BasicButton
オブジェクトリテラル
const Button = styled.button({
fontSize: '12px',
height: '100%',
background: (props) => props.bg // 動的な背景色の切り替え
})
const BasicButton = ...
data属性
もちろん、htmlのdata属性にスタイルを当てることも可能
&[data-color='black']{
background: ${Color.black};
}
メディアクエリ
- デバイスごとのブレークポイントを定義
const Size = { mobileS: '320px', tablet: '768px', laptop: '1024px', desktop: '2560px' ... } export default Size
- 定義したデバイスごとのブレークポイントに基づいて、デバイスごとにメディアクエリを作成
import Size from './Size' const Device = { mobileS: `(min-width: ${Size.mobileS})`, mobileM: `(min-width: ${Size.mobileM})`, ... tablet: `(min-width: ${Size.tablet})`, laptop: `(min-width: ${Size.laptop})`, desktop: `(min-width: ${Size.desktop})`, } export default Device
- 対象のコンポーネントにデバイスごとのスタイルを定義する
例えば、子要素をラップするコンポーネントであれば、max-widthでデバイスに基づいて異なるものを指定するだけでOK// Wrapper.jsx import React from 'react' import styled from 'styled-components' import Device from '../../../shared/style/Responsive/Device' const Wrapper = styled.div` margin: auto; @media ${Device.laptop} { max-width: 800px; } @media ${Device.desktop} { max-width: 1400px; } ` const BasicWrapper = ({ children }) => { return <Wrapper>{children}</Wrapper> } export default BasicWrapper
@keyframes
アニメーションの@keyframes
import styled, { keyframes } from 'styled-components';
const logoRotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const LogoImage = styled.img`
animation: ${logoRotate} infinite 10s linear;
`;
...
<LogoImage src="ファイルパス" alt="" />
スタイルコンポーネントの拡張
- 作成したスタイルコンポーネントはextendで拡張できる ←重要
- StyledComponentクラスでない場合(styled.で作成したコンポーネント出ない場合)は、記述方法が異なるので注意(styled(コンポーネント)のように記述する)
const Button = styled.button` //ベースとなるボタン
padding: 1em;
font-size: 14px;
`
const ExtendedButtonSc = Button.extend` //ベースとなるボタンを拡張
background-color: #4c6ef5;
color: #fff;
`
const ExtendedButtonFc = styled(Button)` // StyledComponentクラスでない場合の拡張
background-color: #4c6ef5;
color: #fff;
`
スタイルコンポーネントの拡張のその先
withComponent
withComponentを使えば、styled-componentsでstyleがあてられたコンポーネントを、そのコンポーネントとは異なるタグで拡張できる
// button要素にあてたスタイルをaタグにリンクとしてスタイルを適用できる
const LinkItem = Button.withComponent('a')
ThemeProvider
- コンポーネントに渡すスタイルが複数種類ある場合、themeプロップスにより外から渡すことが可能装飾などに関する規定値を提供してくれる
- theme propsを通して<ThemeProvider />配下のstyled componentにテーマのスタイルをあてることが可能
- 色やレイアウトなどを共通化するための仕組み
まず、Themeを作成する
Theme.js
const Theme = {
colors: {
text: '#2c3e50',
background: '#fff'
},
fontSize: '14px'
}
export default Theme
ThemeProviderコンポーネントでラップし、themeプロップスを渡す
import { ThemeProvider } from 'styled-components'
import { Theme } from './Theme'
<ThemeProvider theme={Theme}>
<SomethingComponent1 />
<SomethingComponent2 />
</ThemeProvider>
ラップされたコンポーネント内では、propsで受け取ることが可能なので、これをもとにstyled componentを生成する
const SomethingContainer = styled.div`
color: solid 1px ${(props) => props.theme.colors.text};
background-color: solid 1px ${(props) => props.theme.colors.background};
font-size:props.theme.fontSize;
`
...
以上です。
まとめ
いかがでしたでしょうか。現代のモダンフロントエンド開発においては、コンポーネント設計がもはや必須の技術となっています。そこで今回は、クリーンなコンポーネント設計を行うために必要なCss in JsについてReactベースで紹介しています。具体的には、最も人気のあるCss in Js用のライブラリであるstyled-compornentの基本的な使い方や一歩踏み込んだ応用的な使い方も説明していますので是非参考にしてみてください。