インターン生は、連日の講義と課題で大変そうですが、今日も講義が続きます。
本日は、id:nanto_viによる「ユーザインターフェース,HTML5」です。仕様書を隅々まで読んだ講師によるディープな講義内容となっています。今日も2時間の長丁場ですが、頑張って着いていきましょう!
ユーザーインターフェース、HTML5
ユーザーインターフェースで大切なこと、HTML5 及び関連 API で何ができるか
自己紹介
- nanto_vi (外山真, TOYAMA Nao)
- ブックマークチーム アプリケーションエンジニア
- はてなブックマーク Firefox 拡張
- はてなツールバー for Firefox
- はてなブックマーク Twitter 投稿機能
- はてなサマーインターン 2008
- なんとなく Emacs
- 富山県南砺市とはあまり関係なし
- ブックマークチーム アプリケーションエンジニア
概略
- UI の評価・設計・実装の概略
- HTML についての概略、HTML5 とは何か
- HTML5 及び関連 API の機能をざっと紹介
- 「標準」に関して
- 課題
ユーザーインターフェース (UI)
interface
【名】英辞郎 on the Web:スペースアルク
- 接合部分、接触面◆異質な物の間の
- 接点、仲立ち、連絡(係)、橋渡し(役)◆【同】liaison
- 《コ》インターフェース
- 《物理》界面
- 機械と人間が情報をやり取りする接点
- 優れた機能であっても、人とつながらなければ意味がない
Norman のデザイン原理
- 可視性
- 状態・機能が見て取れるように
- フィードバック
- 反応を返すことで何をしているのかわかるように
- 制約
- 制限を加えることで誤操作を防ぐ
- 対応付け
- 制御とその結果に関係性を持たせる
- 一貫性
- 同じ機能は同じ操作で
- アフォーダンス
- 操作の手がかりを与える
Design Principles
cf. 概念モデル
UI の評価
- ヒューリスティック評価
- ヒューリスティック (経験則) に沿って問題を発見していく
- ユーザーが常に状態を把握できるか?
- ユーザーにわかりやすい言葉を使っているか?
- etc.
- ヒューリスティック (経験則) に沿って問題を発見していく
- 認知的ウォークスルー
- シナリオに沿ってユーザーの行動をシミュレート
- ユーザー像 (ペルソナ) とタスクを設定
- タスク達成に必要な操作系列を準備
- 各操作を分析
- 次に何を達成すればいいのかをユーザーはわかるか
- 次にどう操作すればいいのかをユーザーはわかるか
- 正しい操作だったかどうかをユーザーはわかるか
- シナリオに沿ってユーザーの行動をシミュレート
- ユーザーテスト
例: プロフィール画像変更
- ユーザー像: 日常的に Web を使っている学生
- タスク: はてなのプロフィール画像を変更する
- 操作系列
- ユーザー設定ページに移動
- プロフィール画像設定ページに移動
- 現在のプロフィール画像を削除
- 新しいプロフィール画像を設定
UI の設計
- ユーザーを想定する
- ≠ ユーザーの言うがままにする
もし人々に何がほしいか尋ねていたら、彼らはより速い馬がほしいと答えていただろう。
ヘンリー・フォード
- ユーザーの行動を観察する
- cf. 「真心の想像力」
- 既存の UI に学ぶ
- ユーザーエクスペリエンスガイドライン
- 検証・評価方法はある程度確立されている
例: ブックマーク追加時のオプション
- 対象ユーザー
- ブックマークはするが、オプション機能を使っていないユーザー
- ユーザーにしてもらいたいこと
- Twitter 連携機能の存在を知り、使ってもらう
- 非公開ブックマーク機能 (はてなブックマークプラス) の存在を知り、使ってもらう
Web での UI の実装
- いままで
- HTML → HTML → HTML
- 現在 (+ JavaScript)
- インタラクティブ性の向上
- HTML → Ajax によるデータ読み込み
- その場で様々な情報を取得・表示
- 動的な検索・RSS リーダー・地図アプリケーション
- 短時間で効率よく情報にアクセス
- インタラクティブ性の向上
はてなでの UI の実装
様々な場所に JS (+ Flash) が
- はてなブックマーク
- その場検索
- キーバインド
- 日記その場編集
- お絵かきツール
- フォトライフアップローダ
ハイブリット (JS と Flash の合わせ技) も使われている
HTML
- HyperText Markup Language
- Web を支える技術のひとつ
- 文書構造を記述
- ごく簡単なHTMLの説明 の「簡単なHTMLの説明」までは必読
あなたを識別し、あなたと対話し、あなたを理解する。 RT @eto: 「Webにとって必要な要素を重要度の順に並べてみると、URI、HTTP、そしてHTMLである。」Tim Berners-Lee「Webの創成」p.53
HTML5 の誕生
- HTML 4 / XHTML 1.0
- 国際化、アクセシビリティ、マルチメディア
- XHTML 1.1
- モジュール化、拡張性 (他の仕様と組み合わせられるように)
- XHTML 2.0
- 「文書」の表現に特化
- 「アプリケーション」の作成は XForms、XML Events、DOM、XFrames、SMIL、SVG、MathML、RDFa といった他の仕様と組み合わせて
- HTML5
- 大きく作り直すのではなく、既存のものの改良で
- アプリケーションの作成も重視
- 旧称 Web Applications 1.0
- 機械アクセス可能なデータの記述
HTML5 仕様の範囲
- HTML 4
- 要素・属性・内容モデル、意味論を定義
- 構文は SGML を利用
- XHTML 1.x
- 要素・属性・内容モデルを定義
- 意味論は HTML 4 のものを流用
- 構文は XML を利用
- HTML5
- 要素・属性・内容モデル、意味論、構文、API を定義
- 構文は XML も利用可能
- 従来の HTML 仕様に加えて、DOM HTML、基礎的な構文の範囲もカバー
- 広義の HTML5
- HTML5 仕様 + Web ブラウザ用の各種 API 仕様
- いくつかの仕様はかつて HTML5 仕様に含まれていたもの
- バズワードとしての HTML5
- 最近のブラウザで実現できそうなありとあらゆること
- CSS 3、独自拡張 CSS、SVG、ECMAScript 5
HTML5 の HTML 構文
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>こんにちは、世界 - お試しサイト</title> </head> <body> <h1>こんにちは、世界</h1> <p lang="en">Hello, world.</p> <p><a href="/so?me=th&in=g">何か</a>いる。</p> </body> </html>
おすすめは、
- 文書型宣言から始める
- 属性値は二重引用符で囲む
- 要素の開始タグと終了タグは省略しない
- どんな場合に何を省略できるのかいちいち考えるのは面倒だし、見落としがあると危険
<
、>
、&
、"
はそれぞれ<
、>
、&
、"
<script type="text/javascript" src="/js/foo.js"></script> <script type="text/javascript"> if (x && y) call('<script type="text/javascript"><\/script>'); </script>
- script 要素の内容には、
<!--
と</script
を直接記述しなければ何でも書ける<!--
を書いたら、対応する-->
を書く必要あり"</"
はすべて"<\/"
と書くのが安全
だいたい、XSS なんてのは「何が起きても常に valid な HTML を出力する」という誇りがありさえすれば、それだけで 9割方回避できるのです。ユーザが入力した < を文字参照に変換する処理は、誇りを守るための処理であって、セキュリティを意識したものではないのです。
H18年度ウェブアプリケーション開発者向けセキュリティ実装講座 | 水無月ばけらのえび日記
セクションとアウトライン
- 章構造の明確化
- ISO-HTML が目指し XHTML 2.0 が成そうとしたもの
section
、article
、nav
、aside
などセクションを生成する要素の導入- 今までどおり
h1
-h6
要素を使うだけでも、それなりに適切なアウトラインが生成される
canvas
要素
- スクリプトからラスタ画像を描画
- はてなではグラフ描画などに利用
<span id="my-graph">25日: 130 km/h, 30日: 160 km/h</span> <script> function drawGraph() { var canvas = document.createElement('canvas'); if (!canvas.getContext) return; canvas.setAttribute('width', '300'); canvas.setAttribute('height', '300'); var placeholder = document.getElementById('my-graph'); placeholder.parentNode.replaceChild(canvas, placeholder); var context = canvas.getContext('2d'); context.strokeRect(...); ... } drawGraph(); </script>
video
、audio
要素
- フォールバック内容を持てる
<video width="300" height="300" control> <source src="video.ogv" type="video/ogg; codecs="theora, vorbis""> <source src="video.mp4" type="video/mp4; codecs="avc1.42E01E, mp4a.40.2""> <object data="video.swf" type="application/x-shockwave-flash" width="300" height="300"> <param name="movie" value="video.swf"> かくかくしかじかなビデオがあり、…… </object> </video>
フォームコントロール
- 新たな種類のコントロール
- 未対応のブラウザではテキストフィールド
- 新たな属性
input
イベント
<input type="url"> <input type="date" required> <input type="text" placeholder="チャンネル名を入力">
- チェックボックス、ラジオボックスにはラベルを
<label for="my-check"> <input id="my-check" type="checkbox"> 確認する </label>
編集 API
- contenteditable 属性
element.contentEditable
- 特定要素を編集可能に
document.designMode
- 文書全体を編集可能に
document.execCommand()
- 特定の編集操作を実行
Drag and Drop API
draggable
属性- ドラッグ & ドロップ時に各種イベントが発生
- 複雑
File API
<input type="file">
で選択したファイルを取得- 内容を読み込んで XMLHttpRequest で送信など
- ブラウザ外からドラッグ & ドロップしてきたファイルも
Microdata
- 機械認識可能なデータの記述方法
- DOM API も定義
- 既存の語彙を使えば共通の意味が保証される
<p itemscope> <span itemprop="name">nanto_vi</span> さんの <a href="http://b.hatena.ne.jp/nanto_vi/" itemprop="bookmarks">ブックマーク</a> </p>
機械認識可能なデータ
- データの記述
- Microdata
- microformats
a
、area
、link
要素のrel
属性
- Web の利用者は人間だけではない
- LDRize
- 「今、私のため」ではなく「いつか、誰かのため」
カスタムデータ属性
- 名前が
data-
から始まる属性 - サイトにとって私的なデータ
- 第三者が何らかの意味に解釈することはない
<ul data-eid="42"> <li data-user="nanto_vi">nanto_vi said yes.</li> <li data-user="r_kurain">r_kurain said no.</li> </ul>
URL と生成元
- URL
- URL ⊂ URI (RFC 3986)
- ここでの URL は Uniform Resource Locator の略
- URL ⊃ URI (HTML5)
- URL ⊂ URI (RFC 3986)
- 生成元 (origin)
- スキーム、ホスト、ポートの組
- http URL においてはパスより前の部分で表される
http://example.org/foo/bar
の生成元はhttp://example.org
- スクリプトからは異なる生成元の文書にアクセスできない
Web Storage
- クライアント側でのデータ保存
- キーと値のペア
- 生成元ごとに独立
sessionStorage
- ブラウザを終了するまで
- ブラウザのタブ単位で独立
localStorage
- ブラウザの終了後も保存される
if (window.localStorage) { localStorage.foo = 'bar'; doSomething(localStorage.foo); }
オフライン機能
- アプリケーションキャッシュ
- マニフェストに記載されたりソースをローカルにキャッシュ
online
、offline
イベント
window.addEventListener('offline', function (event) { alert('オフライン状態になりました'); }, false);
履歴管理
history.pushState()
- ブラウザの戻る / 進む履歴に項目を追加
history.replaceState()
- ブラウザの戻る / 進む履歴の項目を置換
hashchange
イベント- URL のフラグメント部分 (
#
以下) の変更時に発生
- URL のフラグメント部分 (
文書間メッセージング
- 異なる文書 (の
window
) にメッセージを送信 - 異なる生成元の文書間でも通信可能
<!-- http://example.org/foo --> <iframe id="my-frame" src="http://example.com/bar"></iframe> <script> var frame = document.getElementById('my-frame'); // 生成元が http://example.com である // 文書にメッセージ "hello" を送信 frame.contentWindow.postMessage('hello', 'http://example.com') </script>
<!-- http://example.com/bar --> <script> window.addEventListener('message', function (event) { // http://example.org からのメッセージのみ処理 if (event.origin !== 'http://example.org') return; alert(event.data); // "Hello" // メッセージを送り返す event.source.postMessage('world', event.origin); }, false); </script>
Cross-Origin XMLHttpRequest
- XMLHttpRequest Level 2
- 生成元が異なるリソースの取得
progress
イベント
- Cross-Origin Resource Sharing
- HTTP ヘッダを基に異なる生成元からの要求を許可
WebSocket
- 全二重双方向通信
- WebSocket API
- プログラミング言語から通信を扱う API
- WebSocket Protocol
- 実際の通信方式を定めたプロトコル
Server-Sent Events
- サーバーからのプッシュ通信でイベント発生
var source = new EventSource('/event/source'); source.onmessage = function (event) { alert(event.data); };
Web Workers
- JavaScript を別スレッドで実行
- 主文書とはメッセージ通信
- ワーカー内では DOM に触れない
var worker = new Worker("fibonacci.js"); worker.onmessage = function (event) { document.getElementById("result").textContent = event.data; };
Selectors API
- スクリプトから CSS セレクタで要素を選択
node.querySelector('p')
- 単一の要素
- セレクタが複数要素にマッチする場合は文書順で最初の要素
- マッチする要素がなければ
null
node.querySelectorAll('#foo .bar')
- ノードリスト (配列のようなオブジェクト)
- マッチする要素がなければ空のノードリスト
DocumentFragment
に対しても利用可能
WCAG 2.0
- Web Content Accessibility Guideline 2.0
- 誰でも情報にアクセスできるように
- 4 原則
- 知覚可能
- 操作可能
- 理解可能
- 堅牢性
WAI-ARIA
- Accessible Rich Internet Applications
- 機械認識可能な UI 部品 (コントロール) の作成
<dl role="tablist"> <dt id="a" role="tab" aria-selected="true" tabindex="0">A</dt> <dd role="tabpanel" aria-labelledby="a">...</dd> <dt id="b" role="tab" tabindex="0">B</dt> <dd role="tabpanel" aria-labelledby="b" aria-hidden="true">...</dd> </dl>
Web IDL
- 言語中立なインターフェースの記述
- 各種 API 仕様を読むのに必須
- JavaScript では
attribute
がプロパティに対応 - 拡張属性
[...]
で付加情報を記述
interface HTMLElement : Element { // DOM tree accessors NodeList getElementsByClassName(in DOMString classNames); // metadata attributes attribute DOMString id; attribute DOMString title; attribute DOMString className; readonly attribute DOMTokenList classList; readonly attribute DOMStringMap dataset; // microdata attribute boolean itemScope; attribute DOMString itemType; attribute DOMString itemId; [PutForwards=value] readonly attribute DOMSettableTokenList itemRef; [PutForwards=value] readonly attribute DOMSettableTokenList itemProp; readonly attribute HTMLPropertiesCollection properties; attribute any itemValue; // user interaction void focus(); void blur(); };
CSS
- グラフィカルな UI の実現に必須
- 現行仕様は CSS 2.1
- 包含ブロック (containing block)
- 多くの場合親要素の内容辺
- 仕様を読む上で重要
<style> .foo { background: #ffaa66 url("/images/bg.png"); color: #ffffff; } #x li { border: 2px solid #f0e01f; } </style> ... <div id="x"> <ul class="foo bar"> <li>...</li> <li>...</li> </ul> </div>
標準技術
- 自分だけが使うなら標準化の必要はない
- 相互運用性
- アクセシビリティ
標準化団体
- IETF
- URI
- HTTP
- W3C
- HTML
- ISO
- Ecma International
- ECMAScript (JavaScript)
標準化への参加
- メーリングリスト
- IRC
- バグ追跡ツール
まとめ
- 標準技術重要
- 誰もが情報にアクセスでき、操作できるようにするため
- インターフェース重要
- 誰が使うのかをよく考えて
課題 1
- ToDo 管理ツールの出力する HTML を妥当な HTML5 にせよ
- 採点基準 (3 点)
- 構文的に妥当な HTML か (2.0)
- 適切なマークアップか (1.0)
課題 2
- ToDo 管理ツールで ToDo の追加・編集を画面遷移なしで行えるようにせよ
- どんなユーザーが使用するのかを想定すること
- 採点基準 (4 点)
- 動作するか (1.5)
- 想定ユーザーにとって適切な UI か (1.5)
- プログラムの設計 (1.0)
課題 3
- HTML5 及び関連 API を用いて ToDo 管理ツールを拡張せよ
- 例: オフラインでも利用可能にする (Web Storage、オフラインイベント)
- 例: 期限を基に ToDo を図示する (
canvas
要素)
- 採点基準 (3 点)
- 動作するか (1.0)
- プログラムの設計 (1.0)
- その他感ずるところ (1.0)
ヒント: イベント、ちょっと詳しく
- イベントバブリング
- イベントは実際に発生したノードから親に向かって浮上 (バブル) していく
- バブルしないイベントもある (
submit
、focus
、load
、etc.) event.stopPropagation()
で浮上を停止
Document Object Model (DOM) Level 3 Events Specification
<ol id="list"> <li>最初の項目</li> <li>第二の項目</li> </ol> <script> var list = document.getElementById('list'); list.addEventListener('click', function (event) { if (event.target.nodeName.toLowerCase() !== 'li') return; event.target.textContent += ' [checked]'; }, false); </script>
- デフォルトアクション
- イベントに関連づいた挙動
- リンクの
click
イベントならリンク先への移動
- リンクの
event.preventDefault()
でデフォルトアクションを中止- 中止できないイベントもある (
focus
、load
、etc.)
- 中止できないイベントもある (
- イベントに関連づいた挙動
<a href="...">def...</a> <script> a.addEventListener('click', function (event) { ... event.preventDefault(); event.stopPropagation(); }, false); </script>
おまけ: Firebug でのデバッグ
- スクリプトパネルからブレークポイントを設定
- ステップイン
- 1 行実行
- 関数呼び出し時は呼び出された関数の最初の行に移動
- ステップオーバー
- 1 行実行
- 関数呼び出し時も現在の関数の次の行へ移動
- ステップアウト
- 現在の関数の最後まで実行
参考文献
- 講義「ヒューマンインタフェース」石田亨
- 『Webを支える技術 -HTTP、URI、HTML、そしてREST』山本陽平 (技術評論社)