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>
で書くのがわかりやすくていい