[Angular8]サイトを簡単スタイリング!Angular Flex-Layoutの使い方をまとめてみた

どうも!大阪オフィスの西村祐二です。

フッター、ヘッターのレイアウトなど、画面のスタイリングをする際に、CSSのFlexboxなどで記載していく人は多いのではないでしょうか。

AngularではCSSのFlexboxをCSSファイルに書かず、HTMLタグ(ディレクティブ)を設定するだけで、簡単にFlexboxを設定できるライブラリAngular Flex-Layoutが公式から提供されています。

<div fxLayout="row" fxLayoutAlign="space-between">
</div>

今回はそのAngular Flex-Layoutの使い方をまとめてみます。

目次

環境

Angular CLI: 8.3.14
Node: 10.15.1
OS: darwin x64
Angular: 8.2.12
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.803.14
@angular-devkit/build-angular 0.803.14
@angular-devkit/build-optimizer 0.803.14
@angular-devkit/build-webpack 0.803.14
@angular-devkit/core 8.3.14
@angular-devkit/schematics 8.3.14
@angular/cdk 8.2.3
@angular/cli 8.3.14
@angular/flex-layout 8.0.0-beta.27
@ngtools/webpack 8.3.14
@schematics/angular 8.3.14
@schematics/update 0.803.14
rxjs 6.4.0
typescript 3.5.3
webpack 4.39.2

試していく環境を準備

はじめに、CLIを使ってプロジェクトを作成します。

$ npm install -g @angular/cli
$ ng new test-flex-layout --style scss --routing
$ cd test-flex-layout

Angular Flex-Layoutをインストールして、プロジェクトに設定します。公式サイトを参考に設定します。

$ npm i -s @angular/flex-layout @angular/cdk

app.module.tsにimportします。

import { FlexLayoutModule } from '@angular/flex-layout';
...

@NgModule({
    ...
    imports: [ FlexLayoutModule ],
    ...
});

Flexboxの設定があたっているかわかりやすいようにHTMLとCSSを設定していきます。

<div class="container">
 <div class="item item1">1</div>
 <div class="item item2">2</div>
 <div class="item item3">3</div>
 <div class="item item4">4</div>
 <div class="item item5">5</div>
</div>
$itemColors:(
  item1: red,
  item2: blue,
  item3: green,
  item4: pink,
  item5: slategray
);

@each $item, $color in $itemColors {
  .#{$item} {
    background: $color;
  }
}

.item {
    width: 80px;
    height: 80px;
  }

.container {
    width: 300px;
    height: 300px;
    color: #fff;
    background: #eee;
  }

設定ができたらローカル実行して画面を確認してみましょう。

$ ng serve -o

下記のような画面がでれば環境の設定は終了です。

早速試していく!

fxLayout 子要素の並ぶ向き

現状、子要素が縦に並んでいる状態です。子要素を横並びにします。

fxLayoutを指定するだけで、containerクラスがflex containerになります。

そうすることで、containerクラスの中の子要素が自動的にflex itemになってくれます。

fxLayout="row"

containerクラスのdivタグ内で子要素が横並びになります。

<div class="container" fxLayout="row">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

画面はこんなかんじに子要素が横並びになります。

ちなみにflex itemになるのは、flex containerの直近の子要素だけであって、それ以下に階層がある場合は、flex itemにならないので注意ください。

設定をいじってどう画面が変化するか確認していきましょう。

fxLayout="column"

containerクラスのdivタグ内で子要素が縦並びになります。

fxLayout="column-reverse"

containerクラスのdivタグ内で逆順で子要素が縦並びになります。

fxLayout="row-reverse"

containerクラスのdivタグ内で逆順で子要素が横並びになります。

CSSとの対応表

Value 対応するCSS
'' (default) flex-direction: row
row flex-direction: row
row-reverse flex-direction: row-reverse
column flex-direction: column
column-reverse flex-direction: column-reverse

要素の折返し

wrapを追加するとcontainerクラスのdivからはみ出した要素を折返してくれます。

fxLayout="row wrap"

左から右に向かってスタートし折り返されます。

fxLayout="row-reverse wrap"

右から左に向かってスタートして折り返されます。

fxLayout="column wrap"

上から下に向かってスタートし、折り返されます。

fxLayout="column-reverse wrap"

下から上に向かってスタートし折り返されます。

CSSとの対応表

Value 対応するCSS
wrap cloumn flex-flow: wrap cloumn
row-reverse wrap flex-flow: row-reverse wrap
column wrap flex-flow: column wrap
column-reverse wrap flex-flow: column-reverse wrap

inline-flex

inline-flexを設定することも可能です。

fxLayout="row inline"のように書くことでinline-flexとすることができます。

fxLayoutAlign 要素の整列順

設定したflex-directionの軸に対して子要素を左、右、中央揃えなど設定できます。

fxLayoutAlignの第1引数にメインの軸(rowであればx軸、columnであればy軸)の設定、第2引数に別軸をプラスして設定(rowであればy軸、columnであればx軸)できます。

デフォルトではfxLayoutAlign="start"が設定されています。

下記にいろんな設定を試した際の画面を載せていきます。

前提としてfxLayout="row wrap"を設定しておきます。

fxLayoutAlign="center"

要素が中央揃えになります。

<div class="container" fxLayout="row wrap" fxLayoutAlign="center">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

fxLayoutAlign="end"

要素が右揃えになります。

fxLayoutAlign="space-around"

要素を均等に配置し各要素の両側に半分の大きさの間隔を置いて配置されます。

fxLayoutAlign="space-between"

要素の余白が均等になるように配置されます。最初のアイテムは先頭に寄り、最後のアイテムは末尾に寄る形で配置されます。

fxLayoutAlign="space-evenly"

space-aroundと微妙な違いしかありませんが、 各要素を均等に配置し、各要素の周りに同じ大きさの間隔を置いて配置されます。

fxLayoutAlign="center center"

第2引数に値を指定するとCross Axis方向(rowの場合だとy軸方向)に対して配置します。

要素が中央に配置されます。

直近の子要素にのみ指定されるので、「1」を中央にしたいときは「1」を囲うタグに指定すると要素の中で中央に配置されます。

<div class="container" fxLayout="row wrap" fxLayoutAlign="center center">
  <div class="item item1" fxLayoutAlign="center center">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

fxLayoutAlign="center start"

fxLayoutAlign="center end"

fxLayoutAlign="center space-around"

fxLayoutAlign="center space-between"

CSSの高さの指定をはずして、stretchの設定を味わう

下記のようにCSSのheight: 80px;をコメントアウトします。

$itemColors:(
  item1: red,
  item2: blue,
  item3: green,
  item4: pink,
  item5: slategray
);

@each $item, $color in $itemColors {
  .#{$item} {
    background: $color;
  }
}

.item {
    width: 80px;
    // height: 80px;
  }

.container {
    width: 300px;
    height: 300px;
    color: #fff;
    background: #eee;
  }
  • fxLayoutAlign="start"
<div class="container" fxLayout="row wrap" fxLayoutAlign="start">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

デフォルトで、align-items: stretch; align-content: stretchが設定されているので余白がなくなり引き伸ばされます。

  • fxLayoutAlign="start start">

第2引数を設定するとstretchから設定が変更されるので下記のような画面になります。

CSSとの対応表

  • Main Axis
    Value 対応するCSS
    (default) justify-content: flex-start
    start or flex-start justify-content: flex-start
    center justify-content: center
    end or flex-end justify-content: flex-end
    space-around justify-content: space-around
    space-between justify-content: space-between
    space-evenly justify-content: space-evenly
  • Cross Axis (optional)
    Value 対応するCSS
    (default) align-items: stretch; align-content: stretch
    start or flex-start align-items: flex-start; align-content: flex-start
    center align-items: center; align-content: center
    end or flex-end align-items: flex-end; align-content: flex-end
    space-around align-items: space-around; align-content: space-around
    space-between align-items: space-between; align-content: space-between
    stretch max-width: 100% if flex-direction: column; else max-height: 100%
    baseline align-items: baseline; align-content: stretch

fxLayoutGap 要素間のマージン設定

要素と要素の間にマージンを入れたいときはfxLayoutGapを指定することで余白をいれることができます。

ただ、挙動としては下記のようになっていますので、使うときはココを頭にいれて設定するのが良いかと思います。

  • flex-direction="row"のときはmargin-rightが設定される

  • flex-direction="column"のときはmargin-bottomが設定される

  • 最後の要素にはマージンが設定されない

gap

Grid Mode

CSS Grid Layoutの際はgridと指定することでマージンを設定できます。

<div fxLayoutGap="16px grid">
  <div>Section 1</div>
  <div>Section 2</div>
  <div>Section 3</div>
</div>

fxFlex 子要素(Flexアイテム)に指定するプロパティ

fxFlex="<grow> <shrink> <basis>"という形で設定していきます。

  • grow:余白ができたとき、どの要素をどれだけ広げるかの設定
  • shrink:要素が溢れたとき、どの要素をどれだけ縮めるかの設定
  • basis:計算するときの基準となる幅、高さの値。autoのときは要素の大きさになる

CSS対応表

alias 対応するCSS
grow flex: 1 1 100%
initial flex: 0 1 auto
auto flex: <grow> <shrink> 100%
none flex: 0 0 auto
nogrow flex: 0 1 auto
noshrink flex: 1 0 auto

fxFlexOrder 要素の順番を入れ替える

要素の順番を入れ替えることができます。

デフォルトではorder: 0が設定されいます。

ここでは「1」にfxFlexOrder="1"とすることで、order: 1が設定されて後ろに移動されます。

<div class="container" fxLayout="row wrap">
  <div class="item item1" fxFlexOrder="1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

CSS対応表

Value 対応するCSS
(default) order: 0
<int> order: <int>

fxFlexOffset 要素間のマージンを設定

fxFlexOffsetfxLayoutGapと逆の余白を設定できる機能をもっています。だだ、これはFlexアイテムにのみ指定することができます。

  • flex-direction="row"のときはmargin-leftが設定される

  • flex-direction="column"のときはmargin-topが設定される

▼rowで「2」「5」にfxFlexOffsetを設定

<div class="container" fxLayout="row wrap">
  <div class="item item1">1</div>
  <div class="item item2" fxFlexOffset="10px">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5" fxFlexOffset="10px">5</div>
</div>

▼columnで「2」「5」にfxFlexOffsetを設定

<div class="container" fxLayout="column wrap">
  <div class="item item1">1</div>
  <div class="item item2" fxFlexOffset="10px">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5" fxFlexOffset="10px">5</div>
</div>

Value 対応するCSS
(default) margin-left: 0%
<int><suffix> margin-left: <int><suffix>

fxFlexAlign 要素個別にCross Axis設定にする

この要素だけ、rowからcolumnに切り替えたいなど、Cross Axisに切り替えることができます。

下記設定では「5」だけがCross Axisのflex-endの設定になっています。

<div class="container" fxLayout="row wrap">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5" fxFlexAlign="end">5</div>
</div>

Value 対応するCSS
start align-self: flex-start
center align-self: center
end align-self: flex-end
baseline align-self: baseline
stretch align-self: stretch

fxFlexFill, fxFill

cssファイルにwidthや、heightを設定していますが、fxFlexFill, fxFillを設定することで、cssの設定が上書きされ下記のプロパティが設定されます。

Key Value
margin 0
width 100%
height 100%
min-width 100%
min-height 100%

下記よりはcontainerクラスの設定が上書きされていることがわかります。

<div class="container" fxLayout="row wrap" fxFlexFill>
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

レスポンシブデザイン

下記表より、幅によってレイアウトを変更することができます。 []で囲うことで、条件式によって制御することもできます。

<api>.<breakpoint alias>="<value>"
[<api>.<breakpoint alias>]="<expression>"

下のサンプルのように「1」がウインドウサイズが600px-959pxの間非表示、それ以外は表示ということも可能です。

fxHideで要素を隠したり、fxShowで表示したりすることができます。


<div class="container" fxLayout="row wrap">
  <div class="item item1" fxShow fxHide.sm="true">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
  <div class="item item5">5</div>
</div>

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)'
lt-sm 'screen and (max-width: 599px)'
lt-md 'screen and (max-width: 959px)'
lt-lg 'screen and (max-width: 1279px)'
lt-xl 'screen and (max-width: 1919px)'
gt-xs 'screen and (min-width: 600px)'
gt-sm 'screen and (min-width: 960px)'
gt-md 'screen and (min-width: 1280px)'
gt-lg 'screen and (min-width: 1920px)'

応用

ある程度使い方がわかってきたら、次は実際によく使いそうな場面を想定してみましょう。

3カラムのレイアウト

はじめは下記のようにスタイリングしておきます。CSSでは色だけつけています。

<div class="container" fxLayout>
  <div class="left">left</div>
  <div class="center">center</div>
  <div class="right">right</div>
</div>
<footer>footer</footer>
$itemColors:(
  center: red,
  left: skyblue,
  right: green
);

@each $item, $color in $itemColors {
  .#{$item} {
    background: $color;
  }
}

header, footer {
    background: #eee;
  }

ここから、FlexLayoutを使って両端を100pxで固定しておいて、余った領域をcenterが専有する3カラムのレイアウトを作っていきます。

これはhtmlタグで完結できます。

両端固定なのでfxFlex="0 0 100px"を設定し、centerは余った領域を使うので、fxFlex="grow"とすることで3カラムを実現できます。

<header>header</header>
<div class="container" fxLayout.="column">
  <div class="left" fxFlex="0 0 100px">left</div>
  <div class="center" fxFlex="grow">center</div>
  <div class="right" fxFlex="0 0 100px">right</div>
</div>
<footer>footer</footer>

ヘッダーメニュー(ロゴだけ左端、メニューは右寄せ)

よくあるヘッダーメニューもhtmlタグで完結できます。

fxFlexOffsetmargin-leftを指定できるので、右側に寄せたい要素で設定しautoとしてやることで右側によせることができます。

<header>header</header>
<header>
  <div>Logo</div>
  <div fxFlexOffset="auto">Menu 1</div>
  <div>Menu 2</div>
</header>
<div class="container" fxLayout>
  <div class="left" fxFlex="0 0 100px">left</div>
  <div class="center" fxFlex="grow">center</div>
  <div class="right" fxFlex="0 0 100px">right</div>
</div>
<footer>footer</footer>

フッターを最下部に固定表示

コンテンツの高さが足りないときに、フッターの下にスペースができてしまうのを防ぎます。

全体をmainクラスのdivで囲いcolumnにします。containerクラスのdivが上下に伸縮してほしいので、fxFlex="grow"を設定します。

<div class="main" fxLayout="column">
  <header>
    <div>Logo</div>
    <div fxFlexOffset="auto">Menu 1</div>
    <div>Menu 2</div>
  </header>
  <div class="container" fxLayout="row" fxFlex="grow">
    <div class="left" fxFlex="0 0 100px">left</div>
    <div class="center" fxFlex="grow">center</div>
    <div class="right" fxFlex="0 0 100px">right</div>
  </div>
  <footer>footer</footer>
</div>

cssでmainクラスの高さを画面100%にしたいのでmin-height: 100vh;を追加します。

// 下記を追加

.main {
    min-height: 100vh;
}

bodyにデフォルトでついてるマージンとパディングを無効化しておきます。

body {
    margin: 0;
    padding: 0;
}

これで下記のようにコンテンツの高さが足りなくてもフッターが最下部に固定で表示されます。

画像とテキストを互い違いに表示

LPサイトなどでよくある形のテキストと画像が入れ替わっているレイアウトも簡単に作れます。

下記の12,18,25行目fxLayoutAlign="start start"は、デフォルト設定のstretchで画像が引き伸ばされるのを防ぎます。

fxLayout="row-reverse"で簡単に入れ替えることができます。

<div class="main" fxLayout="column">
  <header>
    <div>Logo</div>
    <div fxFlexOffset="auto">Menu 1</div>
    <div>Menu 2</div>
  </header>
  <div class="container" fxLayout="row" fxFlex="grow">
    <!-- left -->
    <div class="left" fxFlex="0 0 100px">left</div>
    <!-- center -->
    <div class="center" fxFlex="grow" fxLayout="column" fxLayoutGap="20px">
      <div fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko_01.png" width="100px" />
        <span>
          こんにちは、めそ子です。いつもは広報兼人事担当として、クラスメソッドをアピールするための活動をしていますが、今回は僭越ながら、少しだけ、私のことについてお話しさせてください。
        </span>
      </div>
      <div fxLayout="row-reverse" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko2nd.png" width="100px" />
        <span>
          こんにちは、めそ子です。2017年6月より2代目めそ子として、広報兼人事担当のお仕事をしています。先輩から引き継いだ「めそ子通信」は今後私が執筆してゆきますので、どうぞよろしくお願いします。
        </span>
      </div>
      <div fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko1709.png" width="100px" />
        <span>
          こんにちは、めそ子です。昼間の雲は高い位置に浮かび、夜はずいぶん涼しくなって、すっかり秋めいてきましたね。まだサンダルを履いていたいところですが、そろそろ衣替えもしなくちゃです。
        </span>
      </div>
    </div>
    <!-- right -->
    <div class="right" fxFlex="0 0 100px">right</div>
  </div>
  <footer>footer</footer>
</div>

下記のような画面になります。

コードはすこし見通しが悪くなっていますが、実際はコンポーネントを分割してメンテナンスしやすくしておきましょう。

レスポンシブデザインに対応させてスマホ用とWeb用で表示を切り替える

600px以下になるとスマホ用のレイアウトになるように設定します。

スマホで使いやすいように、下部に固定でメニューを表示し、ヘッダーはメニュー部分を非表示にして、ロゴを中央に配置します。

また、コンテンツもrowからcolumnになるように設定し、コンテンツ=>left=>right=>footerの順番になるようにします。

スマホ用のメニューはfxHide.gt-xs="true"とすることで、600px以上のときは非表示となるので、web用の大きさでは表示されません。

ngClassにはxsなどのウインドウの大きさでクラスをつけたりはずしたりすることができます。今回は、600px以下になったら、mo-headerというクラスをつけるようにしています。ngClass.xs="mo-header"

<div class="main" fxLayout="column">
  <header>
    <div ngClass.xs="mo-header" fxLayoutAlign.xs="center center">Logo</div>
    <div fxFlexOffset="auto" fxHide.xs="true">Menu 1</div>
    <div fxHide.xs="true">Menu 2</div>
  </header>
  <div class="mo-menu" fxLayout="row" fxLayoutAlign="space-around center" fxHide.gt-xs="true" fxFlexOrder="4">
    <div>Menu 1</div>
    <div>Menu 2</div>
  </div>
  <div class="container" fxLayout fxLayout.xs="column" fxFlex="grow">
    <!-- left -->
    <div class="left" fxFlex="0 0 100px" fxFlexOrder.xs="1">left</div>
    <!-- center -->
    <div class="center" fxFlex="grow" fxLayout="column" fxLayoutGap="20px">
      <div fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko_01.png" width="100px" />
        <span>
          こんにちは、めそ子です。いつもは広報兼人事担当として、クラスメソッドをアピールするための活動をしていますが、今回は僭越ながら、少しだけ、私のことについてお話しさせてください。
        </span>
      </div>
      <div fxLayout="row-reverse" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko2nd.png" width="100px" />
        <span>
          こんにちは、めそ子です。2017年6月より2代目めそ子として、広報兼人事担当のお仕事をしています。先輩から引き継いだ「めそ子通信」は今後私が執筆してゆきますので、どうぞよろしくお願いします。
        </span>
      </div>
      <div fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="10px">
        <img src="assets/mesoko1709.png" width="100px" />
        <span>
          こんにちは、めそ子です。昼間の雲は高い位置に浮かび、夜はずいぶん涼しくなって、すっかり秋めいてきましたね。まだサンダルを履いていたいところですが、そろそろ衣替えもしなくちゃです。
        </span>
      </div>
    </div>
    <!-- right -->
    <div class="right" fxFlex="0 0 100px" fxFlexOrder.xs="2">right</div>
  </div>
  <footer fxFlexOrder.xs="3">footer</footer>
</div>
$itemColors:(
  center: pink,
  left: skyblue,
  right: green
);

@each $item, $color in $itemColors {
  .#{$item} {
    background: $color;
  }
}

header, footer {
    background: #eee;
}


.main {
    min-height: 100vh;
}

.mo-menu {
    width: 100%;
    height: 50px;
    background:  #eee;
    position: sticky;
    bottom: 0;
  }
.mo-header {
    height: 50px;
    width: 100%;
}

CSS Grid Layout

CSS FlexboxだけじゃなくCSS Grid Layoutにも対応しています。

Grid Directive CSS Property(s) Extra Inputs
gdAlignColumns align-content and align-items gdInline for inline-grid
gdAlignRows justify-content and justify-items gdInline for inline-grid
gdArea grid-area none
gdAreas grid-areas gdInline for inline-grid
gdAuto grid-auto-flow gdInline for inline-grid
gdColumn grid-column none
gdColumns grid-template-columns gdInline for inline-grid
! at the end means grid-auto-columns
gdGap grid-gap gdInline for inline-grid
gdGridAlign justify-self and align-self none
gdRow grid-row none
gdRows grid-template-rows gdInline for inline-grid
! at the end means grid-auto-rows

下記のように親要素にディレクティブを指定すると利用することができるようです。

<div gdAuto>
  <div fxLayout="row">
    <div fxFlex></div>
  </div>
</div>

https://github.com/angular/flex-layout/blob/28bc2ae7476367f111edfce39a05b3f9041501f7/guides/Grid.md

さいごに

Angular Flex-Layoutの使い方をまとめてみました。

CSSファイルを行ったり来たりする必要がなく、簡単かつ、手軽にレイアウトの設定ができるので、かなり重宝しそうなライブラリです。

また、レイアウトに関する処理をHTML側によせることができるので、CSSのコード量を減らすことができるのも嬉しいポイントかなと思います。

誰かの参考になれば幸いです。