Master PG

プログラムし続ける...

【Polymer 1.0】フレキシブルレイアウト


目次


概要

iron-flex-layoutコンポーネントはCSS flexible boxをシンプルに利用するための方法を提供します。このコンポーネントではFlexboxを利用するために2つの方法を提供します:

  • CSSクラス: Flexboxを使用するためのCSSクラスを提供します。このCSSクラスはマークアップで直接指定します。
  • カスタムCSS Mixin: Flexboxを使用するためのカスタムCSS Mixinを提供します。CSSルールの定義の中で、@apply()関数の引数にこのカスタムCSS Mixinを指定して利用します。

この2つの方法のどちらを利用するかは好みの問題です:

    classe: ⇒ ソースコード
    mixin: ⇒ ソースコード


iron-flex-layout コンポーネントを使用する

CSSクラスを使用する場合は、次のファイルをインポートします:

<link rel="import" href="bower_components/iron-flex-layout/classes/iron-flex-layout.html">

次はCSSクラスのシンプルな使用例です:

<div class="layout horizontal wrap">

このようにclassには複数のCSSクラスを指定できます。指定するCSSクラスの順番は意識しないため、wrap horizontal layoutも同じ意味になります。


カスタムCSS Mixin を使用する場合は、次のファイルをインポートします:

<link rel="import" href="bower_components/iron-flex-layout/iron-flex-layout.html">

次はカスタムCSS Mixin のシンプルな使用例です (カスタムCSS Mixin の詳細はここを参照ください):

<dom-module id="mixin-simple-demo">
  <style>
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-wrap);
    }
  </style>
  <template>
    <div class="container">
  ...


HorizontalレイアウトとVerticalレイアウト

次は最もシンプルな横方向と縦方向のレイアウトのサンプルです。

classes:

<div class="layout horizontal">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</div>

<div class="layout vertical">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</div>

mixin:

<dom-module id="horizontal-and-vertical-demo">
  <style>
    ...
    .container-horizontal {
      @apply(--layout-horizontal);
    }
    .container-vertical {
      @apply(--layout-vertical);
    }
  </style>
  <template>
    <div class="container-horizontal">
      <div>One</div>
      <div>Two</div>
      <div>Three</div>
    </div>

    <div class="container-vertical">
      <div>One</div>
      <div>Two</div>
      <div>Three</div>
    </div>
  ...

f:id:masterpg:20160923112025p:plain


デフォルトで適用される幅と高さ

ここではまずHorizontalまたはVerticalレイアウトで、デフォルトで適用される幅と高さについて見ていきましょう。次のサンプルでは、<body>に3つの<div>がコンテナとして配置されています。

  • 1つ目のdivは子エレメントを1つ持ちます。
  • 2つ目の<div>は子エレメントを持ちません。
  • 3つ目の<div>は子エレメントを1つ持ち、また高さが指定されています。

⇒ ソースコード

<!doctype html>
<html>
<head>
  ...
  <style>
    html, body {
      height: 100%;
    }
    body {
      margin: 0;
    }
    .container {
      margin: 10px;
      padding: 5px;
      background-color: lightgray;
    }
    .item {
      background-color: white;
      margin: 5px;
      padding: 10px;
    }
  </style>
</head>
<body class="fullbleed layout vertical">
  <!-- このコンテナは子エレメントを持つ -->
  <div class="layout vertical container">
    <div class="item">One</div>
  </div>
  <!-- このコンテナは子エレメントを持たない -->
  <div class="layout vertical container"></div>
  <!-- このコンテナは子エレメント持ち、高さが指定されている -->
  <div class="layout vertical container" style="height: 150px;">
    <div class="item">One</div>
  </div>
</body>
</html>

まず<div>の幅ですが、3つとも親エレメント(ここでは<body>)の幅の中で可能な範囲でストレッチされています。またブラウザをリサイズしても<div>の幅は適切に追従します。

次に<div>の高さですが、1つ目の<div>は子エレメントの高さから計算して親である<div>の高さが決定されています。2つ目の<div>は子エレメントを持たないため、親である<div>がペタンコになっています。3つ目の<div>は指定された高さが適用されています。

f:id:masterpg:20160923112124p:plain

レイアウトを行う際は次のことを頭に置いておくと良いでしょう:

  • 幅が指定されないコンテナでは、親コンテナの中で可能な範囲で幅がストレッチされる。
  • 高さが指定されないコンテナでは、子エレメントの高さを基準にしてコンテナの高さが決定される。
  • 高さが指定されたコンテナでは、子エレメントの高さよりコンテナに指定された高さが優先される。


Main-axis と Cross-axis

コンテナは2つの軸を持っています。Main-axis (主軸) は、指定したコンテナに適用したlayout horizontallayout verticalがこれにあたります。これに対してCross-axis (交差軸) は、Main-axisに対して垂直な軸となり、Main-axisがHorizontalの場合、Cross-axisはVerticalになります。

デフォルトでは、子エレメントのサイズはCross-axis方向へストレッチされます:

<div class="layout horizontal" style="height: 150px;">
  <div>Stretch Fill</div>
  <div>Stretch Fill</div>
</div>

<div class="layout vertical" style="height: 150px;">
  <div>Stretch Fill</div>
  <div>Stretch Fill</div>
</div>

レイアウトを行う際は次のことを頭に置いておくと良いでしょう:

  • Main-axisがHorizontalの場合、子エレメントは縦方向へストレッチします:

f:id:masterpg:20160923112303p:plain

  • Main-axisがVerticalの場合、子エレメントは横方向へストレッチします:

f:id:masterpg:20160923112319p:plain


子エレメントのサイズをフレキシブルに制御する

コンテナの子エレメントは、flexを使用することで自身のサイズを制御することができます。

classes:

<div class="layout horizontal">
  <div>One</div>
  <div class="flex">Two (flex)</div>
  <div>Three</div>
</div>

mixin:

<dom-module id="horizontal-flex-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
    }
    .flexchild {
      @apply(--layout-flex);
    }
  </style>
  <template>
    <div class="container">
      <div>One</div>
      <div class="flexchild">Two (flex)</div>
      <div>Three</div>
    </div>
    ...

f:id:masterpg:20160923112411p:plain



Horizontalと同様にVerticalでもエレメントのサイズが柔軟に変化します。ただしVerticalレイアウトではコンテナのheightに値を指定する必要あります。指定しない場合はレイアウトが崩れる場合があります:

classes:

<div class="layout vertical" style="height: 250px;">
  <div>Alpha</div>
  <div class="flex">Beta (flex)</div>
  <div>Gamma</div>
</div>

mixin:

<dom-module id="vertical-flex-demo">
  <style>
    ...
    .container {
      @apply(--layout-vertical);
    }
    .flexchild {
      @apply(--layout-flex);
    }
  </style>
  <template>
    <div class="container" style="height: 250px;">
      <div>One</div>
      <div class="flexchild">Two (flex)</div>
      <div>Three</div>
    </div>
  ...

f:id:masterpg:20160923112531p:plain

次はheightに値をしなかった場合にレイアウトが崩れた例です:

f:id:masterpg:20160923112540p:plain

Note: ChromeでカスタムCSS Mixinを使用した場合にこのようなレイアウト崩れが起きました。CSSクラスを使用した場合はまた違う結果になります。またブラウザやそのバージョンによっても挙動が異なるようです。



子エレメントのサイズは割合を指定することができます。割合はflex-2のように、数字の部分を2〜12の範囲で指定します (flexは1) :

classes:

<div class="layout horizontal">
  <div class="flex-2">Alpha</div>
  <div class="flex">Beta</div>
  <div class="flex-3">Gamma</div>
</div>

mixin:

<dom-module id="horizontal-flex-ratio-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
    }
    .flexchild {
      @apply(--layout-flex);
    }
    .flex2child {
      @apply(--layout-flex-2);
    }
    .flex3child {
      @apply(--layout-flex-3);
    }
  </style>
  <template>
    <div class="container">
      <div class="flex3child">One</div>
      <div class="flexchild">Two</div>
      <div class="flex2child">Three</div>
    </div>
  ...

f:id:masterpg:20160923112629p:plain



ここではコンテナに子エレメントをフィットさせています。フィットさせるためには以下の性質を利用します:

  • 幅のフィットは、flexを指定することによって行う。
  • 高さのフィットは、Main-axisがHorizontalの場合に子エレメントが縦方向へストレッチする性質を利用する (詳細は「Main-axis と Cross-axis」を参照ください) 。

classes:

<div class="layout horizontal" style="height: 150px;">
  <div class="flex">Fit</div>
</div>

mixin:

<dom-module id="horizontal-fit-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
    }
    .flexchild {
      @apply(--layout-flex);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div class="flexchild">Fit</div>
    </div>
  ...

f:id:masterpg:20160923112714p:plain


Cross-axisにエレメントを配置

ここではCross-axisにエレメントを配置する方法についてみていきます。


次のサンプルでは、Cross-axis (Vertical) のstart位置にエレメントを配置しています:

classes:

<div class="layout horizontal start" style="height: 150px;">
  <div>start</div>
  <div>start</div>
</div>

mixin:

<dom-module id="horizontal-start-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-start);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div>start</div>
      <div>start</div>
    </div>
  ...

f:id:masterpg:20160923112759p:plain



次のサンプルでは、Cross-axis (Vertical) のcenter位置にエレメントを配置しています:

classes:

<div class="layout horizontal center" style="height: 150px;">
  <div>center</div>
  <div>center</div>
</div>

mixin:

<dom-module id="horizontal-center-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-center);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div>center</div>
      <div>center</div>
    </div>
  ...

f:id:masterpg:20160923113242p:plain



次のサンプルでは、Cross-axis (Vertical) のend位置にエレメントを配置しています:

classes:

<div class="layout horizontal end" style="height: 150px;">
  <div>end</div>
  <div>end</div>
</div>

mixin:

<dom-module id="horizontal-end-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-end);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div>end</div>
      <div>end</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113410p:plain



次のサンプルでは、上下左右中央にエレメントを配置しています:

classes:

<div class="layout horizontal center-center" style="height: 150px;">
  <div>center-center</div>
  <div>center-center</div>
</div>

mixin:

<dom-module id="horizontal-center-center-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-center-center);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div>center-center</div>
      <div>center-center</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923112843p:plain


Main-axisにエレメントを配置

ここではMain-axisにエレメントを配置する方法についてみていきます。

Note: ここでのサンプルでは、Main-axis (Horizontal) に子エレメントを配置する際、子エレメントが縦方向へストレッチしています。この理由については「Main-axis と Cross-axis」を参照ください) 。


次のサンプルでは、Main-axis (Horizontal) のstart位置に子エレメントを配置しています:

classes:

<div class="layout horizontal start-justified" style="height: 100px;">
  <div>start-justified</div>
</div>

mixin:

<dom-module id="horizontal-start-justified-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-start-justified);
    }
  </style>
  <template>
    <div class="container" style="height: 100px;">
      <div>start-justified</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113508p:plain



次のサンプルでは、Main-axis (Horizontal) のcenter位置に子エレメントを配置しています:

classes:

<div class="layout horizontal center-justified" style="height: 100px;">
  <div>center-justified</div>
</div>

mixin:

<dom-module id="horizontal-center-justified-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-center-justified);
    }
  </style>
  <template>
    <div class="container" style="height: 100px;">
      <div>center-justified</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113549p:plain



次のサンプルでは、Main-axis (Horizontal) のend位置に子エレメントを配置しています:

classes:

<div class="layout horizontal end-justified" style="height: 100px;">
  <div>end-justified</div>
</div>

mixin:

<dom-module id="horizontal-end-justified-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-end-justified);
    }
  </style>
  <template>
    <div class="container" style="height: 100px;">
      <div>end-justified</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113636p:plain



次のサンプルでは、Main-axis (Horizontal) のエレメントとエレメント間のスペースが均等になります:

classes:

<div class="layout horizontal justified" style="height: 100px;">
  <div>justified</div>
  <div>justified</div>
  <div>justified</div>
</div>

mixin:

<dom-module id="horizontal-justified-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-justified);
    }
  </style>
  <template>
    <div class="container" style="height: 100px;">
      <div>justified</div>
      <div>justified</div>
      <div>justified</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113725p:plain



次のサンプルでは、Main-axis (Horizontal) のエレメントの周りのスペースが均等になります:

classes:

<div class="layout horizontal around-justified" style="height: 100px;">
  <div>around-justified</div>
  <div>around-justified</div>
</div>

mixin:

<dom-module id="horizontal-around-justified-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-around-justified);
    }
  </style>
  <template>
    <div class="container" style="height: 100px;">
      <div>around-justified</div>
      <div>around-justified</div>
    </div>
  </template>
  ...

f:id:masterpg:20160923113812p:plain


自身のエレメントの配置設定

Cross-axisにエレメントを配置」ではコンテナにstartcenterなどを適用し、子エレメントの配置をしていました。ここでは子エレメントに直接self-startself-centerなどを適用して子エレメントの配置を行います:

classes:

<div class="layout horizontal justified" style="height: 150px;">
  <div class="flex self-start">Alpha</div>
  <div class="flex self-center">Beta</div>
  <div class="flex self-end">Gamma</div>
  <div class="flex self-stretch">Delta</div>
</div>

mixin:

<dom-module id="horizontal-self-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-justified);
    }
    .child1 {
      @apply(--layout-self-start);
      @apply(--layout-flex);
    }
    .child2 {
      @apply(--layout-self-center);
      @apply(--layout-flex);
    }
    .child3 {
      @apply(--layout-self-end);
      @apply(--layout-flex);
    }
    .child4 {
      @apply(--layout-self-stretch);
      @apply(--layout-flex);
    }
  </style>
  <template>
    <div class="container" style="height: 150px;">
      <div class="child1">Alpha</div>
      <div class="child2">Beta</div>
      <div class="child3">Gamma</div>
      <div class="child4">Delta</div>
    </div>
  ...

f:id:masterpg:20160923113855p:plain


折り返しレイアウト

ここでは収まりきらないエレメントを折り返します。

classes:

<div class="layout horizontal wrap" style="width: 250px;">
  <div>Alpha</div>
  <div>Beta</div>
  <div>Gamma</div>
  <div>Delta</div>
</div>

mixin:

<dom-module id="horizontal-wrap-demo">
  <style>
    ...
    .container {
      @apply(--layout-horizontal);
      @apply(--layout-wrap);
    }
  </style>
  <template>
    <div class="container" style="width: 250px;">
      <div>Alpha</div>
      <div>Beta</div>
      <div>Gamma</div>
      <div>Delta</div>
    </div>
  ...

f:id:masterpg:20160923113945p:plain


リバースレイアウト

ここでは通常とは逆方向にエレメントを配置します。以下はそのクラスとMixinの一覧です:

クラス Mixin
layout horizontal‑reverse ‑‑layout-horizontal-reverse
layout verical‑reverse ‑‑layout-verical-reverse
layout wrap‑reverse ‑‑layout-wrap-reverse

classes:

<div class="layout horizontal-reverse">
  <div>Alpha</div>
  <div>Beta</div>
  <div>Gamma</div>
  <div>Delta</div>
</div>

mixin:

<dom-module id="horizontal-reverse-demo">
  <style>
    ...
    .container {
      @apply(--layout);
      @apply(--layout-horizontal-reverse);
    }
  </style>
  <template>
    <div class="container">
      <div>Alpha</div>
      <div>Beta</div>
      <div>Gamma</div>
      <div>Delta</div>
    </div>
  ...

f:id:masterpg:20160923114033p:plain


<body>をアプリケーション領域で満たす

多くのケースでは<body>領域の全てをアプリケーションで利用したいといったことがほとんどでしょう。このような場合は次の項目を決まりごととして記述してください:

  • <body>タグにfullbleedlayoutverticalクラスを適用する。
  • <body>直下のアプリケーション領域となるエレメント (カスタムエレメント) にflexクラスを適用する。


まず<body>直下のアプリケーション領域を<div>とした場合のサンプルです:

⇒ ソースコード

<!doctype html>
<html>
<head>
  <script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="bower_components/iron-flex-layout/classes/iron-flex-layout.html">
  ...
  <style>
    .my-app {
      background-color: greenyellow;
    }
  </style>
</head>
<body class="fullbleed layout vertical">
  <div class="flex my-app">Fitting a fullbleed body.</div>
</body>
</html>


次は<body>直下のアプリケーション領域をカスタムエレメント (my-app) とした場合のサンプルです:

⇒ ソースコード

<dom-module id="my-app">
  <style>
    :host {
      background-color: greenyellow;
    }
  </style>
  <template>
    Fitting a fullbleed body.
  </template>
  <script>
    Polymer({ is: 'my-app' });
  </script>
</dom-module>
<!doctype html>
<html>
<head>
  <script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="bower_components/iron-flex-layout/classes/iron-flex-layout.html">
  ...
</head>
<body class="fullbleed layout vertical">
  <my-app class="flex"></my-app>
</dom-module>
</body>


どちらのサンプルもこの図のような結果になります:

f:id:masterpg:20160923114129p:plain


汎用的なルール

次のような汎用的なルールも提供されます:

クラス Mixin 内容
block --layout-block display: block
invisible --layout-invisible visibility: hidden
relative --layout-relative position: relative
fit --layout-fit コンテナに子エレメントをフィットさせる

Note: fit (--layout-fit) を使用する場合は、祖先でエレメントのサイズが決められてかつposition: relativeの必要があります。

<div class="layout vertical">
  <div>Before <span>[A Span]</span> After</div>
  <div>Before <span class="block">[A Block Span]</span> After</div>
  <div>Before <span class="invisible">[A Invisible Span]</span> After</div>
  <div class="relative" style="height: 100px;">
    <div class="fit" style="background-color: black; color: white">Fit</div>
  </div>
</div>

f:id:masterpg:20160923114211p:plain