私とIEとフィードバック(IE卒業式)2022年06月19日 12時28分

2022年6月16日に開催された「IE卒業式」というイベントで、「私とIEとフィードバック」という発表(5分間のライトニングトーク)をしてきました。以下に話した内容を掲載します。


私とIEとフィードバック

2022-06-16

nanto_vi (株式会社はてな)

Web開発者によるフィードバック

  • 標準準拠
  • 相互運用性の向上

➜ より開発しやすく

ブラウザベンダが不具合に気づくことを期待するという受身の立場から、積極的に熱心でいる(自らバグを報告する)ことへの移行は、信じられないほど多くの力をあなたにもたらします。

John Resig

[発話] ソフトウェアを作るうえでも使う上でもフィードバックは重要ですね。Webブラウザの場合、Web開発者からのフィードバックによって標準準拠の度合いが進んだり、ブラウザ間の相互運用性が向上したりして、Web開発者にとってはより開発しやすくなります。John Resigさん——jQueryを作った方です——も、バグが直るのを待つのではなく自らバグを報告するとめっちゃええことあるというようなことをおっしゃっています。

個人開発者によるIEへのフィードバック手段

go to http://131.107.85.110/msdn/bugreports/ to report issues

Internet Explorer 5.5 Preview

[発話] 個人がIEにフィードバックする手段は、IE 7の前後で大きく変わっています。IE 7以前はニュースグループ——掲示板やメーリングリストのようなものです——が中心でした。IE 7以降はMicrosoft Connectというサービスを使うようになっています。Microsoft Connectにはバグトラッキングシステムが備わっており、他人の登録したバグを検索したり、自分の登録したバグの状態を知れたりと、バグ報告者からすると使いやすくなっています。ちなみに、IE 5.5 Previewのときにはバグ報告用のURLがIPアドレス丸出しで、のどかな時代だったんだなというのを感じさせます。

IE 8 Betaへのフィードバック

開発者の支持のないブラウザは廃れるとの思いで、標準準拠路線を進めてきた

「ここが変わった! IE8 Beta2」(第13回 Admintech.jp勉強会)

  • 筆者もフィードバックに参加
    • Web Storageがオリジンごとではなくドメインごと
    • Web Storageのイベントが同期的
    • 文書間メッセージング(postMessage)のイベントが同期的

[発話] 私がIEにフィードバックするようになったのはIE 8 Betaが出たあたりからです。このころはFirefoxとSafariがIEを追い上げ、GoogleがChromeを発表し、Microsoftとしては非常に危機感を持っていたのではないかと思います。実際に、当時あったイベントでMicrosoftの方が、開発者の支持のないブラウザは廃れるとの思いで標準準拠路線を進めてきたというようなことをおっしゃっていました。このころはWeb Storage APIや文書間メッセージングが新機能としてもてはやされ、私も標準仕様とIEの実装との差異をいくつか報告しています。Web Storage API——localStorageなど——の範囲がオリジンではなくドメインである、すなわちhttpsのページで書き込んだデータをhttpのページで読み込めるというったことがありました。

フィードバックの返礼品

  • IE 8の工具セット
  • FirefoxとThunderbirdの傘

[発話] そうしたバグ報告をしているとMicrosoftからメールが来て、グッズを送るから住所を登録してくれと言われました。何かしらと思って住所を入力すると後日IE 8の工具セットが届きました。これでIEを直せということでしょうかね。こうしたノベルティの贈呈はMicrosoft以外のブラウザベンダもやっており、MozillaからはFirefoxとThunderbirdの傘をもらったことがあります。

フィードバックしよう!

[発話] 皆さんもどんどんフィードバックしていきましょう。個別のブラウザにフィードバックする以外にも、ブラウザ間の相互運用性を高めるためにweb-platform-testsというものがあります。web-platform-testsにコミットすると各ブラウザで実行され、場合によってはブラウザ側で挙動が変更されることもあります。フィードバックを通じてWebの将来を作っていきましょう。ありがとうございました。


以上が発表内容です。久々の発表、しかもリモートからの参加ということで緊張しましたが、無事終えられてよかったです。

イベント自体は懐かしい機能を思い出したりIEの功績を振り返ったりと、IEの存在感の大きさを改めて感じられるものでした。イベントを企画・運営してくださった方々に感謝します。(IEのケーキが思ったより大きくて、現地で食べてみたかったです。)

IE 6も登場した時点ではそこまで悪いものではなく(個人的にはまだCSS 2ではなくCSS 1なのかと思いましたが……)、開発者の落胆を招いた要因としては、その後5年もメジャーバージョンアップがなかったという部分も大きいかと思います。

発表するにあたって、発表内容で触れた以外にも以下のページを参考にしました。また、窓の杜およびInternet Archiveには当時の記事が多数残っており、調査の大きな助けとなりました。

HTML のフォームコントロール要素と label 要素の紐づけ2021年12月24日 21時11分

この記事は HTML アドベントカレンダーの 24 日目の分、兼 JavaScript アドベントカレンダーの 24 日目の分です。


HTML のフォームコントロール要素 (inputtextareaselectbutton 要素など) には、label 要素を使ってラベルを指定できます。ここでいうラベルとは、そのフォームコントロールに何を入力するか・そのフォームコントロールで何ができるのかの簡単な説明であり、人間が読んで理解できるようなフォームコントロールの名前です。

ある label 要素の子孫にフォームコントロール要素が存在すれば、その label 要素の内容が、そのフォームコントロール要素のラベルとなります。そうでない場合、label 要素の for 属性にフォームコントロール要素の ID (id 属性の値) を指定する必要があり、その label 要素の内容が、その ID を持つフォームコントロール要素のラベルとなります。

このフォームコントロール要素と label 要素との紐づきは JavaScript を使って参照できます。フォームコントロール要素オブジェクトの labels プロパティはそのフォームコントロール要素と紐づく label 要素の一覧 (NodeList オブジェクト) を返し、label 要素オブジェクト (HTMLLabelElement オブジェクト) の control プロパティはその label 要素に紐づくフォームコントロール要素を返します。

labels プロパティの名前が複数形なのは、ひとつのフォームコントロール要素に対して複数の label 要素を紐づけられるからですね。

<label id="query-label-1" for="query-field">キーワード</label>
<label id="query-label-2" for="query-field">URL</label>
<input id="query-field" type="search" name="q">
const label1 = document.getElementById('query-label-1');
const label2 = document.getElementById('query-label-2');
const field = document.getElementById('query-field');

console.assert(label1.control === field, 'control プロパティでフォームコントロールを参照できる (1)');
console.assert(label2.control === field, 'control プロパティでフォームコントロールを参照できる (2)');
console.assert(field.labels[0] === label1, 'labels プロパティで label 要素を参照できる (1)');
console.assert(field.labels[1] === label2, 'labels プロパティで label 要素を参照できる (2)');

あるフォームコントロールにおいて、labels プロパティの返す NodeList オブジェクトは常に同一です。紐づく label 要素に変更があれば、その NodeList オブジェクトの内容が動的に変化します。

const oldLabels = field.labels;
label1.remove();
const newLabels = field.labels;

console.assert(oldLabels === newLabels, 'labels プロパティの値は何度参照しても同一のオブジェクトである');
console.assert(oldLabels.length === 1, 'labels プロパティの値は動的に変化する');

ただし、実際のところひとつのフォームコントロール要素に複数の label 要素を紐づけるような場面はほとんどないと思います。

button 要素にも label 要素を紐づけられます。しかしながら、button 要素の場合は自身の内容がラベルとして扱われるので (<button type="submit">検索する</button> なら「検索する」がそのボタンのラベルになります)、実際のところ button 要素に label 要素を紐づけるような場面はほとんどないと思います。

ラベルは aria-label 属性aria-labelledby 属性を使って指定することもできます。

<form action="/search">
  <p>
    <input type="search" name="q" aria-label="キーワード">
    <button type="submit" aria-label="検索する">🔍</button>
  </p>
</form>

HTML のテキスト入力欄の入力値の一部を置換する2021年12月23日 23時48分

この記事は HTML アドベントカレンダーの 23 日目の分、兼 JavaScript アドベントカレンダーの 23 日目の分です。


HTML のテキスト入力欄 (<input type="text"> 要素や textarea 要素など) で選択範囲の文字列を置換したいとき、一昔前は JavaScript で以下のように書く必要がありました。

// 引数 field には HTMLInputElement オブジェクトまたは HTMLTextAreaElement オブジェクトを、
// 引数 newText には文字列を、それぞれ受け取る。
function replaceSelectionText(field, newText) {
  var start = field.selectionStart;
  var end = field.selectionEnd;
  var text = field.value;
  field.value = text.substring(0, start) + newText + text.substring(end);
  field.setSelectionRange(start, start + newText.length);
}

(さらに大昔は IE 向けに TextRange オブジェクトを使う必要がありました。)

今は HTML 標準で setRangeText メソッドが定義されているため、以下のように書けます。

function replaceSelectionText(field, newText) {
  field.setRangeText(newText);
}

setRangeText メソッドには置換する範囲を指定することもできます。テキスト入力欄 field の入力値が abcde のとき、以下のコードを実行すると入力値が axde になります。

field.setRangeText('x', 1, 3);

このとき、元の入力値において改行は \n に正規化され、1 文字として数えられます。また、「1 文字」というのが Unicode の符号位置ではなく UTF-16 の符号単位を表すことに注意が必要です。

置換する範囲を指定して setRangeText メソッドを呼び出したとき、選択範囲はメソッド呼び出しの前後であまり変化しないように調整されます。この挙動は、第 4 引数に selectstartendpreserve のいずれかの値を指定することで変更できます (省略時は preserve)。以下の例ではメソッド呼び出し後に部分文字列 x が選択されます。

field.setRangeText('x', 1, 3, 'select');

Web Platform Tests での HTML 標準のテストに触れる2021年12月22日 23時50分

この記事は HTML アドベントカレンダーの 22 日目の分、兼 JavaScript アドベントカレンダーの 22 日目の分です。


Web Platform Tests をご存じでしょうか。Web ブラウザ間の相互運用性を高めるための、様々な Web 標準技術に関するテストスイートです。主要 Web ブラウザは Web Platform Tests を開発プロセスに取り込み、互換性の向上やリグレッションの防止を図っています。

Web Platform Tests はあなたが今閲覧に使っているブラウザで実行できます。試しに HTML 標準に関するテストを実行してみましょう。https://wpt.live/ からディレクトリをたどって https://wpt.live/html/syntax/parsing/ に行くと、数多くのテストファイルが並んでいます。

ファイルリストの先頭にある DOMContentLoaded-defer.html を開いてみてください。あら、テストが失敗してしまいました!

DOMContentLoaded-defer.html を開くと 1 Fail と表示されます。

気を取り直して次の Document.getElementsByTagName-foreign-01.html を開いてみると……今度は成功しています! JavaScript から document.getElementsByTagName メソッドを呼び出して SVG の要素を取得できることを確かめられました。

Document.getElementsByTagName-foreign-01.html を開くと 37 Pass と表示されます。

ブラウザによっては失敗したテストをバグトラッキングシステムで管理しています。先ほど失敗した DOMContentLoaded-defer というファイル名を Mozilla Bugzilla (Firefox のバグ管理にも使われています) で検索してみると、1242128 - Frequent Win8 TEST-UNEXPECTED-PASS | /html/syntax/parsing/DOMContentLoaded-defer.html | The end: DOMContentLoaded and defer scripts - expected FAIL が出てきました。

議論の場はそこから DOMContentLoaded-defer.html is likely wrong · Issue #4267 · web-platform-tests/wpt に移っています。どうもこれはテストのほうがおかしいのではないかという話が出ていますね。

Web Platfrom Tests は絶対的なものではなく、日々追加・変更されています。開発は GitHub で開かれており、開発への貢献は各 Web ブラウザの品質向上につながります。筆者もかつて縦書きの文書におけるスクロール位置に関するテストを追加したところ、それに関する Chrome の挙動が修正されました

あなたも Web Platform Tests に参加して Web プラットフォームを進化させていきませんか!

HTML のフォームでアップロードしてほしいファイル種別を指定する2021年12月21日 23時14分

この記事は HTML アドベントカレンダーの 21 日目の分です。


HTML のフォームでファイルを送信するには、ファイルアップロードコントロール <input type="file"> を使います。このとき、accept 属性に MIME タイプまたは拡張子を指定することで、アップロードしてほしいファイルの種別を指定できます。PNG 画像または JPEG 画像をアップロードしてほしければ、以下のようにカンマ区切りで記述します。

<input type="file" accept="image/png, image/jpeg, .png, .jpg, .jpeg">

特殊な値として以下の三つが定義されています。これらの値も他の値と組み合わせて指定できます。

image/*
何らかの画像ファイルをアップロードしてほしいときに指定する。
video/*
何らかの動画ファイルをアップロードしてほしいときに指定する。
audio/*
何らかの音声ファイルをアップロードしてほしいときに指定する。

個別のファイル種別を指定するときは、MIME タイプと拡張子を両方組み合わせて指定することが勧められています。MIME タイプまたは拡張子、どちらかのみでファイル種別を管理しているシステムへの配慮からでしょうか。

MIME タイプにパラメータは指定できません。UTF-8 で符号化された HTML 文書のみアップロードしてほしいからといって、accept="text/html; charset=UTF-8" とは書けないのです。

accept 属性で指定できるのはあくまでもファイル名などに基づく表面的なファイル種別であり、Web ブラウザがファイルフォーマットをきちんと検証してくれるわけではありません。サーバー側でのファイルフォーマット検証を忘れないようにしましょう。

<input type="file"> にはほかにも、複数ファイル選択を可能にする multiple 属性や、デバイスのメディアキャプチャ機能を直接利用可能にする capture 属性を指定できます。capture 属性に関しては「captureでカメラ起動(知名度が低いウェブ標準ひとりAdvent Calendar 2021 – 17日目) | Ginpen.com」で紹介されているのでそちらも参照してください。なお、capture 属性はまだ HTML 標準に取り込まれていませんが、HTML Media Capture として W3C 勧告になっています。