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

2022-06-16
nanto_vi (株式会社はてな)
Web開発者によるフィードバック

- 標準準拠
- 相互運用性の向上
➜ より開発しやすく
ブラウザベンダが不具合に気づくことを期待するという受身の立場から、積極的に熱心でいる(自らバグを報告する)ことへの移行は、信じられないほど多くの力をあなたにもたらします。
[発話] ソフトウェアを作るうえでも使う上でもフィードバックは重要ですね。Webブラウザの場合、Web開発者からのフィードバックによって標準準拠の度合いが進んだり、ブラウザ間の相互運用性が向上したりして、Web開発者にとってはより開発しやすくなります。John Resigさん——jQueryを作った方です——も、バグが直るのを待つのではなく自らバグを報告するとめっちゃええことあるというようなことをおっしゃっています。
個人開発者によるIEへのフィードバック手段

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

開発者の支持のないブラウザは廃れるとの思いで、標準準拠路線を進めてきた
- 筆者もフィードバックに参加
- 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には当時の記事が多数残っており、調査の大きな助けとなりました。
- Internet Explorer Product Downloads (Internet Explorer 6 Public Preview)
- Please send us your feedback on the IE7 Beta 2 Preview | Microsoft Docs
- Announcing Internet Explorer Feedback | Microsoft Docs
- Feedback and Support for IE7 Beta 2 | Microsoft Docs
- Microsoft Internet Explorer 7: サポート
- IE7 Feedback and Support | Microsoft Docs
- IE8 Beta Feedback | Microsoft Docs
- RE: IE8 Beta Feedback | Microsoft Docs
- Internet Explorer 8 ベータ フィードバック について
- IE8 β版でのもっと積極的なフィードバック: 世の中は不思議なことだらけ
- 第 13 回 Admintech.jp 勉強会: Days on the Moon
- IE8の次、「Internet Explorer 9」に搭載して欲しい機能をマイクロソフトが募集中 - GIGAZINE
- IE9 Platform Preview Feedback | Microsoft Docs
- IE9 Platform Preview へのフィードバック | Hebikuzure's Tech Memo
- How IE9 Platform Preview Feedback Changed the JavaScript Standard | Microsoft Docs
- Internet Explorer 9 Beta で気になる現象を見つけたら: 世の中は不思議なことだらけ
TypeScript の可変長タプル型における共用体の分配 ― 2022年06月09日 01時29分
TypeScript の可変長タプル型 (variadic tuple types) とは、配列型やタプル型を展開して別のタプル型の一部として使える機能のことです (「TypeScript 4.0で導入されるVariadic Tuple Typesをさっそく使いこなす - Qiita」に詳しいです)。記法としては、展開する型の直前に三連続のドット ...
を記述します。例えば、
type Sandwich<Fillings extends unknown[]> = ['bread', ...Fillings, 'bread'];
のように具材 (filling) をパン (bread) で挟む Sandwich
型があったとき、Sandwich<['ham']>
型は ['bread', 'ham', 'bread']
型に展開されます。
type HamSandwich = Sandwich<['ham']>;
// → ['bread', 'ham', 'bread']
type BLTSandwich = Sandwich<['bacon', 'lettuce', 'tomato']>;
// → ['bread', 'bacon', 'lettuce', 'tomato', 'bread']
type RichHamSandwich = Sandwich<'ham'[]>;
// → ['bread', ...'ham'[], 'bread']
type TwoSlicesOfBread = Sandwich<[]>;
// → ['bread', 'bread']
ここで型引数 Fillings
に共用体型 (縦線 |
で区切った複数の型のうちのいずれかを表す型) を渡すとどうなるでしょうか。具材がハムか卵なら、できあがるのはハムサンドか卵サンドになります。つまり、Sandwich<['ham'] | ['egg']>
型は Sandwich<['ham']> | Sandwich<['egg']>
型と同等に扱われます。
type HamOrEggSandwich = Sandwich<['ham'] | ['egg']>;
// → ['bread', 'ham', 'bread'] | ['bread', 'egg', 'bread']
このように、T<A | B | C | (略)>
型が T<A> | T<B> | T<C> | (略)
型として扱われる挙動を「共用体の分配 (union distribution)」と呼びます。
共用体の分配は条件型 P extends Q ? R : S
でも発生しますが (「TypeScriptの型初級 - Qiita」に詳しいです)、可変長タプル型でも発生するのです。
条件型における共用体の分配では、never
型を分配しようとすると展開結果も never
型になります。これは可変長タプル型においても同じです。
type ImpossibleSandwich = Sandwich<never>
// → never
なお、可変長タプル型において any
型は any[]
型に展開されます。unknown
型を展開することはできません。
type AnySandwich = Sandwich<any>;
// → ['bread', ...any[], 'bread']
type UnknownSandwich = Sandwich<unknown>;
// → Error: Type 'unknown' does not satisfy the constraint 'unknown[]'.
可変長タプル型で共用体の分配が発生するというのは、可変長タプル型を導入した pull request の説明に書かれています。私はこの挙動を、type-challenges の回答のひとつをきっかけに知りました (その回答は誤答なのですが)。
- When the type argument for
T
is a union type, the union is spread over the tuple type. For example, [A, ...T, B]
instantiated with X | Y | Z
as the type argument for T
yields a union of instantiations of [A, ...T, B]
with X
, Y
and Z
as the type argument for T
respectively.
Variadic tuple types by ahejlsberg · Pull Request #39094 · microsoft/TypeScript
HTML のフォームコントロール要素と label 要素の紐づけ ― 2021年12月24日 21時11分
この記事は HTML アドベントカレンダーの 24 日目の分、兼 JavaScript アドベントカレンダーの 24 日目の分です。
HTML のフォームコントロール要素 (input
、textarea
、select
、button
要素など) には、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 引数に select
、start
、end
、preserve
のいずれかの値を指定することで変更できます (省略時は 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
を開いてみてください。あら、テストが失敗してしまいました!
気を取り直して次の Document.getElementsByTagName-foreign-01.html
を開いてみると……今度は成功しています! JavaScript から document.getElementsByTagName
メソッドを呼び出して SVG の要素を取得できることを確かめられました。
ブラウザによっては失敗したテストをバグトラッキングシステムで管理しています。先ほど失敗した 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 プラットフォームを進化させていきませんか!
最近のコメント