Angular Flex-Layout 入門

はじめに

Angular には公式から flex-layoutというFlexbox と Responsive API を使って Layout してくてるディレクティブが提供されています。
使いこなすことで劇的にCSSの量が減らせるため、今後を考え一度時間をかけて学びまとめます。

また、本家に素晴らしいdemoページ があるのでそちらも参照ください。

angular flex-layout

例のごとく stackblitz 上に Demo を作成しています。

  • 列と行が入れ子になった flex-layout の作り方
  • スマートデバイス、PC等の画面サイズが異なる場合のレイアウトの作り方
  • グリッドリストと flex-layout の組み合わせ方

stackblitz.com

flex-layout と material をinstall

今回は stackblitz でしか利用しないので stackblitz上でのライブライの import についてです。
とは言ってもとても簡単。 app.module.ts に import したいClassやらを書くだけで、自動的にpackageのインストールをするかを問われます。

stackblitz lib import
stackblitz lib import

また、依存ライブラリがあれば、それも聞いてくれます。
なんて簡単なんだ。

stackblitz dependency install
stackblitz dependency install

Nest した flex-layout

行と列が入れ子になったレイアウトを考えます。
作りたいのは下の図の通りです。
大きな枠として1行目はフルサイズ、2行目は2列、3行目もフルサイズとなっていて、2行目の各列の中で行と列を入れ子にしています。

Nested Flex-layout
Nested Flex-layout

まずは大きな枠を作ります。
1つの fxLayout="column" の中に 3つの fxLayout="row" があります。

<div fxLayout="column">
  <!-- Column-1 -->
  <div fxLayout="row" fxFlex="50px" style="background-color: #74edfd" fxLayoutAlign="center center"></div>
  <!-- Column-2 -->
  <div fxLayout="row" style="height: 75px">
    <!-- Column-2 Row-1-->
    <div fxFlex="40" fxFlexFill style="background-color: #fd7474"></div>
    <!-- Column-2 Row-2-->
    <div fxFlex="60" fxFlexFill style="background-color: #e8fd74"></div>
  </div>
  <!-- Column-3 -->
  <div fxLayout="row" style="height: 75px; background-color: #74fd86"></div>
</div>

この時点でこんな感じ。

flex-layout outline
flex-layout outline

2行目をさらに入れ子にしてみます。 <!-- Column-2 Row-1--> を見ると fxLayout="column" を指定しています。
中をcolumnに分割したい場合は外側のdivに対してfxLayout="column"を指定するだけで良さそうです。
同様にrowに分割したい <!-- Column-2 Row-2--> では fxLayout="row" を指定しています。

<!-- Column-2 -->
<div fxLayout="row" style="height: 75px">
  <!-- Column-2 Row-1-->
  <div fxLayout="column" fxFlex="40" fxFlexFill style="background-color: #fd7474" fxLayoutAlign="space-between strech">
    <div fxLayout="row" fxFlex="20px" style="background-color: #ffa1a1" fxLayoutAlign="center center">column2-1 row1</div>
    <div fxLayout="row" fxFlex="20px" style="background-color: #ffa1a1" fxLayoutAlign="center center">column2-2 row1</div>
    <div fxLayout="row" fxFlex="20px" style="background-color: #ffa1a1" fxLayoutAlign="center center">column2-3 row1</div>
  </div>
  <!-- Column-2 Row-2-->
  <div fxLayout="row" fxFlex="60" fxFlexFill style="background-color: #e8fd74" fxLayoutAlign="space-around strech">
    <div fxFlex="30" style="background-color: #f1fac0" fxLayoutAlign="center center">column2, row2-1</div>
    <div fxFlex="30" style="background-color: #f1fac0" fxLayoutAlign="center center">column2, row2-2</div>
    <div fxFlex="30" style="background-color: #f1fac0" fxLayoutAlign="center center">column2, row2-3</div>
  </div>
</div>

3行目はOffsetの例をあげています。
やんごとなき理由により親要素から指定したOffsetを当てたい場合があるかもしれません。 その場合は子要素にfxFlexOffset を指定することでOffsetが当たります。

<!-- Column-3 -->
<div fxLayout="row" style="height: 75px; background-color: #74fd86">
  <div fxFlex="20" fxFlexOffset="10" style="background-color: #b5ffbf" fxLayoutAlign="center center">column3 row1</div>
  <div fxFlex="80" fxFlexOffset="10" style="background-color: #b5ffbf" fxLayoutAlign="center center">column3 row2</div>
</div>

以上で入れ子になったflex layoutを作ることができました。
ここまでは基礎ですね。

flex-layout break point

近年はPCだけでなくスマホ等のスマートデバイスへの考慮が必須です。
従来mediaクエリを書くことで対応してきましたが、flex-layoutでは fxFlexを活用することである程度対応することができそうです。

BreakPoint Flex-layout
BreakPoint Flex-layout

flex-layout ではこのページに break point がまとまっています。
独自のbreak pointを設定することもできますが、基本的にはこの break point と不等号(gt / lt)を使ってレイアウトを指定します。

fxLayout に対してbreak pointを指定することで row と column を変更できます。
fxFlexOrder に対してbreak pointを指定することで要素の順番を変更できます。
fxFlex に対してbreak pointを指定することで親要素に対する大きさを変更することができます。
fxHide に対してbreak pointを指定することで指定した要素を非表示にすることができます。

<mat-card-content>
  <div fxLayout="column">
    <!-- Header -->
    <div fxLayout="row" fxFlex="50px" style="background-color: #74edfd" fxLayoutAlign="center center">header</div>
    <!-- Main -->
    <div fxLayout="row wrap" style="height: 150px">
      <div fxFlexOrder="1" fxLayout="row" fxLayout.xs="column" fxFlex.xs="100" fxFlex.gt-xs="30" style="background-color: #fd7474" fxLayoutAlign="center center">side nav</div>
      <div fxFlexOrder="5" fxLayout="row" fxFlex.xs="100" fxFlex.gt-xs="70" fxFlex.gt-sm="50" style="background-color: #e8fd74" fxLayoutAlign="center center">article</div>
      <div fxFlexOrder="10" fxLayout="row" fxHide.xs fxHide.sm fxFlex.gt-sm="20" style="background-color: #74fd86" fxLayoutAlign="center center">toc</div>
    </div>
    <!-- Footer -->
    <div fxLayout="row" fxFlex="50px" style="background-color: #74edfd" fxLayoutAlign="center center">footer</div>
  </div>
</mat-card-content>

これだけでも相当のユースケースをカバーできそうですがdemoページにあるように ngClass または ngStyle に対してもbreak pointが仕込めるようです。 もうメディアクエリだこれ

<div
  fxFlex
  class="fxClass-all"
  ngClass.xs="fxClass-xs"
  [ngClass.sm]="{'fxClass-sm': hasStyle}"
  [ngClass.md]="{'fxClass-md': hasStyle, 'fxClass-md2': hasStyle}"
  [ngClass.lg]="['fxClass-lg', 'fxClass-lg2']">
</div>

Grid list と flex-layout

最後は Grid list との組み合わせです。
画像やCardをngForでダーッと並べる時に使いますね。

Grid List Flex Layout
Grid List Flex Layout

fxLayout="row wrap" を指定した中に fxFlex="25" fxFlex.sm="33.3" fxFlex.xs="50" *ngFor="let tile of tiles" のように画面サイズに応じた割合を指定することでgrid-tileの個数を指定できます。
xsの時は2つ、smの時は3つ、その他は4つ、という指定です。

<div fxLayout="row wrap">
  <div fxFlex="25" fxFlex.sm="33.3" fxFlex.xs="50" *ngFor="let tile of tiles">
    <mat-grid-list cols="1" rowHeight="1:1">
      <mat-grid-tile [style.background]="tile.color">
        {{ tile.text }}
      </mat-grid-tile>
    </mat-grid-list>
  </div>
</div>

まとめ

Angular Flex-Layout の3つのユースケースをまとめました。
活用することでCSSの量をかなり減らすことができそうです。
また、Angularチームが公式に提供してくれているため、Material Componentsとの組み合わせで苦労することもなさそうです。