HTMLのカスタム要素(とシャドウDOM)を使ったWebコーディング
Jitoinを開発しているitteと申します。Webエンジニア向けのサービスや記事を公開しています。
今回はHTMLのカスタム要素(Custom Element)について解説します。
カスタム要素を使うとオリジナルのHTMLタグを作ることができます。
カスタム要素の利用例
例えば次のタグは文字色をあらかじめ決めておいたプライマリ色に変えるタグです。
<color-primary>Primary</color-primary>
これだけだと、class
を使うのと変わりありませんね。
次の例はどうでしょうか。ランディングページのHTML例です。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LP</title>
<style>* { margin: 0; }</style>
</head>
<body>
<main-visual></main-visual>
<used-by></used-by>
<section-concept></section-concept>
<conversion-type1></conversion-type1>
<section-point1></section-point1>
<section-point2></section-point2>
<section-point3></section-point3>
<conversion-type1></conversion-type1>
<section-qa1></section-qa1>
<section-qa2></section-qa2>
<section-qa3></section-qa3>
<conversion-type2></conversion-type2>
<script src="./script.js"></script>
</body>
</html>
私の英語力は置いておいて、タグを読めばなんとなく、どんなコンテンツがあるか分かります。これはカスタム要素の概念を表したもの・・・ではなく、正しいHTMLです。
このHTMLにはランディングページにあるはずの画像や説明文、製品購入ページへのリンクタグが見当たりません。
どこへいったのかというと、最後に読み込んでいる./script.js
の中で生成されています。
カスタム要素をどうやって作るか
愚直にカスタム要素を作ろうとするとJavaScriptの知識が必要になります。しかもその方法が簡単な仕組みで提供されていないのでJavaScriptに慣れていないと難しいかもしれません。
でも、安心してください。
Jitoinを利用すればHTMLとCSSの知識だけでカスタム要素を作ることができます。
Jitoinは、HTMLを既存Webサイトに追加するという、何だかふわっとしたサービスですが、追加する手段としてカスタム要素も提供しています。
これから、Jitoinを使って、カスタム要素を作る方法を解説します。
事前準備
Jitoinに登録する
Jitoinに登録するには、Googleアカウントが必要です。
サイトの右上に『Googleでログイン』ボタンがありますので、そこから利用開始できます。
Jitoinタグを作る
ログインすると、コンソール画面に移動します。
『新しいタグを作る』ボタンを押すと、すぐにJitoinタグが生成されます。Jitoinタグの説明は後述します。
画面下に現れた英数字の羅列は、作ったJitoinタグの名称(変更可)になります。これを押します。
JitoinタグをWebサイトに張り付ける
切り替わった画面で、5行の<script>
タグが書かれています。これがJitoinタグです。2I1*******
のところはタグによって異なります。
このJitoinタグをカスタム要素を使いたいページに張り付けます。ローカルのHTMLファイルでも問題ありません。そうすることでJitoinが対象ページにHTMLを追加できるようになります。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!-- Jitoin Fire Tag -->
<script type="module">
import fire from '/js/fire.js';
fire('websites/2I7*******');
</script>
</body>
</html>
以上で準備完了です。
カスタム要素を作る
先の画面に『新しいコンポーネントを作る』ボタンがありますので押すと、Jitoinのコンポーネントを作る画面に遷移します。
まずはテンプレートを選ばされますので、『テンプレートなし』を選びます。
テンプレートを選んだら、アクションと書かれているところで『カスタム要素』を選んで、仮にmain-visutal
と入力します。カスタム要素のタグ名のルールとしてハイフンを1つ以上含むことになっています。
次に、ガイドの左にあるコードマークを押します。
すると次のようにHTMLを編集できるエディタが現れます。このHTMLがカスタム要素の中身になります。これを好きなように書き換えてください。
今回は全部消して、『Hello』と書いてみましょう。
これでカスタム要素の作成が完了しました。今は下書き状態ですので、公開ボタンを押します。
作ったカスタム要素を使う
先ほど作ったカスタム要素を使ってみます。Jitoinタグを入れたページに次のタグを書くだけです。
<main-visutal></main-visutal>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<main-visutal></main-visutal>
<!-- Jitoin Fire Tag -->
<script type="module">
import fire from '/js/fire.js';
fire('websites/2I7*******');
</script>
</body>
</html>
キャッシュの影響ですぐに反映されない場合がありますが、最大2分以内には対象ページにHelloと表示されます。
シャドウDOMのコーディングのポイント
Jitoinでカスタム要素を作ったときは、シャドウDOMというものを用いています。このシャドウDOMでHTML・CSSを書くときはいくつか気を付けるポイントがあります。
シャドウDOMとは
カスタム要素を使ったときに、カスタム要素内部のHTMLは隠蔽されています。先の例でいうと<main-visutal></main-visutal>
と書くだけで、『Hello』の文字を書かなくても『Hello』と表示されました。
これはシャドウDOMという、その要素だけの独自のDOM(HTML文書)が存在しており、その中に隠されているのです。
シャドウDOMはシャドウと言っておきながら、画面には表示されます。DOM(HTML文書)上では隠されているという点でシャドウという言葉が使われています。
カスタム要素とシャドウDOMは別々の概念で、JavaScriptではそれぞれ個別に利用できるのですが、一緒に利用されることがよくあります。
そして、Jitoinで作るコンポーネントはすべてシャドウDOMを使っていますので、カスタム要素にも必ずシャドウDOMがあります。
以降の説明にあたり、カスタム要素の中のシャドウDOM、すなわちブラウザでJitoinにログインして書くHTMLを内側のHTML(CSS)、作ったカスタム要素を使う側のHTMLを外側のHTML(CSS) と表現することにします。
外側のCSSは適用されない
これはメリットでありデメリットでもあります。
例えば外側のCSSにページ内のすべての要素のマージンを0にするCSSを書いていたとします。
<!DOCTYPE html>
<html>
<head>
...
<style>
* {
margin: 0;
}
</style>
</head>
...
<main-visutal></main-visutal>
...
これはシャドウDOMmain-visutal
の内側のHTMLには適用されず、マージンが復活します。
もし、内側のHTMLもマージンを0にしたい場合は、内側のCSSで再びマージンを0にする必要があります。
面倒に思うかもしれませんが、逆に言えば、シャドウDOMの外側でどのようなCSSが書かれていたとしても無視してコーディングできます。
他にも、シャドウDOMが複数あるときも、互いに別のシャドウDOM(空間)ですので、お互いを気にする必要はありません。
クラス名やidといったCSSセレクタの重複を気にする必要が無いのです。
:host疑似クラス
カスタム要素それ自体にスタイルを当てたいときは、2通りの方法があります。
1つ目は外側のCSSで、カスタム要素をセレクタで指定する方法です。以下の例ではタグ名を指定していますが、クラスやIDでも同様です。
custom-element {
color: red;
}
2つ目は内側のCSSで、:host
疑似クラスを使う方法です。
:host {
color: blue;
}
特筆すべき点として、
カスタム要素自体は外側のDOMに属します。
これ重要です。
:host
疑似クラスは内側のCSSから、外側のHTMLにスタイルを当てることができる特別な疑似クラスとなります。
もし外側のCSSと内側のCSSの両方からカスタム要素にCSSを当てた場合は、外側のCSSが優先されます。
つまり:host
疑似クラスを使ったCSSプロパティは、上書きされてしまうことがあるということです。防ぐ方法は次のセクションで説明します。
継承とCSS変数は引き継がれる
シャドウDOMの外側のCSSは、シャドウDOMの内側のHTMLに適用されないと説明しましたが、フォントサイズや文字色といった、継承は内側のHTMLに突き抜けてきます。
ほかにも、定義したCSS変数やvw
、rem
、<!DOCTYPE>
といった、ドキュメント/デバイスによるものも引き継がれます。
そのため、例えばページ全体の文字色をグレーにしていた場合、シャドウDOMの中の文字色もグレーになります。
もし、継承されないようにしたい場合は、次のように:host
でall
プロパティを使います。
:host {
all: initial;
}
ここで思い出していただきたいのは、:host
はシャドウDOMの外側にあるということです。
実は、シャドウDOMにもシャドウルートという<html>
タグおよび:root
疑似クラスに該当する最上位の要素が存在しますが、困ったことに現状、シャドウルートをCSSセレクタで指定する方法がありません。
そのため、:root
の代わりとしても:host
が使われています。
これは、シャドウDOMの外側で値を初期化して、初期化された値がシャドウルートを突き抜けて内側に継承しているということになります。
ということは、all
プロパティで初期化したとしてもシャドウDOMの外側のCSSで上書きされてしまうと、結局は上書きされた値を継承してしまうということです。
これをどうしても防ぎたいときはシャドウDOMの中に全体を囲むdiv
要素を置いて、そこで初期化すると回避できます。
<div class="root">
Hello
</div>
<style>
.root {
all: initial;
}
</style>
カスタム要素の子
最初の例に戻って、カスタム要素に次のように子要素を書いたとします。
<color-primary>Primary</color-primary>
このとき、『Primary』というテキストは外側のHTMLに書いているのですが、シャドウDOMが存在していると実際に画面に表示されるのは内側のHTMLになります。『Primary』はカスタム要素がJavaScriptで定義されるまでは表示されますが、その後は表示される保証はありません。
では、『Primary』がどう扱われるかというと、カスタム要素の作者にゆだねられています。
Jitoinは、これに関していくつかの方法を提供していますが、難しい話になりますのでここでは1つだけ紹介します。その他は別記事で書きますのでお待ちください。
最も簡単な方法として紹介するのは、内側のHTMLに{{ content }}
と書く方法です。{{ content }}
と書いたところにカスタム要素の子に書かれたHTMLを展開します。
<span style="color: blue">{{ content }}</span>
注意点として、あくまでHTMLとして展開しているので、外側のCSSは効かず、内側のCSSが適用されます。そのためclass
やid
を使わないHTMLに留めるべきです。
SEOはどうなのか
カスタム要素を導入するにあたって気になるのはSEOへの影響です。
カスタム要素とシャドウDOMに対応している検索エンジン
カスタム要素&シャドウDOMのコンテンツを解析してくれる検索エンジンはいくつかあります。
私が実際にサイトを作って検証したところ、最大手のGoogleは対応していました。Ask、Startpageも対応を確認しています。Bing、Yahooは未対応でした。
なお、Googleは対応しているといっても、私の個人的な感想として、シャドウDOMの内側のHTMLがインデックスされるまでに時間がかかった印象を受けました。最初、シャドウDOMの外側だけインデックスされていたので、内側はインデックスされないのかと思いましたが、後日シャドウDOMの内側もインデックスされました。
勝手な推測ですが、GoogleはJavaScriptを動かさずに解析するBOTと、JavaScriptを動かすBOTが2つ走っているのではないでしょうか。負荷が高くなる後者は、負荷の分だけ動きが鈍いのでしょう。
パフォーマンス
カスタム要素はページが読み込まれた後でJavaScriptで内側のHTMLを描画します。そのため、ページが読み込まれたときに描画されている通常のHTMLよりも表示がどうしても遅くなります。
PageSpeed Insightsでパフォーマンスを上げるには相当頑張らないといけないでしょう。
対応ブラウザ
主要ブラウザをまとめるとこうなります。
ブラウザ | 対応年 |
---|---|
Chrome | 2016年末~ |
Safari | 2017年~ |
FireFox | 2018年末~ |
Edge | 2020年~ |
ChromeとSafariの対応が早かったので、現在利用されているスマホはほぼ問題ありません。FireFoxとEdgeの対応が遅かったため、古いPCを使っている人には表示できないことがあるかと思います。
スマホではCSSのグリッドレイアウトとほぼ同時期、PCではmax-content
系と同時期です。
詳しくはCan I useで確認できます。
SEOを最重視するページには向いてない
以上のことから、SEOが重要となる企業HPやブログ、ECサイトにはまだおすすめできないことが分かります。
しかし、クローズドサイトや広告からの流入を想定しているランディングページでは十分に利用できます。あるいは、ページ内でSEOが重要でないコンテンツだけカスタム要素にするというのも問題ありません。
他には、次のようにSEOが重要な文章だけシャドウDOMの外に出すという方法があります。
<main-article>
こんにちは
・・・
</main-article>
おわりに
最近ではShopifyの公式テーマもカスタム要素が導入され始めました。今後どんどん普及していくと思います。
Discussion