Skip to content

Instantly share code, notes, and snippets.

@albatrosary
Last active April 20, 2016 03:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albatrosary/d478f1d1f8e083786a4b0c2cd88ad014 to your computer and use it in GitHub Desktop.
Save albatrosary/d478f1d1f8e083786a4b0c2cd88ad014 to your computer and use it in GitHub Desktop.

Web Components

ご存知の通り、HTMLとCSS、JavaScriptには明確に役割が決まっています。 つまり外観を整えるCSSとHTML、何かしらの処理を行うJavaScriptからWebアプリケーションができています。 HTMLが持つマークアップはセマンティックWebからも重要であることが理解できます。

重要なCSS、HTMLですが、Webアプリケーションを作る上で幾つか問題も指摘されています。例えば

  • 再利用性が悪い
  • CSSスコープが基本的にはグローバル


ということが問題視されます。 重要なCSS定義では「!important」というキーワードを利用することで「スタイルの優先」が定義できます。 この「!important」は後勝問題を解決するために用いることが可能です。

具体的な例を見てみます。

(!important無し)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
<style type="text/css">
  body {background:#ffdff9}
</style>
</head>
<body style="background:#000000;">
</body>
</html>

(!importantあり)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
<style type="text/css">
  body { background:#ffdff9 !important ; }
</style>
</head>
<body style="background:#000000;">
</body>
</html>

「!important」としたCSS定義が優先されブラウザのレンダリングに影響を及ぼしていることが理解できます。 ただ、こうしたキーワードを利用してもWebアプリケーションを開発するための根本的な問題解決にはなっていません。

CSSの設計手法

CSSを用いて開発する場合開発手法として幾つか提案されています。

  • OOCSS: Object Oriented CSS
  • BEM: Block、Element、Modifier
  • SMACSS: Scalable and Modular Architecture for CSS

OOCSS

OOとは、「Object Oriented(オブジェクト指向)」のことで、設定ひとつひとつをCSSオブジェクトとして考え、Webページをレゴの集まりのように考えます。

BEM

BEMとは、Block、Element、Modifierの略語です。 Webサイトのコンポーネント化のためのフロントエンド設計方法のひとつで、厳格なclass名の命名ルールが特徴的な手法です。 そして、__や、_、-を使って単語と単語を区切ります。BEMではこれをセパレーターと呼んでいます。 Block、Element、Modifierのそれぞれの区切りにセパレーターを使用します。すなわち

  • BlockとElementとの区切り
  • Block(あるいはElement)とModifierとの区切りとModifierのkeyとvalueの区切り
  • BlockやElement名を、2つ以上の単語で表す場合の単語と単語との区切り

BEMのデメリットは、次のことが上げられます:

  • 独特な記法のため、BEMを知らない人から見ると、違和感を持つ人もいる
  • ElementやModifierの名前が冗長になりがち

SMACSS

SMACSSとは、Scalable and Modular Architecture for CSSの略語で、「スマックス」と読みます。 SMACSSはCSSの設計手法のひとつで、CSSのルールを5種類にカテゴライズした上で、それぞれの考え方や記述ルールが取り決められているのが特徴的な手法です。

(SMACSSの5つのルール)

  • ベース:要素そのもののデフォルトスタイル
  • レイアウト:ページをエリアごとに分割
  • モジュール:再利用可能なパーツ
  • 状態(ステート):レイアウト,モジュールの特定状態を示す
  • テーマ:サイトのルック&フィールを定義

Web Componentsが解決してくれること

CSS自体の問題や設計手法によって問題をどう解決しようとしたか具体的に見てきましたが、複雑になりがちなWebアプリケーションの解決に対するきれいな回答を得ることは難しいです。
 こういった問題をWeb Componentsが解決してくれるのではという意味においても期待されています。

  • 複雑になりがちなHTML+CSSによるWebページの構築を綺麗にしてくれる
  • ライブラリや方法論に依存せずコンポーネントを再利用することができる

それではWeb Componentsについて見ていきます。

Web Components

Web ComponentsはHTMLを部品化する仕組みです。 Web Componentsというのは概念であり、次の4つのWeb標準からできています。

  • Custom Element
  • HTML Templates
  • HTML Imports
  • Shadow DOM

Custom Element

Custom Elementsは独自タグを定義する仕組みです。 W3Cで定義されたタグを利用するだけでなく、自分たちでタグを定義することが可能になります。

> document.registerElement('my-app')
function my-app() { [native code] }

カスタムタグとして認められないケースももちろん存在します。

> document.registerElement('my_app')
> document.registerElement('myapp')

まとめると次のルールがあります。

  • 二重登録できません
  • 大文字小文字の判定はしません
  • 「-」は必須です。文字と文字で挟む必要があります

このように、新しい要素を登録するためにはdocument.registerElementを利用します。

var XFoo = document.registerElement('x-foo');
document.body.appendChild(new XFoo());

要素をインスタンス化する

要素をインスタンス化するためにはいくつか方法があります。

  • 宣言する
  • JavaScript で DOM を生成する
  • new オペレーター を使う

ひとつひとつ見ていきましょう

宣言

カスタムタグを通常のHTMLタグと同様に定義します

<x-foo></x-foo>

JavaScript で DOM を生成

JavaScript で DOM を生成する

var xFoo = document.createElement('x-foo');
xFoo.addEventListener('click', function(e) {
  alert('Thanks!');
});

new オペレーター

new オペレーター を使う

var xFoo = new XFoo();
document.body.appendChild(xFoo);

JavaScript プロパティとメソッドの追加

JavaScript プロパティとメソッドを追加することも可能です。

var XFooProto = Object.create(HTMLElement.prototype);

// x-foo に foo() メソッドを追加
XFooProto.foo = function() {
  alert('foo() called');
};

// 読み込み専用のプロパティ "bar" を定義
Object.defineProperty(XFooProto, "bar", {value: 5});

ライフサイクルコールバックメソッド

コールバックメソッドが幾つか定義されています。

コールバック名 呼び出されるタイミング
createdCallback 要素のインスタンスが作られた時
attachedCallback インスタンスがドキュメントに追加された時
detachedCallback インスタンスがドキュメントから取り除かれた時
attributeChangedCallback(attrName, oldVal, newVal) 属性が追加、削除、更新された時

次のように書くことができます。

var proto = Object.create(HTMLElement.prototype);

proto.createdCallback = function() {...};
proto.attachedCallback = function() {...};

マークアップを追加します。

var XFooProto = Object.create(HTMLElement.prototype);

XFooProto.createdCallback = function() {
  this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
};

var XFoo = document.registerElement('x-foo-with-markup', {prototype: XFooProto});

HTML Templates

次に「HTML Templates」について見ていきます。 HTML 要素はマークアップ上のテンプレートを表わします。

<template id="mytemplate">
  <img src="" alt="great image">
  <div class="comment"></div>
</template>

テンプレートはアクティベートされ初めてブラウザで動作可能となります。

  • コンテンツはアクティベートされるまで自律動作しません。
  • スクリプトは動作しませんし、画像はロードされません。オーディオも再生されません
  • コンテンツはドキュメント内に存在しないものとして扱われます
var t = document.querySelector('#mytemplate');
// src をランタイムに埋める
t.content.querySelector('img').src = 'logo.png';
var clone = document.importNode(t.content, true);
document.body.appendChild(clone);

HTML Imports

HTML ImportsはHTML Templatesで再利用可能にしたHTMLを取り込むための仕様です。 ページに を宣言してインポートします。サンプルを見てみましょう。

(import.html)

<template>
  <h1>Hello World!</h1>
  <!-- <template> が実際に使われるまで img はリクエストされない -->
  <img src="world.png">
  <script>alert("Executed when the template is activated.");</script>
</template>

(index.html)

<html>
  <head>
    <link rel="import" href="import.html">
  </head>
  <body>
    <div id="container"></div>
    <script>
      var link = document.querySelector('link[rel="import"]');
  
      // import で <template> をクローンする
      var template = link.import.querySelector('template');
      var clone = document.importNode(template.content, true);
  
      document.querySelector('#container').appendChild(clone);
    </script>
  </body>
</html>

Shadow DOM

上記3つでHTMLの部品化は出来ましたが、問題はCSSのスコープにあります。そのスコープを定義するためにShadow DOMという仕様があります。このShadow DOMのお陰で部品化されたコンポーネントの書式を隠蔽することができます。

次の具体的なサンプルを見てみましょう。

https://github.com/albatrosary/webcompoments

サンプル

応用として次のサンプルを実行してみましょう。

https://github.com/albatrosary/x-business-card

Polymer

Web ComponentsはWeb標準となる仕様でブラウザでのネイティブ実装になっています。webcomponents.jsというポリフィルライブラリをラッピングしています。これによりすべてのブラウザでPolymerが動くことを保証します。Web Componentsを利用しやすく実装されたライブラリがPolymerになります。Polymerは7つの機能から構成されます。

  • Fe(Iron Elements)
  • Md(Paper Elements)
  • Go(Google Web Components)
  • Au(Gold Elements)
  • Ne(Neon Elements)
  • Pt(a Elements)
  • Mo(Molecules)

https://www.polymer-project.org/1.0/

https://html5experts.jp/girlie_mac/12359/

https://github.com/albatrosary/paper-chat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment