Graceful DegradationとProgressive Enhancementの実践
Chris Heilmanによる“Graceful degradation versus progressive enhancement”という記事について、前回は概要とその意義について紹介しました。今回は後半にあるの例をもとに、どのように実践していくのかを考えてみたいと思います。
「印刷する」というリンク
オンラインショッピングの決済画面には、印刷して手元に保管したいというニーズがあるからか「印刷する」といったリンクやボタンが設けられています。クリックしたときに印刷用ページが現れるものもありますが、記事では印刷ダイアログが現れる簡単なものを取り上げています。
このようなリンクは、JavaScriptにより実現されています。
<p id="printthis">
<a href="javascript:windowprint()">Print this page</a>
</p>
しかしながら、JavaScriptが無効な環境では、リンクが機能せず全く意味がなくなってしまいます。というわけで、noscript
要素を利用して、利用できない環境に向けたメッセージを記述することにしましょう。
ただ、「JavaScriptが有効になっていません」といったものはあまり意味がありません。「その機能が何で実装されているか」という情報を、ユーザーが直接求めているわけではないからです。なので、ここではブラウザーの印刷機能について書くことにしましょう。
<p id="printthis">
<a href="javascript:windowprint()">Print this page</a>
</p>
<noscript>
<p class="scriptwarning">
Print a copy of your confirmation.
Select the "Print" icon in your browser,
or select "Print" from the "File" menu.
</p>
</noscript>
「『印刷』アイコンまたは『ファイル』メニューより『印刷』を選択することで、印刷することができます。」といった文を書くことで、代替手段を直接提供はしないものの、ユーザーにその存在を伝えることができます。
起こってしまった問題への「対処」という側面が強いので、これはGraceful Degradation的なアプローチといえるでしょう。では、Progressive Enhancementでは、どのようなアプローチになるでしょうか。
Progressive Enhancementな印刷リンク
Progressive Enhancementは、最低限提供したい機能や目的を「ベースライン」として設定します。印刷リンクは「ページを印刷したいというユーザーのニーズに答える」ことが目的ですから、まず「ページの印刷について言及する」ことをベースラインとしましょう。
<p id="printthis">Thank you for your order.
Please print this page for your records.</p>
まず「印刷して保管できます」ということを伝える文を書きます。もちろん、先ほどのように、ブラウザーの印刷手法について言及するのも悪くないでしょう。
さて、印刷リンクはどのように実装すればよいでしょうか。ここで登場するのが、「Unobtrusive JavaScript」という考え方です。「おせっかいではないJavaScript」という意味のこのキーワードですが、簡単に説明すると、不必要にUAやHTMLに干渉したり依存したりすることのないようにJavaScriptを書くことです。
「おせっかいなJavaScript」の例としては、リンク先を新規ウインドウやポップアップで開く、次のようなコードが該当します。
<a href="#" onclick="window.open('popup.html','_blank')">ポップアップ</a>
JavaScriptが無効な環境では、通常のページ遷移すら行われないため、情報にアクセスすることができなくなってしまいます。このようなおせっかいをせずに、印刷リンクを追加するコードを書くわけです。
記事の中で、Unobtrusive JavaScriptな印刷ボタンを追加するコードは、次のように実装されています(この例ではリンクではなく、ボタンになっています)。
(function(){
if(document.getElementById){
var pt = document.getElementById('printthis');
if(pt && typeof window.print === 'function'){
var but = document.createElement('input');
but.setAttribute('type','button');
but.setAttribute('value','Print this now');
but.onclick = function(){
window.print();
};
pt.appendChild(but);
}
}
})();
getElementById
の存在や、window.print()
が機能するかを確かめた上で、ボタンをDOMにより生成し、先ほどの段落に追加しています。
最終的なコードは、次のようになります。
<p id="printthis">Thank you for your order.
Please print this page for your records.</p>
<script type="text/javascript">
(function(){
if(document.getElementById){
var pt = document.getElementById('printthis');
if(pt && typeof window.print === 'function'){
var but = document.createElement('input');
but.setAttribute('type','button');
but.setAttribute('value','Print this now');
but.onclick = function(){
window.print();
};
pt.appendChild(but);
}
}
})();
</script>
ブラウザーがJavaScriptコード中で必要な機能を満たすときのみ、印刷ボタンが現れます。
このやり方は、印刷リンク(ボタン)だけではなく、文字の拡大縮小インターフェースなどにも利用することができるでしょう。まずブラウザーの文字サイズ変更機能について言及し、インターフェースをあとからJavaScriptで組みこむのです。
今回の印刷ボタンは、window.print()
というブラウザーのAPIにどうしても依存してしまうものなので、「実現したいもの」と「最低限必要なもの」の差が大きく開いている例です。次回は、漸進的なEnhancementの例をお見せしたいと思います。
コメント
前回の記事へのリンク先がこの記事になっているようです。
正しくは http://standards.mitsue.co.jp/archives/001387.html でしょうか。
levaさま、ご指摘ありがとうございます。
リンクを修正し、エントリを更新しました。