|
|
||
CSS、HTML、XHTML、XML、DOM、XSLT、XPath、ECMAScript、Python、ウェブユーザビリティ、その他に関連する文書等のリソースを挙げていったりします。より本質的な議論を志向。
注意:Hatena::agendaの更新は終了しています!過去の記事はagenda のホームページよりどうぞ。今後の更新情報の取得は、agendaのフィード(XML/Atom)から。
一応この2ヶ月、はてなダイアリで何かできないかを考えてみた。でもやっぱり、JavascriptもPHPもPythonも使えないし、管理に制限はあるしで実験場としてのメリットは見いだせない。URIの管理に責任を持つことができない以上、他人のドメイン上で記事を公開するのは無責任である。
というわけで、Hatena::agendaの更新は完全に終了することにした。今後のメモはagendaに公開する。過去の記事を消したりはしないので、まあ当分の間はデッドリンクは発生しないだろう。Hatenaを追い出されたり、Hatenaそのものが消えたりした場合には、ログファイルをhttp://purl.org/jintrick/agenda-links/に置くことにする。一応このURIをHatena::agendaのURIとしてアナウンスしていたので。
惰性ではてなダイアリを使い続けてしまったのは結構痛い。ただより高いものはない。
見出しとオブジェクトの題名が混同されているが、まあ別にh6でも実害はないだろう。但しh6要素が実際セクション単位の見出しとして出てきたときに問題になるし、言い逃れようのない要素の詐称だ。はっきり言って、問題を起こさないdl/dt/ddやp/strongの方がまだマシというもの。どれも嫌だというならセルが一つしかない表なんだよと豪語してしまう手もある:
<table><caption>犬の写真</caption>
<tr><td><img src="dog" alt="">
</table>
犬の写真が複数あり、それぞれ撮影日だのコメントだのをつけるなら、表組みになる。たまたま、撮影日の記載やコメントがなく、写真も一つだけだった「のだ」。わらい。
書いていて思ったがそう悪くないな。自分のサイトでも使ってみることにするか。何か文句言われたらデータ増やして本当に表にしてしまえばいいだろ。
でもこれはやや不適切:
<table><caption>注意</caption>
<tr><td>犬が嫌いな人は帰ってください
</table>
注意事項が複数あったとしても、表組みにはならなそう。文書指向的にはデータオブジェクトではなく主張そのものだから、table要素ではありえない。文書の階層構造の中に組み込まれるべきものであって、正しく見出しとしてマークアップすべきだ。そのために文書構造を見直すのは、全く正当な行為である。
ページの一番下の部分にできた下向きの矢印ボタンをクリックすると、以前に 書いた日記がその場でどんどん開く便利な機能です。これまでは、ページに表 示されていない以前の日記を見る場合は「前の○日分」といったリンクを押し てページを開く必要がありましたが、今回できた矢印を押せば、ページを開き 直すことなく、その場で見たい日記が表示されますので、待たずにどんどん閲 覧できます。新しくできた矢印と仲良くしてあげてください。*
frame要素乱用の失敗から何も学んでいなかったのか? URIの仕組みが使えないからブックマークできないし、履歴で戻れない。まあキャッシュの強力なOperaなら戻れそうな気がするがそんな保証はない。単純なハイパーリンクの方が便利。Ajaxはリンクのセマンティクスを何一つ表さない。
それに今の所先行読み込みしているわけでもなさそうなので、待たずにどんどん閲覧
なんてできていないよ。しっかり待たされた。そのうち改善されるかもしれないけどさ。つまり今の所メリットは限りなくゼロ近くてデメリットが沢山あるという状況だな。はてなはrel="next"なlink要素があるんだから、待たずにどんどん閲覧
なんて昔から可能だったんだよ。Greasemonkeyスクリプト、あるんじゃない?
やばい呆れ返ってしまって詳しく書く気力がでない。最初はキレてたんだけど、逆に脱力してきたぞ。わらい。はたから見れば大したことないんだろうけど、私はリンクを舐めてるウェブデザイナが大嫌いなんだよ。もうこれ以上こんなところにまともな記事は書けない。予定より少し早いけど今日からはてなに記事を書くのはやめることにしたよ。宣言していた通り私が記事を消去することはしない。これからも「実験」をしにきたり、「痰」ぐらいは吐きにくるかもしれないけど。
スタイルシートの文脈で文書指向ウェブデザインを説明すると、文書を読みに来た閲覧者のみをターゲットにしたデザインということだ。正式版をjintrick.netで公開する前に1時間で書いたプレビュー版を糞ブログに「流して」おこう。
前景色は黒(#000)、背景色は白(#FFF)にすることで、より確実な可読性を確保できる。眩しくて読みづらいというよくある批判に対する答えはこうだ:
特に後者はまだ誰も言及していないんじゃないかな。
左右のマージンを小さくすることで、より幅広い状況に適応できる。相対指定の2〜3%程度で十分だろう。それでも左右が詰まっていて息苦しいという批判に対する答えはこうだ:
文書を眺めに来た閲覧者というのは、たいていスタイルシート制作者自身に他ならない。文書指向の考え方はこのミスを防ぐ。
枠線はコンテンツの区分にのみ使用することで、枠線に統一的な意味を感じさせることができる。セクション単位や見出し一つに対してボーダーを設けると、画面が窮屈になる。空白をうまく使おう。枠線ばかり使っていると、いざというとき(注意書きなどを目立たせるとき)に枠線の効果が得られない。
文字サイズはユーザーに任せるというのは、当たり前かもしれないが一応挙げておく。CSSでは継承元に100%またはmediumを指定し、見出し等には大きめの相対指定をする。
本文のフォントは一種類に統一する。意味もなく様々なフォントを混在させて脅迫文のような印象を与えてしまう愚は避けよう。例外としてプログラムコードなどのフォントは、l(小文字エル)とI(大文字アイ)、0(ゼロ)とO(オー)のような似ている文字の区別がはっきりとしたもの(例:Consolas)を選んで使う。また見出しには大きめのボールド体でもきれいに見えるフォントを別途指定して良い。
無駄な画像は使わず、表示までの速度を0.1秒でも速くしよう。質の高い画像で閲覧者をだます行為は、文書指向とは何の関係もない。内容で勝負しよう。trustの情報を必要とする閲覧者には、質の高い画像などではなく著者紹介等へのリンクを用意しよう。
文書の理解を補助する画像はふんだんに使おう。これはスタイルシートの話ではないように見えるが、実際にそのような画像を使うときには文書が見栄えするように配置・調整すると一石二鳥で、無駄な背景画像を使うより遥かに有益である。
スクロールは小さく抑え、画面領域という資源を有効に利用する。窮屈にならない程度の最低限の縦幅で済ませるよう、各要素の上下マージンを小さくしたり、テーブルや画像などを浮動させてテキストを回り込ませるなどの工夫をする。
リンクのアンカーには下線を引くのが標準であり、リンクであることを示す最も簡単で確実な方法である。裏を返せば、これ以外の要素に下線を引いてはならない。
未訪問リンクのアンカーは青色にするのが標準であり、これを逸脱するとリンクであるかどうかを判断する労力を強いることになる場合もあり、無駄である。
訪問済みリンクのアンカーは赤紫色にするのが標準であり、未訪問のアンカーと同じ色にして訪問済みかどうかという重要な情報を隠すような馬鹿げた嫌がらせをしてはならない。
要するに、文書指向ウェブデザインのプレゼンテーションスタイルは実に禁欲的で殺伐としていますよ、ということになるが、説明的な画像やビデオなどはふんだんに使って良いので、最終的な見た目の鮮やかさはその文書の内容次第である。一般的なブラウザのデフォルトのスタイルシートとの明らかな違いは、画面領域に対してコンテンツ領域がその多くを占めているということだ。2007年現在、CSSでは不可能だがJavascriptと組み合わせてリキッドレイアウトを実現すれば、特に高解像度モニタに対して画面をさらに有効に使うことが出来る。
リキッドマルチカラムを利用する。この方法は内容が深いので別文書とした。
ちなみにこの糞ブログのリキッドマルチカラム指定は欠陥だらけである意味嫌がらせに近いものがあるが、まあこんなのもあるよくらいの意味なのでよろしく。ウィンドウ幅を小さくすれば1カラムになるよ、というのは言い訳にならないか。
はてなダイアリー日記 - 2007-09-29を読んだけれども、 はてなダイアリはもっと簡単に、しかもクールに改善できる。今すぐに。
title要素は「記事名 - ブログ名」の順序にする。理由:タイトル要素が利用されるのはOSのタスクバーやタブブラウザのタブなど、限られたスペースであることが多い。ブログ名を記事タイトルの後にしないと異なる記事なのにブログ名しか一覧されず不便。(探しても見つからなかったけれど、設定でできるのかもしれないね。出来たらごめん)
スクリプトは統合、最適化する。現在これらのJavascriptファイルが外部リンクされているようだが、一つにまとめる。
理由:分割すると管理、運営しやすいかもしれないが、それは文字通り0.1秒でも早く閲覧したい閲覧者には何のメリットもない。そもそもprototype.jsってプロが使うものなの? そのサービスで利用する最小限に削るべきでは。IE向けにlanguage="JScript"で、Firefox2向けにtype="application/javascript;version=1.5"とかに分けるなら尚可。プロならスクリプト内でのブラウザ判別はできる限り避けるべき。ユーザに無駄なものをダウンロードさせてはいけないし、無駄な処理を要求してもいけない。それが可能なプロなら。(探しても見つからなかったけれど、設定でできるのかもしれないね。出来たらごめん)
HTML4.01 Strictの文書型を選択可能にする。理由:transitionalだとmax-widthプロパティを解釈しないへんてこなブラウザが存在するため。(探しても見つからなかったけれど、設定でできるのかもしれないね。出来たらごめん)
カテゴリ名のリンク先は、そのカテゴリの記事一覧を表示するようにする。なんか他所のはてなダイアリで、[Javascript]とかのカテゴリ名をクリックしてもJavascriptに関する記事の「一覧」ではなくて、最近の記事がいくつか表示されるだけなんですけど。何の冗談なんですかこれは。( 探しても見つからなかったけれど、設定でできるのかもしれないね。出来たらごめん)
別に改善してくれなくても全然構わない。というかむしろ改善しないで。駄目な子ほど可愛いんだから。
Tabs, Used Right: The 13 Usability Guidelines (Jakob Nielsen's Alertbox)を読んだ。
最近Hatena::agenda - フォーム部品を不適切に使うなで触れた話題が出た。タブのユーザビリティガイドラインだ。13もある。まさか今更Alertboxで取り上げられるとは。
一番目のto alternate between views within the same context
は当然というか標準の話だが、三番目のusers don't need to simultaneously see content from multiple tabs
、つまり並行閲覧することがない情報についてタブのUIを使え、というのは理にかなっている。以前タブブラウザに批判的なコメントをした理由はここにある。私が観るところ、タブブラウザが流行るのは単にOSが駄目であるか、あるいはOSを使いこなしていないか、どちらかの理由による。たくさんのウェブページを開いておきたいけど、複数のウィンドウを開くとmanageしづらくなる、だからタブブラウザを選択する、というのは、明らかにウィンドウというUIを生かせていない。その原因がOSにあるかユーザーにあるかは、色々なケースがあるだろうけど。
ちょっと話題がそれるけど、私はMacでSafari使ってるときにほとんどタブを使わない。ウィンドウいっぱい開いて、Exposeする方が便利なんだもん。タブブラウザっていうのはMacからは生まれてこなかったアイデアかも知れない。閑話休題。*
ウィンドウ間の論理的な繋がりが視覚化されている形が望ましいと考えているので、Max OS XのExposeがベストな解だとは思わないが、少なくともタブブラウザを使う理由が、変な制約のない環境においてreasonableではないことは明らかで、共感できる。でもやはりまだタブブラウザは要るんだよね。並行閲覧を妨げるような使い方をしない限りはウィンドウのグループ化に有用だが、しかしそれもOSの未熟の為で、将来的には全く要らなくなるだろう。
話が飛ぶけどyou can do something doesn't mean that you should.
ってAjaxに関して私も割とよく主張することだ。
タブブラウザが流行る理由、もう一つあったっけ。低解像度モニタだ。今流行の「固定幅デザイン」は、XGAくらいではとてもじゃないが並行閲覧できない。できないんならタブブラウザでいいというわけだ。私が昔タブブラウザを好んで使用していた理由はなんだっけ。たしか数十のウェブページを一気に開くようなサーベイを良くしていたからだ。でもそれならSleipnirのタブ機能を切ってツリーviewを使った方が圧倒的に使いやすいことに気づいて、タブブラウザに別れを告げたんだっけ。
非常に懐かしい文書をdeztec.jpが保存しておいてくれた。構造と内容を分離し、ウェブページを動的に生成してサーブするのが制作者にしか利益がないのに対し、CSSによってセマンティクスと表現方法を分離するのは広く閲覧者に利益がある。そこが何しろ重要な点だということが分からないから、実際には、相対的なものにすぎない
などと書けるのだろう。
しかし構造と内容の分離こそ、制作者の自慰行為に「過ぎない」。しかもここで例示されている「構造」は文書構造ではなく、パーツである。文書には内容と構造があるが、実はこれは不可分なのだ。昔XSLTを利用してフラットな「自家製XMLインスタンス」と構造を分離した気になっていたことがあったが、分離などではなく、暗黙的に存在していた文書構造をXHTML1.0という形式を用いて明示しただけの話だということに、やってみて気づいた。そして、文書型宣言やナビゲーションなどのウェブページとしての「パーツ」をくっつけていただけなのだ。それは文書の構造ではない。ウェブページとしての体裁を保つためのパーツである。
しかしそんなものを分離してみたところで、閲覧者に何の利益があるのか。もちろんないから、私は変換後の静的なHTMLを公開した(サーバの仕様上不可能であったためでもあるが)。そしてHTML+CSSによるセマンティクスと表現方法の分離と比べて、いかに公開価値がないものであるかも理解した。つまり分離しているという状態の公開価値がである……。
2007年8月21日 妖精現実ファアリアル(faireal.net)は、負荷を減らすため、通常のページの一部を一時公開停止しています。すぐに記事を見るには、XMLの生データを参照してください。*
そして現在に至る。XMLの生データ
とは何か。静的なHTMLを公開しない(できない)理由が、私にはちっとも理解できない。
追記:
[教育]妖精現実は2chの人大杉と同じ。文句言うなら募金しなさい。*
このAYBABTUみたいな馬鹿に「教育」される人間はいないと思う。読み直せ。妖精現実? そんなサイトの事なんか知らん。悪いが読者でもない。内容と構造の話しかしていない。そんなリスクの小さな「そーしゃるぶっくまーく」なんぞという殻にこもって「低能」だの何だの中傷していないで、堂々と出てきたらどうだ? 最低だぞお前。
Hatena::agenda - 本物のリキッドレイアウトの具体化。
リキッドレイアウトは動的なスタイルシートによって実現する。CSS2は閲覧環境に応じてある程度柔軟な変化を提供するが、まだ充分ではない。今現在でもJavascriptの助けを借りれば、本物のリキッドレイアウトに近づけることはできる。
リキッドレイアウトを助ける主なstuffは、今のところ次の四つ。
floatプロパティは「サイドバー」を表現するために作られたのでは、ない。テキストが回りこむ浮動オブジェクトを描くのがfloatプロパティの本来の姿である。しかし例えばあるテーブルにfloatプロパティを指定したとき、たとえそれがウィンドウの幅の8割を占めていても、テキストは回りこんでしまう。すると一行が異常に短くなってしまうことがあり、読みづらいことこの上ない。充分に小さなテーブルや画像に対してのみfloatを指定したいが、どの程度が充分に小さいかを製作者が判断することはできない。
この問題を解決するために、動的にスタイルシート(クラス名)を変更する。ウィンドウ幅に対して半分以下の幅をもつtableなら浮動オブジェクト化し、そうでなければ浮動させないようにすればいい。イメージとしてはこのようなスクリプトだ。
function optimizeLayout(){
var w = document.documentElement.clientWidth;
for each(let e in document.selectNodes("descendant::table"))
e.className = e.clientWidth/w < 0.5 ? "FloatingObject" : "";
}
window.addEventListener("resize", optimizeLayout, true);
window.addEventListener("load", optimizeLayout, true);
半分というのは単純化のための例に過ぎず、より良いリキッドレイアウトを追求するなら「ウィンドウ幅の残りが20em以上」のような計算が必要である。フォントサイズがユーザーの好みに応じて可変となり得るメディアにおいては、width(幅)の概念は一文字の大きさが基準となる。
イメージとしてはこのような構造だ:
<body>
<div class="container">
<div class="contents" href="contents.xht" rel="contents"></div>
<div class="main">本文</div>
<div class="appendix" href="appendix.xht" rel="appendix"></div>
</div>
</body>
もちろんdiv要素にhref属性などない。言いたいのは「埋め込むな。参照せよ。」ということだ。実際には目次や付録はlink要素でリンクしておき、必要となった時に埋め込む。
15emとか30emという値、右側、左側というのは一例に過ぎない。
2.とほぼ同じだが、floatではなくより適切なdisplay: tableを利用しようということ。
本文部分のブロック要素の高さの合計値が表示領域の高さ未満であったなら、本文部分を包括するdivブロックに対して-moz-multi-column-widthを指定する。しかしそのような適切なdivブロックが常にあるとは限らない。
長文の場合、本文部分のブロック要素(主にp要素)のshrink to fitした場合の「面積」を順々に加算していき、表示領域の面積を超えない範囲でdiv要素で包括するというプロセスが必要となる。
逆に短い文章、小さなコンテンツはマルチカラム化できない。表示領域の高さに対し30%未満の場合、前述の2.と3.の方法で外部リソースをロードした方が良い。
数年前Hatena::agendaで公開したselectNodesメソッドの実装に加えて、カスタムイテレータを定義してfor each文で使えるようにしてみた。
まず_XPathNSResolverを定義。非XMLなHTMLで使う限りこれは読み飛ばし可。経緯はHatena::agenda - 2003-12-04。
function _XPathNSResolver(nsmap, nodeResolver){
this._nsmap = nsmap;
this._resolver = nodeResolver?
nodeResolver.ownerDocument.createNSResolver(nodeResolver) : null;
}
_XPathNSResolver.prototype.lookupNamespaceURI = function(prefix){
var v;
if (v = this._nsmap[prefix])
return v;
if (v = this._resolver)
return v.lookupNamespaceURI(prefix);
return v;
};
_XPathNSResolverの使い方。第一引数に接頭辞とURIのペアのオブジェクトリテラルを渡してインスタンスを作って、evaluateメソッドの第三引数に渡す:
/* Tipical usage of _XPathNSResolver
var de = document.documentElement;
var type = XPathResult.FIRST_ORDERED_NODE_TYPE;
var nsresolver = new _XPathNSResolver(
{xht: "http://www.w3.org/1999/xhtml"}, de);
var result = document.evaluate(
'descendant::xht:*', de, nsresolver, type, null);
*/
次。Nodeインターフェイスを拡張。まず個人的に良く使う手でスコープを作る:
(function(__proto__/* Node.prototype */){
次にselectNodesメソッドを書く:
var resolver = (
Document.prototype.xpathNSResolver = new _XPathNSResolver({}, null)
);
__proto__.selectNodes = function(expression){
var doc = this.nodeType == Node.DOCUMENT_NODE ?
this : this.ownerDocument;
var result = doc.evaluate(
expression, // XPath expression
this, // Context node
resolver, // Name space resolver
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, // Result type
null // XPathResult if reuse
);
if (result.snapshotLength == 0) return null;
return new _NodeList(result);
};
たぶん毎回_XPathNSResolverを作るのがアレだからdocumentオブジェクトのメンバにして使いまわそうとしたんだろう>自分。ここ改善の余地。
で、ここからがついさっき書き加えた部分。_NodeListコンストラクタ。selectNodesメソッドの戻り値はNodeListなので、それに似たものを自作。
function _NodeList(result){ // 「死」んでいる点に注意する
this.__index = 0;
this.__result = result;
this.length = result.snapshotLength;
}
いよいよ本題というか、_NodeListのメソッドと共にカスタムイテレータを定義。Javascript1.7は……本当にいいものだ。
(function(__proto__){
__proto__.__iterator__ = function(){
return this;
};
__proto__.item = function(index){
return this.__result.snapshotItem(index);
};
__proto__.next = function(){
var item = this.item(this.__index++);
if (!item) {
this.__index = 0;
throw StopIteration;
} else {
return item;
}
};
})(_NodeList.prototype);
_NodeList自身をイテレータにした。こうすることでfor each文を自然なPython風に使用できるという寸法。おっとスコープを閉じなきゃ。:
})(Node.prototype);
で使い方なんだけど例えば次のようなタスクを考える:
DOMでは割と小面倒な部類なんじゃないかな。北村さん(誰)に突っ込まれそうなクラス名だけど気にしない。
for each(let e in document.selectNodes("descendant::ul | descendant::ol"))
e.selectNodes("child::li").length < 4 && (e.className = "short");
終了。XPathをもっとうまく使う別解もあり。
CSS3のマルチカラム(草案)の先行実装を利用すると、Googleの検索結果がモニタ上で一望できる。それに伴ってGoogleナビゲーションその他の位置も最適化してみた。
滅多に褒めてくれないうちの嫁さんも「いいね」って言ってた。greasemonkeyスクリプトとユーザースタイルシートで実現している。
先日のユーザースタイルシートに少し指定を加えた:
@-moz-document domain("www.google.com"), domain("www.google.co.jp") {
body {margin: 0; padding: 0 }
div#res{
-moz-column-width: 25em;
-moz-column-gap: 1em;
}
.purlOrgJintrickNext b{
font-size: 30pt !important;
}
div#res table {
width: 100%;
}
#mbEnd{ display: none; }
}
Google検索結果には緑色の文字でURLが表示されていて、ウェブページの信頼性を判断する基準として利用できるのだが、これが長すぎると折り返されず、隣のカラムにはみ出して重なってしまう。これを防ぐためoverflowプロパティを追加指定した。
/* 緑色のURL部分 */
span.a{
display: block;
overflow-x: auto;
overflow-y: hidden;
}