2009-09-21

QuirksBlog: HTML5のドラッグ&ドロップはクソだ

QuirksBlog: The HTML5 drag and drop disaster

QuirksBlogで有名なPeter-Paul Kochさんが、HTML5のドラッグ&ドロップに関して、酷くののしっている。かなり好い文章で、興味深かったので翻訳してみた。記事が長いので、blockquoteを使うのは御免を被る。

一日半もテストして、HTML5 drag and drop moduleはクソなばかりか、ゲロみてえな臭いがプンプンするってことが、いやというほど分かったね。

コイツはHTML5規格から、ソッコーで消すべきだし、もっとまともな規格が制定されるまでは、現行ブラウザは、この機能を、一刻も早く無効にするべきだ。

Web開発者は、HTML5のドラッグ&ドロップを使うな。絶対使うな。RFC2119で規定されているMUST NOTの意味で使うな。使いたきゃ、従来通りのスクリプトで実装しろ。いいな。

これからその理由というヤツを述べていこうと思うんだが、その前に、ひとつ言っておくことがある。俺は基本的に、HTML5規格は支持してる。何でかっていうと、規格の出来が、結構好いからな。実際、こんな好い規格に、なんでこんなクソの塊が転がってるんだよ。マジでおかしいし。

マジで調子ブッコいてるほどアホくさいんで、俺はストを敢行する。もうこれ以上ドラッグ&ドロップについては調べん。てめーらで勝手にやんな。あるいはやんないか。まあ、どっちでもいいか。どうせ俺の知ったこっちゃあない。

以下に述べることは、実に言葉遣いがなっていないが、謝罪はしない。ドラッグ&ドロップは最悪だ。

誰の責任だよ?

マイクロソフトが、ドラッグ&ドロップを、「設計」して実装したのは、1999年のIE 5.0のリリースにまで、さかのぼれる。それ以来、IEはこれをサポートし続けている。

この次に述べるごとく、この規格は恐ろしくクソだった。責任の大部分はマイクロソフトに帰するといっていい。

最初は、独りマイクロソフトのせいだと思ってたんだが、HTML5 WGとブラウザ各社にも、責任がある。

HTML5と、その前身、WHAT-WGの基本理念に、先のワーキンググループが規定していなかった、実際のブラウザの挙動を規格化しようというものがある。たとえば、innerHTMLとか、offsetWidthとかだ。

俺も、この理念には賛成だが、マイクロソフトのドラッグ&ドロップに限っていえば、かなり問題があると言わざるを得ない。

Hixie曰く、「ドラッグ&ドロップAPIはひどいが、利点もある。IE6が実装しているのだ。SafariやFirefoxも」

まあ、現実はその通りなんだが、FirefoxとSafariとChromeは、ために悲惨な憂き目にあっている。Operaだけは悲惨な現状から免れている。

どこでもその機能が使えるってこたあ、たしかに重要だ。でもコレはないだろ。ドラッグ&ドロップは悲惨すぎるぜ。

俺様のテスト状況

オッケー。んで、一体HTML5のドラッグ&ドロップの、何がクソかって話だ。

教えてやるよ。

俺がテストしている状況を、そっくりそのままに記述すると、以下のようになる。俺は以下のような思考順序を経て、このエントリを書くに至ったわけだ。

今回のテストはメチャ最悪だった。ネットスケープ4が絶滅して以来のクソさ加減だ。だから記述には、暴力的な言葉が含まれているわけだ。それもメチャたくさん。

イベント多すぎ

ドラッグ&ドロップには、七個もイベントがありやがる。dragstart, drag, dragover, dragenter, dragleave, drop, dragendだ。

mousedown, mousemove, mouseupのイベントだけで実装できるモノにしちゃあ、何かやたらと多くないか。

まあ、これぐらいなら、別にクソって事もないんだ。ちょいとAPIの設計が汚いって程度だ。この中から使いたいイベントをいくつか選び、残りは無視しなければならない。

茫然自失

茫然自失

ハァッ? ナメてんのかッ? 何だとッ!?

dropイベントは、ユーザーがドラッグ中の要素をドロップした時に起こる。

そして、当然ながら、ドラッグ中の要素をドロップすることが、この規格の主目的なわけだ。

従って、dropとは、最も重要なイベントである。しかし、何故か起こらない。何故だろう。

茫然自失。

規格と使用例の確認。

オッケー、分かったよ。

dropイベントを発動させるには、dragoverとdragenterイベントのデフォルトをキャンセルしなければならない。

・・・・・・。

ハァァァァァァッッッ?

オッケー、もう一回、確認しよう。

dragoverとdragenterのデフォルトアクションは、要素をドロップさせないことである。そのため、要素をドロップさせるには、デフォルトアクションをキャンセルしなければならない。これ当然なり。いかにも明白の理なり。

・・・・・・。

ハァッ? ナメてんのかッ? フザけるなッ!?

オッケー、もう一度。

dragoverとdragenterイベントが存在する根本的な理由は、ドロップをさせたいWeb開発者に、デフォルトの挙動をキャンセルさせるためである。

またまたご冗談を。

無言。

フザけやがってッ! ブチ殺すぞゴミめらッ!

何でわざわざ、本来の一番重要な機能を発動させるために、てめーのクソイベントのデフォルトアクションを、ひとつならずふたつもキャンセルせにゃならんのだ。誰がそんなことするかッ!

じゃ、遊んであげないニャ。さいニャら。

このチンピラが オレをナメてんのかッ! この、ド低能がァーーッ

無言。

おいよく聞けよ、ボケなす。まあ、その頭じゃ到底理解不可能だとは思うがな。万が一ってことがある。ひょっとしたらお前みたいなクズにも分かるかもしれん。

デフォルトアクションとはな、ポジティブにあるべきなんだ。かくかくの挙動をしたら、しかじかが起こるというものだ。スクリプトでキャンセルしない限りはな。JavaScriptのイベントはそのように設計されているんだよ。

無言。

クソッ、タバコがやめらんねえ。

時間の浪費。

落ち着け、落ち着け。Let it be. どうにかなるさ。

まず、何か別のことをして気を紛らわせよう。

ようやくにして平常心を取り戻す。

dragstartイベントハンドラを定義すると、IEでは、他のイベントが起こらなくなる。他のイベントすべてだ。

Remy Sharpのテストケースをみると、IE8では、dragstartありでも動くらしい。

どうにも不思議だ。だいたい、規格はIEの実装を元にしているはずではないか。つまり、規格が、他のすべてのイベントがキャンセルされるという挙動を見逃したのだろうか。あるいは、IEが自分とこの独自機能すら、満足に実装できていないのか。

今のところ、後者ではないかと思う。ブラウザバグを一件発見。後で再テストして、再現方法の発見して、ドキュメント化しなければ。

やれやれ、なんとかマトモになってきたぜ。

まあ、他のヤツは、そんなにクソじゃないだろ。たぶん。

だが、その前にイベントに関して。

ドラッグこれイベント

dragイベントというのは、mousemoveに似ている。ただし、ドラッグ中に発生する。これはマトモじゃないか。ちゃんとどこでも動くだろうか。動くようだ。次。

ドラッグあれイベントとドラッグ何かイベント

dragenterとdragleaveは、すばらしいイベントのように思える。ドラッグ中に、HTML要素の中に出入りすると、発生するわけだからな。要素が妥当なドロップターゲットの場合、そのスタイルを、ondragenterとondragleaveで変更して、そのことをユーザーに伝えることが出来るって寸法だ。

マイクロソフトのAPIを元にした規格で、オレはdragenterとdragleaveが、mouseenterとmouseleaveと同等機能だと期待していたんだ。だが、違うんだなコレが。IEにおいてですら、違うんだな。mouseoverとmouseoutと同等で、あらゆる点においてクソだ。命名が間違っているわけだ。

mouseoverとmouseoutは最悪だ。というのも、常にbubbleで上がっていくので、重要なものとそうでないものを判断するのが、最高にムズかしいんだ。イベントがセットされている要素の、子要素に対して、mouse overするかdrag enterしても、発生する。そんなのいらねーんだよ。マウスが要素の上を通るたびに、イベントが無駄に発生するだろうが。有益なイベントと、そうでないものを選り分けるのが面倒なんだよ。

訳注:DOM Level 2のEventTargetインターフェースにある、addEventListener()を使ってイベントハンドラを追加すれば、第三引数をtrueにすることによって、bubbling phaseを無視できる。また、リスナーとして登録するEventListenerインターフェースのhandleEventメソッドの引数、Eventインターフェースにある、eventPhaseプロパティをみれば、現在のPhaseはすぐ分かる。この問題は、それほど面倒だろうか。

一方、mouseenterとmouseleaveは、定義されている要素にしか、発生しないし、bubbleもしない。こっちの方が使いやすいって事だ。

コイツらはマイクロソフトの独自拡張なんだが、いい機能だ。IEでしか動かない。

元々、mosueenterとmouseleaveはドラッグ&ドロップと同じで、互換だった。mouseenterとmouseleaveにとっては役に立つが、ドラッグ&ドロップに対しては、役に立たない。他のブラウザはどんな風に実装するんだろうな?

Web開発がこんなにクソ面倒なのも当然の話だ。こんな大マヌケがブラウザの挙動を決めてんだから。

おっと、これはマヌケに失礼だったな。

あ゛-、クソが。

drag大まぬけイベント

dragoverは、mouseoverとは何の関係もない。dragイベントとまったく同じだ。ただし、documentだけではなく、どんな要素にもセットできる、あるいは何か。どうでもいいけど。

じゃあ何で、dragイベントがあるのに、dragoverイベントが必要なのか?

プカー、スパスパスパスパ・・・・・・プカー

デフォルトアクションをキャンセルするためにある。

デフォルトアクションをキャンセルしなくて良けりゃ、dragマヌケイベントなんざ、ハナッから必要じゃねーんだよ。ボケが!

そうすりゃ無意味なイベントが、規格から無くなるだろ。だろ?

だから、デフォルトアクションを定義するんだよ。複雑なデフォルトアクションを。

もちろん、キャンセルできる必要がある。当然だ。動作を取りやめるためのキャンセルだな。

無言。

おい、誰かいないのか?

時間の浪費。

おい、オレ今、サイコーに好いこと言ってんだぞ。お前らさっさと規格改良しやがれ。

draggable

で、draggableっちゅー属性があってだな、trueにしとくと、その要素がドラッグ可能になる。Firefoxでしか動かない。リンクとイメージは、デフォルトでdraggableだ。

実際、これは実に好いアイディアだ。

ワーオ。やっとマトモなものを見つけたぜ。でも誰に感謝すりゃいいんだ?

思うに、draggableというのはHTML5による追加なんだろう。IEでは動かないもんな。HTML5 WGも、ひとつぐらいはまともなアイディアを出せたようだな。おめでとう。

だいたいだな。ドラッグ&ドロップに関するマイクロソフトのドキュメントが見あたんねーんだ。だからIEでdraggableがサポートされているべきかどうか、分からねーんだ。

見た限りでは、IEのアイディアではないってことだけは、確実だ。

(おめーらがマイクロソフトのドキュメントがどこにあるか知っていたとしても、コメントに書き込むこたあーない。もはや、どうでもいいことだからな)

マヌケすぎるSafari

はい、次の問題。

Safariでドラッグ&ドロップを動かすためには、CSSにこれを追加しろ。

#tobedragged {
 -khtml-user-drag: element;
}

・・・・・・。

Q:よお、この要素をどのようにユーザーに対して表現したらいいんだ?
A:それはドラッグ可能だ。

・・・・・・。

死ね、Safariチーム、氏ねじゃなくて死ね。

いやまてしばし。もういちど言ってみよう。丁寧な言葉は、乱暴な言葉よりも受け入れられやすい。

Safariチーム各位。「表現と挙動の分離」という事をご存じの方はいらっしゃいますか?

無言。

んなこったろーと思ったぜ。

時間の浪費

何にせよクソだ。

訳注:CSSとは本来、ユーザーに対して、どのように表現するかを指定するものである。ドラッグ可能かどうかという事は、表現ではなくて、むしろ挙動である。Safariのこの独自拡張は、表現を指定するはずのCSSで、挙動を指定するというものである。それ故、不可思議な拡張となっている。

ドロップエフェクトか? それともドラッグエフェクトか?

DropEffectプロパティ(訳注:確かに、Javascript側からみたら、プロパティだが、ここは属性と呼ぶべきでは?)は、ドラッグエフェクトを指定できるらしい。すくなくとも、規格では、そのように読める。

これは間違っているかも知れない。オレはドラッグエフェクト、あるいはドロップエフェクトの何たるかを知らんし、お前らも知らん。お互い様だ。

訳注:現行のHTML5ドラフトでは、「dropEffect属性は、ドラッグ&ドロップ中のユーザーが受けるドラッグ&ドロップフィードバックを指定する」と書いてある。名前はドロップなのに、ドラッグにも関係しているように読める。しかも、この文面だけでは、一体何のことなのか、さっぱり分からない。また、none, copy, link, moveという値を設定できるとも書いてあるが、それが何を意味するのかという規定はない。
規格の文面で、意味が何も言及されていない以上、「オレは知らんし、お前も知らん」、つまり誰も知らないのである。
このようにHTML5のドラフトは、まだ詳しく規定されていない部分や、未完成の文面が多々見受けられる。もちろん、まだドラフト段階であり、今後の議論により規定されていくのかも知れない。ただし個人的に思うのは、なぜ、未完成の文面の一部を、早々にドラフトに入れてしまうのかということである。例えば、別のペーパーなどで提案し、完成した段階でドラフトに入れる、という形を取った方が良いのでないのだろうか。

実験として、規格で規定されている値をすべて突っ込んでみたんだが、どのブラウザでも変化無しと来ていやがる。

で、ドロップエフェクト(あるいは、ドラッグエフェクトかもしれない)を許可するには、effectsAllowedをallにしておかなきゃならんってことに気がついた。ただし、何も変わりゃしねえ。ドラッグ(あるいはドロップ?)エフェクトを許可しても、どのブラウザもdropEffectに反応しない。

あるブラウザでは、effectsAllowdをallに設定した直後に、値はcopyLinkであると返してきた。何か根性らしきものを感じるね。

そもそも、なんでオレが許可を出さなきゃならないんだ? dropEffectをセットするということ自体が、オレが命令して(つまりは、許可を出して)、そのエフェクトを発現させるんじゃないか。

違うのか?

無言。

無言

クソが。もういい、オレは抜ける。

ストライキ

この上でまだ、ドラッグ&ドロップがクソだと思わないなら、Fransisco Tolmaskyの記事を読めば、ヤツの出くわしたバグと問題が載ってる。

ヤツの記事を読んでみると、どうもブラウザベンダーはドラッグ&ドロップを実装するのにトラブッているみたいなんだよな。

やれやれ、何でなんだろうな。

まあ、わざわざ知りたいとは思わんけどな。もうたくさんだ。

オレの知る限り、この記事で答えの出ていない疑問は、永遠に答えがでないだろうよ。オレはこのクソッタレなゴミ溜めに、もう二三日、無給で首を突っ込みたいとは思わん。

現状を変えたければ、どうぞご自分で研究してくんな。

あと、有益な記事とかサイトを教えてくれなくても好いぜ。もうどうでもいいし、どうせ読まないだろうから。

オレはストに入る。

ppkは、ドラッグ&ドロップに関して、相当辛酸を舐めたようだ。

追記:dropEffectという名前の属性や、その値である、none, copy, move, linkなどは、IEの実装上の都合らしい。
DROPEFFECT Constants (COM)

追記2:上記の追記からして、IEのこの機能の本来の目的は、IEとその他の外部との間のプロセス間通信としての、ドラッグ&ドロップなのかもしれない。それならなおさら、HTML5の規格からは取り除くべきである。Webとは関係がない機能だ。Webのドラッグ&ドロップというのは、もちろん、ページ内で完結しているドラッグ&ドロップのことである。たとえば、Google Readerには、フィードをフォルダという単位でまとめることができるが、その操作を、ドラッグ&ドロップで行える。

3 comments:

Anonymous said...

「dragoverとdragenterのデフォルトアクションは、要素をドロップさせないことである」とか、dropEffect属性が取るという値none, copy, link, moveの選択肢(dropEffectという名前自体も)などといった辺りから、Windowsの中身(API)をそのまま引きずり出してきた印象を受けました。そうやって、内部の実装の都合が表に出てくるのがMS製らしいなと感じます。

江添亮 said...

DROPEFFECT Constants (COM)
なるほど、確かにそのままですな。
自分は、COM周りは不勉強なので、知りませんでした。

しかし、この辺は、主にエクスプローラー上のファイルなどを想定しているのではないでしょうか。
Webブラウザ上で、要素を別の要素の上にドラッグしていくような場合には、あまりうまく当てはめられないような気がします。

以前、ドラッグ&ドロップを使おうとして、HTML5ドラフトの該当部分を読もうとしたことがあったのですが、さっぱり分からず断念したことがあります。
quirksmode.orgの人ですらこの有様になるとは。

現状では、ドラッグ&ドロップは、HTML5の規格に頼らない方が良さそうですね。

Anonymous said...

挙動といえば、imeを切るのもなぜかcss。
絶対におかしい。