はじめてのReact #28 「CSSフレームワークを導入する」Material-UI グリッド編

前回はMaterial-UIのインストールと基本的な利用方法について取り上げました。今回は画面のレイアウトを行う際に利用するグリッドシステムです。

この手のCSSフレームワークの醍醐味の一つはグリッドが用意されていることですね。最近はflexboxが使えるようになってずいぶん楽になりましたが、細かい制御をやってくれるので中々重宝するんですよね。

グリッドシステム

containerとitem

グリッドを使用する際にはその名の通りコンポーネントをimportします。Gridはpropsによって大きく2つの役割を与えることができます。

  • itemを指定すると実際のコンテンツを表示。表で言う「列」の役割。
  • containerはitemをまとめる。表でいう「行」の役割。

具体的には以下のようになります。

<Grid container>
  <Grid item xs={4}>1列目</Grid>
  <Grid item xs={4}>2列目</Grid>
  <Grid item xs={4}>3列目</Grid>
</Grid>

xsで列の幅を定義しています。 一つのcontainerの中には最大で12個のitemを含めることができますが、12個に満たない場合はこのxsの合計が12になるよう調整してあげます。上のコードだと均等に4になっていますが、合計が12になっていれば良いので、1,1,10など不揃いでもOKです。

ちなみに次のようにitemの幅が12を超えてしまった場合は、単純に次の「行」に送られます。

<Grid container>
  <Grid item xs={4}>1列目</Grid>
  <Grid item xs={4}>2列目</Grid>
  <Grid item xs={4}>3列目</Grid>
  <Grid item xs={4}></Grid>
</Grid>

幅を自動的に割り当てる

すべて等幅で良い場合は、以下のように属性になんの値も与えなければ、自動的に同じ幅になってくれます。ここでは3つのitemを入れているので、xs={4}と同じ意味になります。

<Grid container>
  <Grid item xs>1列目</Grid>
  <Grid item xs>2列目</Grid>
  <Grid item xs>3列目</Grid>
</Grid>

一部の列だけ幅を固定したい場合には以下のようにそのitemだけ指定することもできます。左右のitemはそれぞれxs={3}になります。

<Grid container>
  <Grid item xs>1列目</Grid>
  <Grid item xs={6}>2列目</Grid>
  <Grid item xs>3列目</Grid>
</Grid>

ブレークポイント

このxsってそもそもなんやねんというと、ディスプレイの解像度やウィンドウサイズなどに合わせ横幅を定義する物になります。巷で話題の「モバイルファースト」ってやつですね。

MUIでは具体的には次のように定義されています。

属性 本名 サイズ
xs extra-small 0px 〜
sm small 600px 〜
md medium 960px 〜
lg large 1280px 〜
xl extra-large 1920px 〜

例えば以下のようなグリッドを書いたとします。この場合960px以上のディスプレイでは4,4,4の比率で表示されますが、それに満たないディスプレイでは1,1,10の比率で表示されます。

<Grid container>
  <Grid item xs={1}   md={4}></Grid>
  <Grid item xs={1}   md={4}></Grid>
  <Grid item xs={10}  md={4}></Grid>
</Grid>

非表示にする

ブレークポイントによって解像度に応じた列の幅を設定することはできるようになりましたが、特定の解像度で表示しない(逆に表示する)といった設定を行うにはコンポーネントを利用します。

例えば以下のように定義した場合、

<Grid container>
  <Hidden xsDown>
    <Grid item sm={6}></Grid>
  </Hidden>
  <Grid item xs={12} sm={6}></Grid>
</Grid>

次のような挙動になります。

  • sm以上では6,6の比率で表示
  • xsに下がったら0,12で表示 (1列目が非表示)

最初は若干分かりづらいのですが、Hiddenコンポーネントの【サイズ名】Downという属性を使用した場合、そのサイズに落ちた瞬間、非表示に切り替わります。また逆に【サイズ名】Upという属性を使用するとそのサイズに上がった瞬間に非表示になります。

Hiddenは隠すといった意味を持つ英単語ですので、非表示を基準に考えます。

以上のことから全部で次のような属性が用意されています。

属性 効能
xsDown sm,md,lg,xl → xs に下がったら非表示
xsUp xs → sm,md,lg,xl に上がったら非表示
smDown md,lg,xl → sm に下がったら非表示
smUp sm → md,lg,xlに上がったら非表示
mdDown lg,xl → md に下がったら非表示
mdUp md → lg,xlに上がったら非表示
lgDown xl → lg に下がったら非表示
lgUp lg → xlに上がったら非表示
xlDown ? → xl に下がったら非表示
xlUp xl → ? に上がったら非表示

xlDownとxlUpは将来のための物でしょうかね? なんというかxs={false}とかxs={0}あたりで隠せるとシンプルなんですけどね。タグでゴチャゴチャして見通しが悪くなってる気がしないでもない。

その他の便利属性

item間の余白

containerにspacing属性を指定します。

<Grid container spacing={8}>
  <Grid item xs={4} />
  <Grid item xs={4} />
  <Grid item xs={4} />
</Grid>

「0, 8, 16, 24, 32, 40」の中のいずれかの整数を利用する必要があります。10とか指定すると効きませんのでご注意を。

itemを均等に並べる

justify属性にcenterを指定します。

<Grid container spacing={24} justify={"center"}>
  <Grid item xs={4} />
  <Grid item xs={4} />
  <Grid item xs={4} />
</Grid>

折返し

wrap属性にnowrapを指定すると折返しを行わずギュッと詰め込まれます。以下のように定義すると本来は3番めのitemが下の行に追い出されますが、無理矢理1行目にとどまります。

<Grid container wrap={"nowrap"}>
  <Grid item xs={6} />
  <Grid item xs={6} />
  <Grid item xs={6} />
</Grid>

またwrap-reverseを指定した場合、通常は「1,2(改行)3」と表示されるところが、「3(改行)1,2」と折返しを逆にすることができます。

<Grid container wrap={"wrap-reverse"}>
  <Grid item xs={6}>1</Grid>
  <Grid item xs={6}>2</Grid>
  <Grid item xs={6}>3</Grid>
</Grid>

利用例

は真っ白なカードを表示するコンポーネントです。

import React, { Component } from 'react';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';

class App extends Component {
  render() {
    return (
      <div style={styles.root}>
      <Grid container justify="center" spacing={8}>
        <Grid item xs={4}>
          <Paper style={styles.paper}>xs=12</Paper>
        </Grid>
        <Grid item xs={4}>
          <Paper style={styles.paper}>xs=12</Paper>
        </Grid>
        <Grid item xs={4}>
          <Paper style={styles.paper}>xs=12</Paper>
        </Grid>
      </Grid>
      </div>
    );
  }
}

const styles = {
  root: {
    width: "640px",
    height: "120px",
    paddingTop: "15px",
    paddingLeft: "10px",
    backgroundColor: "lightgray",
  },
  paper: {
    width:"200px",
    height:"100px",
    textAlign:"center",
  }
};
export default App;

続き

blog.katsubemakito.net

参考ページ