スキップしてメイン コンテンツに移動

エイプリルフール企画などでレガシーブラウザ対応する場合に覚えておきたい最初期のDHTMLブラウザのJavaScriptの罠たちを回避する

執筆時点で未解決だった、Gecko 0.8.0以下での括弧の下の関数の問題es2-postprocessor 0.12.0で解決しています。(2023/01/04 追記)

この記事は、JavaScript Advent Calendar 2022の3日目です。2日目の記事は martinheidegger さんによる「JavaScript を使って DNS データ受け取る。」になります。

  1. はじめに
  2. IE5 以下に未実装のビルトインオブジェクトとメソッドを補う
  3. Opera 7.23以下はラベル付きブロックで構文エラー
    1. ラベル付きブロックを do~while または即時実行関数に書き換える
  4. 優等生の Gecko 0.8.0以下のややこしめのバグ
    1. 即時実行関数が絡むバグ
  5. さいごに
    1. 注釈
    2. ご参考リンク

1. はじめに

2016年のエイプリルフール企画の『英雄伝説 空の軌跡 the 3rd Evolution』公式サイト(アーカイブより)

本記事を一般化して書くと、エイプリルフール企画で0年代前半風の Web サイトを制作する案件が来て「見た目はバイブスでてますけど、コレ、当時のブラウザで動くんスか?」と恐ろしい方向に話が進んだ際に、気配をフェードアウトする暇でこの記事のことを思い出してください。

当時のブラウザを取り出して閲覧してくれるユーザーの手元でバッチリ動いてくれたなら、ハートキャッチですね。

因みに『空の軌跡』のエイプリルフール企画については、Internet Exproler 3.0や Netscape Navigator 3.0で閲覧した報告のツイートを目にした記憶があるので、油断なりません。(*1)


さて、0年代前年は DHTML ブラウザが出揃い、後の Ajax(2005年~)の開花を準備します。

Microsoft が IE4 に向けて書いた文書によると DHTML はダイナミックコンテンツ、ダイナミックスタイル、CSS-P などがその構成技術です。これらに加えて、要素とテキストレンジの計測が正常に実装されているなら、理論上は、新しい CSS の実装を待たずともどんなレイアウトでも可能です。つまり DHTML さえ健全ならどんな表現でも可能なわけです。(*2)

そんな素晴らしい能力を秘めたレガシー DHTML ブラウザですが、いざそれらに向けて開発を始めると、不可解なバグと貧弱な開発者ツールに泣くことになります。エラーコンソールがあれば御の字という世界へようこそ。

本記事では未実装とバグの中から印象的なものを3つご紹介します。どれも JavaScript を書き換えるポストプロセッサーを用意してエレガントめに迂回できた問題たちです。

2. IE5 以下に未実装のビルトインオブジェクトとメソッドを補う

IE5 で執筆中の本記事を表示してみる

最初期の DHTML ブラウザ向け開発を始めたらまず入手したいのが、IE5(1999年3月18日)からサポートする jQuery クローン「kQuery」を開発していた ofk 氏による polyfill 集です。ECMAScript 3未満の IE 4~5 を ES3 のちょい手前くらいまで引き上げる事ができます。

僕の手でいくつかのバグを修正し、他の足りない組み込みオブジェクトとメソッドの polyfill を加えた es2-to-es3 を公開しています。自動で polyfill を埋め込む gulp プラグインにもしていて npm からインストール出来ます。

3. Opera 7.23以下はラベル付きブロックで構文エラー

Opera 7.03のラベル付きブロック非サポートを確認する(テストページになります。)

Opera 7.23(7.20は2003年9月23日に公開)以下は、ラベル付きブロックを非サポートで、7.50(2004年5月12日)以降でサポートします。

JavaScript でラベル付きブロックを使うコーディングは寡聞にしてあまり見かけないようですが、僕のケースでは Closure Compiler で ADVANCED コンパイルをすると遭遇しました。「ラベル付きブロックさえなければ動くのに…!」という状況は結構口惜しいですね。

そんなラベル付きブロックを書き換えるツール es2-postprocessor を公開しているのでもう大丈夫です。

3.1. ラベル付きブロックを do~while または即時実行関数に書き換える

こんな感じに書き換えます。

a: {
  break a;
}
// ↓
do{
  break; // <= break a;
} while(false);

// ---------

a: {
  b: {
    break b;
    break a;
  }
  break a;
}
// ↓
(function(){
  do{
    break; // <= break b;
    return; // <= break a;
  } while(false);
  return; // <= break a;
})();
UI のゴテゴテ感の新鮮な Opera 7.54で表示してみる、Google Code Prettifyの改造版も動作

この書き換えを自動で、あらゆるパターンで漏れなく実施することは、僕の手にはあまりました。そこで、エラーを投げて書き換えを諦める場合があります。但し、僕の使用状況では Closure Compiler の出力するラベル付きブロックは簡素な為、書き替えできなかったことは今のところありません。

それにしても、Opera 7.xは可愛くて良いです。7.0(2003年1月28日)は若干遅めの登場にしては実装状況がやや遅れ気味な気がしますが、可愛いので良しです。

4. 優等生の Gecko 0.8.0以下のややこしめのバグ

Mozilla ブラウザ(Gecko 0.7)で表示してみる。0.6ではロードが完了しなかった。Google Photoの画像のせいかも。

Netscape Navigator 6(Gecko 0.6)は2000年の11月14日にリリースされたブラウザで IE 5.5(2000年7月17日公開)が同期です。この時点で Object.prototype.__defineGetter__, Object.prototype.__defineSetter__ を実装していて頼もしいです。一方の CSS とペイント周りでは、問題がやや多めに感じます。

今回紹介するのは Gecko ~0.8.0で遭遇する JavaScript 実装のバグです。0.8.1では解決したことを確認しました。何年か前に初めて遭遇した時は、訳が分からず頭が白くなりましたが、この11月に条件を特定して解決するところまで漕ぎつけました。(執筆中に発生条件が即時実行関数に留まらないことが判明しました。これへの対処は後日にします。es2-postprocessor 0.12.0 以降で解決しています。2024/01/04 追記)

4.1. 即時実行関数が絡むバグ

Gecko 0.6での IIFE のテスト結果(テストページ)

先祖スコープのオブジェクトを参照すると常に undefined になっているバグです。但し、グローバルオブジェクト(window のプロパティ)では問題が起きません。即時実行関数などの括弧で囲まれた無名関数の中からの参照でだけ発生します。そして、これらの関数と同じスコープに関数定義が存在する場合は発生しません。

と、文章にするとややこしいですね。テストページでご確認いただけます。

この問題も es2-postprocessor に、次のように即時実行関数と括弧で囲まれた(無名)関数を関数定義に書き換えて回避するコードを追加して対処しました。

function parentScope(){
  var a = {};
  (function(){
    alert(typeof a); // "undefined"
  })();
};

// ↓

function parentScope(){
  var a = {};
  function b(){
    alert(typeof a); // "object"
  };
  b();
  b = false;
};

5. さいごに

これで0年代風の見た目に留まらず、対応ブラウザも0年代の Web 開発をする下準備が出来ました。

さて、現在では Visual Studio Code などの優れたツールを使って Web 開発が行えます。現代のツールと知見を駆使してチューニングされた Web コンテンツをレガシーブラウザに読み込ませたら、当時には引き出せなかったパワーを引き出すことが出来るかもしれませんね!(*3)


「この Canvas ゲームですけど、Java アプレットってので出来るんじゃないっスか?」

「… … 、、、」

(function(){
  obj.filters.alpha.opacity -= 5;
  0 < obj.filters.alpha.opacity && setTimeout(arguments.callee, 50);
})();

5.1. 注釈

  1. 本記事執筆中に Netscape 3.04でアーカイブの企画サイトを表示してみた
    本記事執筆中に Netscape 4.8でアーカイブの企画サイトを表示してみた

    Netscape 4.xまでは日本語 UTF-8 に非対応のようです。公開サーバ側で Shift-JIS などで HTML を返す必要があると思います。そして、仮にこのような実装がされていても Web アーカイブには記録されません。

  2. やっぱり、CanvasWebAudioGamePad APIService WorkerIndexedDB は欲しいです。
  3. という事象は確認していません。特に Opera 7.xの DHTML は、激しくモッサリです。

5.2. ご参考リンク

  1. 令和にも残そう、懐かしい90年代WEBデザイン。さよなら平成。
  2. レトロブームが、どのようにwebデザインに取り入れられているか「ニュートロ(Newtro)」とは「現在or未来(New)」と「過去(Retro)」を融合させた「新しい過去」を意味する韓国で生まれた新造語です。
  3. 懐かしのインターネット。AppleにGoogle、Amazonなど1999年のサイトデザインはこんな感じだった。 90年代は、ウェブのグラフィックデザインの可能性が模索された時代でした。当時、ウェブデザイナーの大多数は印刷物のデザインしか手がけたことがありませんでした。だからウェブサイトをどのようにデザインするのか、その方法が試行錯誤されていたのです。