SSRと絡めようとすると難しくて、いろいろ試行錯誤しました。いまはこういう方向でやろうとしていて、そこそこメンテナンス可能に書けそうだなという手応えがあります。
三行で
- CSSのメディアクエリのみを使い、Railsでテンプレートエンジンを使うにせよReactでSSRするにせよReactでCSRするにせよ同じ方法を使う
- PCのみ表示させる場合は
.showPcOnlyクラスを、スマホでのみ表示させる場合は.showSmartphoneOnlyクラスをつけたdivで囲む - たまに
.showPcOnlyなどとは別にwidth: 100%などを指定しないといけないが、それは別途クラスを定義して与える
ヘルパーSCSSクラス
こんな感じのヘルパーを用意しておく。
$smartphoneBreakpoint: 767px;
@mixin smartphone {
@media screen and (max-width: $smartphoneBreakpoint) {
@content;
}
}
@mixin pc {
@media screen and (min-width: $smartphoneBreakpoint + 1) {
@content;
}
}
@include smartphone {
.showPcOnly {
display: none;
}
}
@include pc {
.showSmartphoneOnly {
display: none;
}
}
ヘルパーJSX components
こんな感じのJSX componentsを定義しておく。
import React from 'react';
import classNames from 'classnames';
export class SmartphoneOnly extends React.Component {
static propTypes() {
return {
children: React.PropTypes.any.isRequired,
className: React.PropTypes.string,
};
}
render() {
return (<div className={classNames(this.props.className, "showSmartphoneOnly")}>
{this.props.children}
</div>);
}
}
export class PcOnly extends React.Component {
static propTypes() {
return {
children: React.PropTypes.any.isRequired,
className: React.PropTypes.string,
};
}
render() {
return (<div className={classNames(this.props.className, "showPcOnly")}>
{this.props.children}
</div>);
}
}
試したこと
.showPcOnlyクラスを@extendする→❌- そのクラスに
display: flexをつけたい場合に衝突してうまくいかない
- そのクラスに
react-responsiveライブラリをつかう→❌- サーバーサイドでJavaScriptのmedia query APIを使えないのでダメ
- JS media queryのための情報をクライアントから送る(e.g.
width: 1024)こともできるが所詮シミュレーションでしかないし、キャッシュとの相性も悪い
- CSSでクラスごとに地道にがんばる→❌
- DOM構造をみて(=hamlやJSXをみて)どうスイッチされるかを把握できないのでつらい
- DOM構造に直接
.showPcOnlyや<ShowPcOnly>で書くのがわかりやすくていい