UI
angular
MaterialDesign
angularMaterial

Angular Materialでマテリアルでレスポンシブなリストを実装する

更新履歴
2018.04.05 - 5.0.0-beta.13 (2018-02-22) におけるBREAKING CHANGESに対応


Angular Material (material2)は2017/10/06時点で未だbetaバージョンですが、レスポンシブルでマテリアルデザインなSPAを作る際にはドキュメントも充実しており手軽に美しく実現できて素敵です。

今回はAngular Materialの グリッドリスト とangularの フレックスレイアウト を使ってレスポンシブなデザインを構築しました。

環境

@angular: 4.4.3
@angular/material: 2.0.0-beta.11
@angular/flex-layout: 2.0.0-beta.9

素のグリッドデザイン

Angular Materialで提供されているGrid listをそのまま使うと、幅にあわせて表示エリアが拡大・縮小します。

angular-not-flexLayout_500p.gif

このままの状態でもユーザの環境に合わせたレンダリングができるのですが、今回自分が実現したかったのは「表示領域にあわせてコンテンツ表示数を増やしたい」という要件でした。

これを実現するために、angularのflex-layoutを組み合わせて使います。

FlexLayoutと組み合わせて使う

使い方はここにあります。

flex-layoutのインストール

angularプロジェクトで使用できるようにするためには $ npm -i @angular/flex-layout --save コマンドでインストールし、 app.module.ts でインポートします。

  • app.module.ts
import { FlexLayoutModule } from '@angular/flex-layout';
..
  imports: [
    FlexLayoutModule,

ブレークポイント

今回やりたいことをflex-layoutで実現するためには Breakpoints を知っておく必要があります。

layout-adaptive-breakpoints-01.png

ディスプレイサイズに応じて名前付け(例:600px - 959px の場合は sm)がされており、その名前ごとに表示方法を指定することが出来ます。

  • MediaQueries and Aliases
breakpoint mediaQuery
xs 'screen and (max-width: 599px)'
sm 'screen and (min-width: 600px) and (max-width: 959px)'
md 'screen and (min-width: 960px) and (max-width: 1279px)'
lg 'screen and (min-width: 1280px) and (max-width: 1919px)'
xl 'screen and (min-width: 1920px) and (max-width: 5000px)'

フレックスレイアウトを使う

今回は複数要素を表示幅に応じて改行して表示させます。このような用途の場合、 fxLayoutWrapを使用します。

fxLayoutWrap
5.0.0-beta13 (2018-02-22) の変更でfxLayoutWrapは廃止されました。2018年4月時点での新しいコード例はこのページの下記に追加しています。

Defines if child items appear on a single line or on multiple lines within a flexbox container. <div fxLayoutWrap> </div>

子アイテムがフレックスボックスコンテナ内の1行または複数行に表示されるかどうかを定義します。

簡単な使用例:

<div fxLayoutWrap>
  <div fxFlex="25" fxFlex.sm="33.3" fxFlex.xs="50">
    <p>1st</p>
    <p>2nd</p>
    <p>3rd</p>
  </div>
</div>

fxFlex="xx" は、100に対する割合を設定します。値は 整数 or % or px 単位 で指定します。この例ではデフォルト=25(全体に対して1/4の幅)、幅が959px以下なら33.3(1/3の幅)、幅が599px以下なら50(1/2の幅)と指定しています。

Grid Listを組み合わせる

このままでは幅が変わってもコンテンツのサイズが変わらないため、Grid Listを適用します。

※今回はGrid Listのスタイルを流用したいがために1コンテンツ1つしかないリストとして実装しています。本来の使い方とかけ離れているため推奨はしません。

この場合は <mat-grid-list cols="1" rowHeight="1:1"> と指定します。(列:1, 縦横比1:1)

<div fxLayoutWrap>
  <div fxFlex="25" fxFlex.sm="33.3" fxFlex.xs="50" *ngFor="let card of cards">
    <mat-grid-list cols="1" rowHeight="1:1">
      <mat-grid-tile>
        <mat-card>
          <img mat-card-image src="foo.jpg" alt="{{card.name}}'s latest card img.'">
        </mat-card>
        <mat-grid-tile-footer style="margin-bottom:48px;">
          <div class="name">{{card.name}}</div>
        </mat-grid-tile-footer>
        <mat-grid-tile-footer>
          <div class="kana">{{card.kana}}</div>
        </mat-grid-tile-footer>
      </mat-grid-tile>
    </mat-grid-list>
  </div>
</div>

※上の例では更にCardコンポーネントも併用しています。あと、足が2本生えていたりします…ごめんなさい。

完成したもの

angular-flexLayout_500p.gif

まとめ

flex-layoutとAngular Materialの組み合わせでレスポンシブなコンテンツページを作ることができました。angularではまだまだ便利なAPIが提供されているので練習でどんどん使ってみて覚えていきたいと思います。

参考リンク

追記 2018.04.05

5.0.0-beta.13 (2018-02-22) で fxLayoutWrap は廃止されたため、次のように修正する必要があります。

before

<div  fxLayout="row" fxLayoutWrap="wrap"> ... </div>

after

<div  fxLayout="row wrap"> ... </div>

5.0.0-beta.13 (2018-02-22) CHANGELOG