はじめに
こんにちは、ねりこ @nerikosans と申します。もう2019年も終わりが近づいてきましたね。
皆様におかれましてはますます import * as React from 'react';
の由、何よりと存じます。日頃は特別の export default
にあずかり心より御礼申し上げます。
さて、Styled Components は、DOMのスタイルを、その定義ファイル( .jsx
, .tsx
)内で完結させてしまおうという思想のフレームワークです。コードの見通しの良さ、動的レンダリングのしやすさなどから昨今は人気になってい(ると感じてい)ます。
そして、DOMスタイリングにはレスポンシブ対応がつきものですが、やっぱり爆速で書きたいですよね。
ということで、 styled-componentsでレスポンシブするときのメモ書きです。
目標
最低限の記法で書きたいので、これ↓だけ書けば対応が済むように構築します。
const Box = styled.div`
background: black;
/* PC */
${media.pc`
background: red;
`}
/* Smartphones */
${media.sp`
background: red;
`}
`;
Step1. styled-media-query
morajabi/styled-media-query
よく使うサイズをサクッと使いたい場合はこれだけで大丈夫。
small
, medium
, large
, huge
の4つの width breakpoint を備えていて、media queryを自動で生成してくれます。
公式サンプルが以下の通り。
const Box = styled.div`
background: black;
${media.lessThan("medium")`
/* screen width is less than 768px (medium) */
background: red;
`}
${media.between("medium", "large")`
/* screen width is between 768px (medium) and 1170px (large) */
background: green;
`}
${media.greaterThan("large")`
/* screen width is greater than 1170px (large) */
background: blue;
`}
`;
便利ですね。でも .lessThan("medium")
って毎回書きたくないので、これをwrapします。
styled-media-query
の export されていない type を使用しているところがあります。
import media from 'styled-media-query';
import {
ThemedStyledProps,
InterpolationValue,
FlattenInterpolation,
} from 'styled-components';
/**
* https://github.com/morajabi/styled-media-query/blob/master/src/index.d.ts
*/
type InterpolationFunction<Props, Theme> = (
props: ThemedStyledProps<Props, Theme>
) => InterpolationValue | FlattenInterpolation<ThemedStyledProps<Props, Theme>>;
type GeneratorFunction<Props, Theme> = (
strings: TemplateStringsArray,
...interpolations: (
| InterpolationValue
| InterpolationFunction<Props, Theme>
| FlattenInterpolation<ThemedStyledProps<Props, Theme>>
)[]
) => any;
const rules: { [v: string]: GeneratorFunction<unknown, any> } = {
pc: (...args) => media.greaterThan('medium')(...args),
sp: (...args) => media.lessThan('medium')(...args),
};
export default rules;
よし、これでこのファイルを media
として default importすれば、 ${media.pc` .... `}
だけでpc専用スタイルを書けるようになりました!
Step2. カスタマイズ
さて、これだけでも便利ですが、styled-media-query では今のところ pre-defined な4つのサイズ以外は指定できないようなので、これに加えて自由なmedia queryを書きたい場合 (例えば、heightで区切りたい場合) は以下のようにすればOKです。
import media from 'styled-media-query';
import {
ThemedStyledProps,
InterpolationValue,
FlattenInterpolation,
css,
} from 'styled-components';
/* (... 中略) */
const rules: { [v: string]: GeneratorFunction<unknown, any> } = {
pc: (...args) => media.greaterThan('medium')(...args),
sp: (...args) => media.lessThan('medium')(...args),
short: (...args) => css`
@media screen and (max-height: 480px) {
${css(...args)}
}
`,
};
export default rules;
これで新たに media.short`...`
が使えるようになりました!
おわりに / 展望
以上で、晴れて簡潔にレスポンシブスタイルが書けるようになりました。最高ですね。
しかし、そもそもComponentを render
するかどうかから出し分けたい場合などは、この方法では足りません。
例えば
const media = useMedia();
const isPC = media.pc;
みたいに書けたら便利ですよね。これを実現する方法はまた今度書きたいと思います。
追記: 書きました! [React] 年末だしwindow.matchMedia()で爆速レスポンシブ対応していこうな
お読みいただきありがとうございました!