print メディアへの暫定対応

昔々に対応したものの、その後のアップデートでいつの間にか意味消失していた print メディア専用スタイルを復元させた。しかしあくまでも暫定。かなり適当。またぼちぼち改良しようと思っている。

明日は COMIC1 か……。友人に誘われたし、とりあえず行くとしましょうか。

2008-04-26

YUI Compressor は IE の条件付きコンパイルを /**/ 形式しかサポートしない

Rhino を利用した高い圧縮性能を誇る YUI Compressor。これ、何気に IE の条件付きコンパイルをサポートしており、きちんと判定してコード中に残してくれる。しかし、完全にはサポートしていないようだ。コメントが複数行形式 /**/ の場合のみのサポートだからである(2.3.5 で確認)。

実のところ、条件付きコンパイルは1行形式のコメント // でも書くことができる。次のコード断片は、同一の条件付きコンパイルを /**/// の両形式で記述した例である。

/* 複数行形式の場合 */
/*@cc_on @if (@_jscript) var ie = true; @else @*/
var ie = false;
/*@end @*/

// 1行形式の場合
//@cc_on @if (@_jscript) var ie = true; @else
var ie = false;
//@end

YUI Compressor は、1行形式のコメントを無視して削除対象にしてしまう。よって、YUI Compressor で圧縮しようとしているコードに条件付きコメントが含まれる場合は、必ず複数行形式のコメントで記述しなければならない。削除されてしまっては元も子もないからだ。

そもそも条件付きコメントは JScript の独自仕様であり、はっきり言って嫌らしいことこの上ない。できれば使いたくなどないが、使った方が労力とコードが省ける場合というのも往々にして存在する。絶対に積極的な利用をするべきではないが、必要悪として最低限利用する分には問題も少なくなるだろう。

そういえば、JScript Blog にガベージコレクタの記事が出てるな……。読んでおこう。

2008-04-24

XPath も線形探索も querySelectorAll も、getElementsByClassName の完全なる代替にはなりえない?

Selectors API 仕様の最新 Editor's Draft を読み返していて「あーそうか」と改めて思ったのは、getElementsByClassName が返す NodeList オブジェクトと querySelectorAll の返す NodeList オブジェクトが似て非なるものだということ[1]だった。前者は動的に内容が変化するが、後者は静的である。ここで、少しばかり先日のネタの結論を修正。

ここで、「他の方法」とは XPath による方法と線形探索による方法のことである。

さて、現時点での Selectors API 最新 Editor's Draft には次のような記述がある(強調筆者)。

The NodeList object returned by the querySelectorAll() methods must be static, not live. ([DOM3Core], section 1.1.1) Subsequent changes to the structure of the underlying document must not be reflected in the NodeList object. This means that the object will instead contain a list of matching Element nodes that were in the document at the time the list was created.

Selectors API

要は DOM Level 3 Core で定義されている NodeList とは微妙に違い、「静的でなければならない(= live でない)」らしい。

DOM Level 3 Core には「live」の定義と NodeList の説明がある。

The DOM also specifies a NodeList interface to handle ordered lists of Nodes, such as the children of a Node, or the elements returned by the Element.getElementsByTagNameNS(namespaceURI, localName) method, and also a NamedNodeMap interface to handle unordered sets of nodes referenced by their name attribute, such as the attributes of an Element. NodeList and NamedNodeMap objects in the DOM are live; that is, changes to the underlying document structure are reflected in all relevant NodeList and NamedNodeMap objects. For example, if a DOM user gets a NodeList object containing the children of an Element, then subsequently adds more children to that element (or removes children, or modifies them), those changes are automatically reflected in the NodeList, without further action on the user's part. Likewise, changes to a Node in the tree are reflected in all references to that Node in NodeList and NamedNodeMap objects.

Document Object Model Core

つまり、文書に対して何らかの操作が成されてノードが増減した場合、NodeList のアイテムは動的に変化する。念のため HTML 5 仕様から getElementsByClassNameNodeList に関する記述を引いてみよう(強調筆者)。

The getElementsByClassName(classNames) method takes a string that contains an unordered set of unique space-separated tokens representing classes. When called, the method must return a live NodeList object containing all the elements in the document that have all the classes specified in that argument, having obtained the classes by splitting a string on spaces. If there are no tokens specified in the argument, then the method must return an empty NodeList.

HTML 5

getElementsByClassName は、通常の live な NodeList オブジェクトを返さなければならない。

ところが、である。XPath による方法、線形探索による方法、そして querySelectorAll による方法は、全て「live でない」何らかの Array ないし NodeList オブジェクトを返してしまう。XPath と線形探索は、その性質上どうしても Array オブジェクトを返さざるを得ないし、querySelectorAll は前述の通り「live でない」NodeList オブジェクトを返す。

結果的に、どの代替手段でも完全な getElementsByClassName は実装できないのである。

とはいえ、この仕様の相違にさえ目を瞑れば、XPath、線形探索、そして querySelectorAll は十分に代替品として利用できる。動的に要素を増減させることが多い昨今の JavaScript 事情を考えれば、どこかで矛盾は出てくるし、現に出ているだろうが、何より大事なのは代替品が最低限必要な機能を持っているか否かである。

うーむ……。この絶妙な差異、どう考えても潜在的なバグの温床のような気がしてならない。どちらが悪い、というのではなくて、この差異をプログラマの側が意識していないと何か厄介なことが起きる可能性があるという話だ。得てしてそういうバグほど、デバッグしにくいのである。

でもこの話、どこかで誰かが既にしてるかもしれない。そうすると、私はある意味で車輪の再発明みたいなことをしているわけだが……気がつけたからいいや。

何だか色々心配になってきたな。自分が書いたコード、あとで見直してみよう。

脚註

  1. この話は、つい最近ある人から教えてもらったこと。気がついたのは私ではない。

2008-04-22

CSS ファイルとディレクトリ構造の大整理

前々から気になっていた点をいくつか修正。詳細は Updatelog に記述した。おおまかに言えば「CSS ファイル数の削減」と「ディレクトリ名の変更」を行った。

「CSS ファイル数の削減」は、前々からやろうとしていたことの1つ。以前は用途毎に分割して style.css をヘッダファイル代わりに利用、インポートしていた。だが容量も大してない上に IE6 や IE7 用の CSS 群とミラーリングさせる時、どうしてもファイル数が多いと手間ばかりかかって仕方がない。構成も煩雑になり、必要な HTTP コネクションも多くなる。非常に微々たる問題としてファイル容量の増加もあるが、それはまあどうでもいい(微小すぎるため)。ともかく、現時点では利点より欠点の方が目立つ形になってしまったため、最小数のファイルにまとめる形式をとるようにした。

実はこの作業途中でむかーしに作成した印刷用 CSS がいつしか無効になっていたことが判明したのだが、これの対応はまた後々。今回、デザインそのものの対応は小さな変更をひとつだけ行うにとどめた。

「ディレクトリ名の変更」は、img ディレクトリを media ディレクトリにリネームしただけ。これは全置換用の正規表現を書く時間だけでおしまい。

マークアップはまだいいとして、スタイルはかなりガタがきてるなぁ。一応メンテしている分寿命も延びてはいるが……。ぼちぼち考えるだけ考えとくか。IE8 Beta 1 のこともあるし。ここいらで、そろそろ IE6 とはオサラバしたいし。

2008-04-21

しまった休日が潰れた

18時間ぐらい寝てしまった。こんなに睡眠とったのは久々だ。おかげで何もできず、何もする気にならず、久しぶりの過睡眠でズキズキする頭を抱えるしかない。

休日なのでフィードの更新も少なめ。ヤケクソでもうひと眠りしようかしらん。

2008-04-20

IE8 向け getElementsByClassName 実装には Selectors API の querySelectorAll を使いたい

激しく久しぶりにサイトいじった……。さて、IE8 Beta 1 には getElementsByClassName が実装されていない。この有用なメソッドはしばしば JavaScript ライブラリに収録されている。「Prototype JavaScript framework」が有名な例だろう。そして、Mozilla Firefox 3 や Apple Safari 3、Opera 9.5 Beta といった最近の UA は、getElementsByClassName をネイティブサポートしていたりする。HTML5 でも定義されている。だが、Firefox 2 や Safari 2、Opera 9.2x、そして勿論 IE6、IE7、IE8 Beta 1 はネイティブでは実装していない。

結論から言ってしまえば「IE8 Beta 1 で getElementsByClassName を実装してやるには、Selectors API(特に querySelectorAll)を利用するのがベター」となる。

話を元に戻す。では、数多の JavaScript ライブラリは getElementsByClassName をどのように実装しているのか? 答えのひとつは XPath だ。document.evaluate がサポートされている UA では、@classclass 属性値の値一致)を用いて getElementsByClassName を実現している。Firefox 2、Safari 2、Opera 9.2x は document.evaluate すなわち JavaScript からの XPath 利用をサポートしている。よって、モダンブラウザと呼ばれることもある UA のほとんどでは、パフォーマンス面でネイティブ実装には叶わないものの、そこそこ高速に動作してくれる getElementsByClassName が利用できる。

では、XPath が利用できない場合――IE6 や IE7――はどうするのか? 答えは簡単で、とてもいやらしい。線形探索を利用するのである。つまり、document.getElementsByTagname("*")document.all を利用してドキュメント内にある全ての要素を取得し、先頭から末尾までひとつひとつの要素の class 属性値をチェックしていくという意味だ。これは当然ながら一番頭の悪い方法になる。

ネイティブ getElementsByClassName や XPath による実装も、内部実装は線形探索になっているかもしれない。しかし、それらはレンダリングエンジンの開発言語で書かれているだろう。C や C++ といった言語の方が、JavaScript より高速かつ少資源で動作しやすいのは明らかである。つまり、現状では ネイティブ < XPath < 線形探索 の順にパフォーマンスが悪くなる。

IE8 Beta 1 ではどうだろう。ネイティブ getElementsByClassName も XPath もサポートしていない。では線形探索しか道はないのか?

そんなことはない。ここで Selectors API、具体的には querySelectorAll メソッドの登場である。querySelectorAll の詳細な解説は W3C の仕様IT 戦記のエントリに任せるとして、以降では簡単に実装例を紹介するに留める。

次のコード断片は、Selectors API を利用した getElementsByClassName の実装例である(他方法の実装は省略)。

var FOO = {}; // 適当な疑似名前空間

FOO.getElementsByClassName = function(elem, className) {
  return elem.querySelectorAll("."+className);
};

実にシンプルだ。そして勿論、線形探索より高速に動作する。これは実際にテストしてもらった方がよいだろう。

の4種を用意した(利用できない場合は押下できない)。ボタン押下でアラートダイアログが出現し、1000 回の実行に何ミリ秒かかったかを表示する。IE8 Beta 1 では差が顕著に現れるだろう。

じきに、Selectors API を getElementsByClassName に利用したライブラリも登場するかもしれない。

脚註

  1. スクリプトは data/2008-04-19/test.js に記述した。

2008-04-19

Sage が復活!? しかしまだまだ buggy

謎つぶし文@謎経由で、Sage 1.9.1 リリースを知る。3.0 Beta 5 用なので、完全にテスタ用。人柱希望者以外は入れないほうがいいだろう。Places はそれほどまでにやりにくいということか。

Trunk Nightly の 2008040606 に入れて使ってみた。インタフェイスは同じだが、挙動の面で Firefox 2 用の Sage 1.8 系とはかなり違っている。シングルクリックで Live Bookmark は開いてしまうし、一覧も出ない。おまけに、Places 上に Sage Feeds という特殊なフォルダを作成されてしまう。酷いことに、これは削除できないのだ。現状は、まだ常用に耐えうるレベルに達していないといえる。

それでも開発が続行されていたことに拍手喝采を送りたい。今常用しているフィードリーダは Brief だが、CVS HEAD でもその挙動はまだまだ遅い。もう少し様子をみることにする。

2008-04-07

新しいノート PC が届いた

木曜日のことだったが。……買ったのは Lenovo ThinkPad X61NA75C36。同梱 OS は Windows XP。そして、今現在 Windows の基本的なカスタムは完了したので、Linux をインストールすべく準備中。ディストリビューションは今のところ Vine Linux にする予定。……主記憶と CPU が自宅のデスクトップより大容量 & 高性能ってどういうことやねん。いかん。早いとこ更なる貯蓄を決行しなければ。

Linux のインストールだが、とりあえず USB メモリを用いる方法が楽そうだ。Vine のインストールパッケージは CD-R に収納できる容量(700MB 未満)に抑えられているので、自宅にある2GB の USB メモリ(というより microSD)に簡単に入れられる。やり方は、そのものズバリ ThinkPad X シリーズ用に書かれている「Vine on X40」が参考になる。ブートローダは GRUB にしたいなー。あとで試そ。

あとは IBM 部品センター[1]に US キーボードを注文すれば完璧。勿論 42T3467 (NMB) の予定。それまでは HHK と併用して誤魔化す。もう Winodows の方はレジストリ設定変えちゃったし。いや、元に戻して再起動すればいいだけの話なんだが。

さて、これからコツコツと Vine Linux 環境を整えましょう。しばらくいじってなかったから……。shell は何にしようかなぁ。ここは Zsh にしちゃおうかしらん。いや、昔から使い慣れている Bash も捨てがたい。C Shell 系は好みじゃないから論外。ああ、GNU Emacs も CVS HEAD にしなきゃ。先月の26日に 22.2 が正式にリリースされたことだし。

脚註

  1. 電話番号は 03-5445-0365補修用部品の購入方法・部品番号一覧があったりする。まとめた方に感謝。

2008-04-06

Mozilla Firefox 3 Beta 5 & Opera 9.27 Released

Mozilla Firefox 3 Beta 5 がリリースされた。いつもの通り、開発者プレビュー版であるため一般ユーザの利用は推奨されない

次からはついに RC か……。どうなることやら。

そして、Opera 9.27 もリリースされた。日本の公式サイトでは、現時点 (22:03) で配布が始まっていない。本家からダウンロードした方が無難だろう。デフォルトで International 版(ローカライズされているバージョン)がダウンロードできる。

2008-04-03

「WebKit 開発者の一部よ、恥を知れ!」に対する指摘への返答・加筆訂正

驚いたことに、「WebKit 開発者の一部よ、恥を知れ! - Opera の非公開テストビルドと WebKit Nightly r31342 が Acid3 をクリア」は様々な人に読んでいただけたようで、その内容に対する指摘を色々と頂戴することができた。その一部は既に該当記事にも反映したが、全てを追記するには改めて書き起こす必要があると考えた。それが、今回の内容である。

因みに「WebKit 開発者の一部よ、恥を知れ!」の後、追加情報として「WebKit の Acid3 クリア用の修正 Changeset 31322 がバックアウトされる」という後日談を書いた。以降の内容は、前述した後日談の閲覧を前提として記述する。

指摘に対する検証

私が現時点で把握できている指摘は、全て「WebKit 開発者の一部よ、恥を知れ!」に対するものである。そして、その殆どは「Safari Part41」でのものだ。以後、引用を交えつつ内容を検証する。

まず、レス895 (ID:JCWAmUkB0 氏) から引用。

895 :名称未設定:2008/04/02(水) 00:51:11 ID:JCWAmUkB0
>>868
このサイトさ、Operaが100点取った!って宣言したビルドの点数が
実は99点だったってことに「まったく言及していない」のはなぜだろう。

>http://ln.hixie.ch/?start=1206578003&count=1
> This presumably means Opera is now at 99/100... the race continues!

100点取ったのはその後のビルドなんだよね。

そもそもWebKitチームから指摘されたAcid3の不具合が修正されたこと
さえきちんと書いておらず、ものすごく恣意的だと思うんだが。

Safari Part41

特に Hickson 氏の Blog エントリについては完全に見落としていた。情報提供ありがとうございました。これでは、ものすごく恣意的だと思うと受けとめられても仕方ない。特に、WebKitチームから指摘されたAcid3の不具合が修正されたことさえきちんと書いていなかったことは不覚の極みである。

但し、Operaが100点取った!って宣言したビルドの点数が実は99点だったというのは This presumably means Opera is now at 99/100... を踏まえてのことだと考えられるが、presumably が「おそらく」という意味なので、Hickson 氏も推測しているだけと考えられる点は指摘できるだろう。100点取ったのはその後のビルドという指摘はソースがわからないため、検証することができなかった。

次に、レス896 (ID:JCWAmUkB0 氏、レス895と同一 ID) から引用。

896 :名称未設定:2008/04/02(水) 00:54:40 ID:JCWAmUkB0
もう一ついうと、
Webkitのblogに書いてあったけど、
サブピクセルレンダリングのパッチを適用せずとも100点取れていたって
ことにも言及していない。
Acit3がReferenceImageとのPixel-to-Pixelでの一致を要求する時点で
サブピクセルレンダラを標準実装する環境とあわないのは自明の理。

きちんと英文読めてるのかな?

Safari Part41

サブピクセルレンダリングのパッチを適用せずとも100点取れていたってことにも言及していない点についても、完全に見落としていた。Webkitのblogに書いてあったというのは「Surfin' Safari」のエントリ「WebKit achieves Acid3 100/100 in public build」のことだと考えられる。確かに、サブピクセルレンダリングの件が Acid3 の点数には影響しない現象であることは確かであり、この点を明確にしなかった私の文章に落ち度があった。

Acit3がReferenceImageとのPixel-to-Pixelでの一致を要求する時点でサブピクセルレンダラを標準実装する環境とあわないのは自明の理というのも、なるほどもっともな話である。

きちんと英文読めてるのかな?については、以前にも脚注でも言及したように、私の英語力は酷いものであり、英文が読めていなかった。これは自他共に認める事実であると思う[1]

最後に、レス900 (ID:5E+KvCxK0 氏) から引用(脚注筆者)。

900 :名称未設定:2008/04/02(水) 01:07:15 ID:5E+KvCxK0
>>895
> このサイトさ、Operaが100点取った!って宣言したビルドの点数が
> 実は99点だったってことに「まったく言及していない」のはなぜだろう。

> そもそもWebKitチームから指摘されたAcid3の不具合が修正されたこと
> さえきちんと書いておらず、ものすごく恣意的だと思うんだが。

モダンブラウザに興味があるのに、HyattとAppleやMozillaとの関係も
知らないってのは、ちょっと珍しい人だよね。あとWeb標準にこだわりながら
ユーザビリティ的には×××つけたくなるような疑似inline-frame仕立ての
サイトデザインもようわからん[2]

でもま、このスレでの誤訳の指摘が反映されてるあたり、書けば聞く耳
持ってくれる人ではあるんじゃないかなと。

Safari Part41

モダンブラウザに興味があるのに、HyattとAppleやMozillaとの関係も知らないってのは、ちょっと珍しい人だよねという意見には素直に「その通りでした」としか言いようがない。Hyatt 氏のことについて知ったのも、2008年3月29日になってからである。

「WebKit 開発者の一部よ、恥を知れ!」が本当に言いたかったこと

さて、これからの言及は言い訳じみて捉えられる可能性があるため、それを私自身も自覚しているという前提で話を進める。

「WebKit 開発者の一部よ、恥を知れ!」で、私は先に結論を述べた。今回、その結論を修正し、本当に言いたかったことをより詳細に言及する。

まず、「WebKit 開発者の一部よ、恥を知れ!」の結論を強調位置も含め次のように修正する。「WebKit 開発者は Acid3 をリファレンスレンダリングとのピクセル完全一致レベルでクリアすることのみに特化した、汎用性のない、バグの温床となりうるコードを実装した」。

以降、前述した結論の本意について記述する。

私が一番問題視したのは、あくまでも「汎用性のない、バグの温床となりうるコードを実装した」点である。つまり「Changeset 31322 のようなコードがレビューを通過し、チェックインされてしまったことが問題である」と言いたかったのだ。むしろ、Acid3 をクリアしているか否か[3]など、どうでもよかったのである。結果として、パッチの意図、Acid3 への影響、翻訳、人物に対する知識といったトピックが生まれた。

パッチの意図、Acid3 への影響、翻訳、人物に対する知識などは、Changeset 31322 のコードが持つ忌まわしい本質とは切り離して考えるべきである。私が論じようとしたのは後者、即ち「Changeset 31322 のコードが持つ忌まわしい本質」についてであった[4]

不明瞭な文章、説明・調査不足、無知などが重なり、結果 Opera 優遇のような印象を与え、「WebKit を攻撃している」と受けとめられる可能性がある文章を記述したことは、私にとっての恥であり、WebKit を愛している人々からの指摘を受けて当然ともいえる。

ここに意図の明瞭化と情報の加筆訂正を行い、関係者並びに指摘を頂戴した方々に、心よりお詫びと感謝を申し上げる次第である。

脚註

  1. まったく自慢できない話である。
  2. これは私自身にとっても悩みの種である。このサイトの基本デザインはここ3年以上の間変更されておらず、どうにかしたいとは思っている(思っているだけじゃねーか、というツッコミはアリ)。
  3. いかなるレベルでも。点数のみであっても、リファレンスレンダリングとピクセル完全一致レベルで同一であっても、実際のところ本論には関係ない。
  4. 無論、前者の中にお粗末な点が存在したことは事実であり、加筆訂正して然るべきだ。

2008-04-02