LoginSignup
20
19

More than 5 years have passed since last update.

Polymer 1.0とBootstrap v3を組み合わせる

Last updated at Posted at 2015-06-15

laco0416です。Polymer 1.0からBootstrapのテーマを自作Custom Elementsに適用するのが簡単になった話をします。

0.5から1.0で変わったこと

前回の記事に書いたとおり、Polymer 0.5系におけるShadow DOMの実装はW3Cの仕様に忠実に、Shadow DOMの外からのCSSの侵入を防ぐようになっていました。しかしPolymer 1.x系では実装を軽量で高速な Shady DOM に切り替えたことで、CSSのスコープは内から外への漏洩を防ぐのみとなりました(W3Cの仕様からはズレますが…)。

この変更によりCustom Elements内でグローバルのスタイルを柔軟に適用できるようになったので、Bootstrapのようなテーマと共に使うのがごくごく自然な書き方で実現できます。

PolymerとBootstrapを組み合わせる意義

WebComponentsのないHTMLはスタイリングのためだけにdivネスト地獄を容易に引き起こします。例えば名前の部分だけスタイルを変えるネームタグを作る次のようなHTMLはセマンティックでない構造をしています

<div class="outer">
  <div class="boilerplate">
    Hi! My name is
  </div>
  <div class="name">
    Bob
  </div>
</div>

我々がやりたいことは「ネームタグを描画する」ことです。そしてそのために必要な情報だけをもつ構造は次の形です

<div id="nameTag">Bob</div>

これでは#nameTagの要素にしか適用できないので、汎用的にDOM要素として配置できるようにするのがWebComponentsであり、Polymerです。

<name-tag name="Bob"></name-tag>

誰がどうみてもこのタグはネームタグに「Bob」を表示する要素ですね。
WebComponentsはこのように、divの入れ子構造による非セマンティックなスタイリングを取り払い、DOM構造に意味を持たせることが可能な技術です。

Bootstrapは御存知の通り、だれでも(デザインなんてわからないプログラマーでも!)簡単にレスポンシブで、それなりの見た目のWebページ、アプリケーションが作れるCSSテーマとJSのツールキットのセットです。そして、Bootstrapはとりわけdivネストが深くなりがちです。BootstrapとPolymerを組み合わせることで、少しでもセマンティックなindex.htmlを書くことは、三ヶ月後にそのコードを読む自分を少なからず幸せにするでしょう。

サンプル

Bootstrapにはいくつかのサンプルが用意されていますが、その中で今回は「Jumbotron」というサンプルの中にある小さなパーツをPolymerで作ってみました。

image

完成品がこちらの<row-item>。ドキュメントからheaderlink-toを属性として指定し、コンテンツ部分は分散ノードとして取り込みました

<!DOCTYPE html>
<html>
<head lang="ja">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Bootstrap with Polymer</title>
  <script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"/>
  <link rel="import" href="elements/row-item.html"/>
</head>
<body>
  <div class="container">
    <div class="row">
      <row-item class="col-md-4" header="ヘッダーA" link-to="#A">
        <p>Content of A</p>
      </row-item>
      <row-item class="col-md-4" header="ヘッダーB" link-to="#B">
        <p>Content of B</p>
      </row-item>
      <row-item class="col-md-4" header="ヘッダーC" link-to="#C">
        <p>Content of C</p>
      </row-item>
    </div>
  </div>
</body>
</html>

image

準備

bowerで必要なパッケージをインストールします

> bower install --save polymer PolymerElements/paper-elements bootstrap

エントリポイントになるHTML(ドキュメント)でWebComponentsのPolyfillとBootstrapのCSSファイルを読み込みます。

index.html
<!DOCTYPE html>
<html>
<head lang="ja">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Bootstrap with Polymer</title>
  <script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"/>
</head>
<body>
</body>
</html>

コンポーネント作成

element/row-item.htmlを作成します。今回はドキュメントからBootstrapのスタイルが降ってくるので、コンポーネント内からBootstrapを呼び出す必要はありません。もちろん広く配布したいコンポーネントであればコンポーネント自体をBootstrapに依存させて<link>でCSSファイルを読み込むことも可能です。(参考)

<link rel="import" href="../bower_components/polymer/polymer.html"/>
<link rel="import" href="../bower_components/paper-button/paper-button.html"/>

<dom-module id="row-item">
  <template>
    <h2>{{header}}</h2>

    <content></content>

    <paper-button class="btn btn-primary" on-click="goLink">View details &raquo;</paper-button>
  </template>
  <script>
    Polymer({
      is: 'row-item',
      properties: {
        header: {
          type: String,
          value: "Heading"
        },
        linkTo: {
          type: String
        }
      },
      goLink: function () {
        window.location.href = this.linkTo;
      }
    });
  </script>
</dom-module>

プロパティの宣言

コンポーネントを使用する側からAttributeとして値を渡すにはpropertiesの中でプロパティを宣言する必要があります。

    Polymer({
      is: 'row-item',
      properties: {
        header: {
          type: String,
          value: "Heading"
        },
        linkTo: String
      }
    });

プロパティは名前をキーにオブジェクトもしくは型を指定します。オブジェクトを指定する場合もtypeプロパティは必須です。valueは初期値になります。

プロパティを文字列としてDOM中で展開するには{{}}を使います

<h2>{{header}}</h2>

イベントハンドラ内で使う場合はthisのプロパティとして呼び出せます

      goLink: function () {
        window.location.href = this.linkTo;
      }

イベントリスナは通常のHTML要素と同じように記述できます。ハンドラーはPolymer()に渡すオブジェクトのプロパティとして宣言します。

<paper-button class="btn btn-primary" on-click="goLink">View details &raquo;</paper-button>
    Polymer({
      is: 'row-item',
      properties: {
        header: {
          type: String,
          value: "Heading"
        },
        linkTo: {
          type: String
        }
      },
      goLink: function () {
        window.location.href = this.linkTo;
      }
    });

CSSテーマの適用

ここまでで気づいた方もいるかと思いますが、paper-buttonのクラスにbtn btn-primaryが指定されています。これはBootstrapで宣言されているボタン向けのスタイルです。

image

Bootstrap 3系はフラットデザインがベースになっているので、クリックした際のアニメーション等はありません。

この<row-item>ではPolymerのPaper Elementsに含まれる<paper-button>にこのクラスを設定しています。<paper-button>はマテリアルデザインのボタンスタイルになっていて、クリックした場所から波紋のようにアニメーションが広がります。

image

今回<paper-button>btn btn-primaryを設定したことで、<paper-button>のアニメーションはそのままに、カラーリングやシェイプはBootstrapのbtn btn-primaryを適用することができました

image

配置

作成した<row-item>をドキュメントに配置します。

index.html
<!DOCTYPE html>
<html>
<head lang="ja">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Bootstrap with Polymer</title>
  <script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"/>
  <link rel="import" href="elements/row-item.html"/>
</head>
<body>
  <div class="container">
    <div class="row">
      <row-item class="col-md-4" header="ヘッダーA" link-to="#A">
        <p>Content of A</p>
      </row-item>
      <row-item class="col-md-4" header="ヘッダーB" link-to="#B">
        <p>Content of B</p>
      </row-item>
      <row-item class="col-md-4" header="ヘッダーC" link-to="#C">
        <p>Content of C</p>
      </row-item>
    </div>
  </div>
</body>
</html>

<row-item>も他のHTML要素と変わらず、rowcol-md-4でレスポンシブに表示することができます。

まとめ

Polymer 1.0のShady DOMのおかげで特にShadow DOMのCSSスコープがあることを感じずに簡単にコンポーネント中でBootstrapが使えました。BootstrapにかぎらずほとんどのCSSテーマが同様に使えると思います。既存のWebアプリケーションを部分的にでもPolymerでコンポーネント化してみてはどうでしょうか?

20
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19