“たとえばCSS Filterの動作サンプルを見てると、WebKitで実装されたCSS FilterがOperaとかMozillaがいつ実装するのかどうかってみんなは思うかもしれないけど、現在のあの仕様がそのまま全社が実装するとは思えない。FX TaskForceの活動の結果、共通化されたFilterの仕様が新規に決められることになるので、それを各社が実装することになる。そうしたほうが覚えるコスト少なくていいしね!”
Posts tagged "css"
CSSファイルをJSから非同期読込する方法
0-9:
CSSファイルをクライアントサイドだけで動的なURLつけて非同期読み込みしたい場合、単純に以下のようなコードを書くと同期読み込みになって読み込み完了まで他のファイルの読み込みがブロックされる。
(function () { var href = 'style sheet url'; var link = document.createElement('link'); link.rel = 'stylesheet'; link.href = href; var head = document.getElementsByTagName('head')[0]; head.appendChild(link); })();これに関しては以下のように別のiframeを作成して読みこめば非同期で読み込めるので、他のファイルの読み込みをブロックしない。
(iOS, Androidで動作を確認)(function () { var href = 'style sheet url'; var html = document.documentElement; html.style.display = 'none'; var iframe = document.createElement('iframe'); iframe.style.position = 'absolute'; iframe.style.top = '-100%'; iframe.style.left = '-100%'; var head = document.getElementsByTagName('head')[0]; head.appendChild(iframe); var doc = iframe.contentDocument; var win = iframe.contentWindow; doc.open(); doc.write('<html><head><title></title><link rel="stylesheet" href="'+href+'" /></head><body></body></html>'); win.addEventListener('load', function () { var link = doc.getElementsByTagName('link')[0]; head.appendChild(link); init(); }, true); win.addEventListener('error', init, true); doc.close(); var timeout = setTimeout(show_body, 1500); function init () { clearTimeout(timeout); html.style.display = ''; alert('load end'); } })();CSSは普通にhtmlに書いてある場合は非同期で読み込まれるので、もしかしたらdocument.writeなら普通に非同期で読んでくれるかもしれない。
クロスドメインの問題がない場合や、URLの解決等の問題がない場合は普通にXHRでtext読み込んで要素に書き込んでもいい
ChromeでSassがコンパイルした結果のCSSから元のSCSSの場所を見つける
Chromeのexperimentalな機能で、Sassのコンパイルした結果のCSSから、SCSSファイルを参照できるとかなんとかを試した。元記事はこれ
まずChromeで
chrome://flags
とかやるとなんか出るので、
Enable Developer Tools experiments
をオンにする。すると、webkit inspectorの設定に、Experimentalタブが追加されてる。その中で
Support for SASS
をチェック。
Sassのコンパイル時、
sass —debug-info hoge.scss hoge.css
って具合でデバッグ情報を出力するようにする。そんで、そのCSSを普通に読み込むと
あれ、これは・・・
オーマイガッド ジスイズクーール!
しかしこのためにCSSに元の部分がどれとか書きだされちゃうんで、ビルドツールつかって、デプロイ時には—debug-infoナシでコンパイルする必要はありんす。
box-shadow と filter: drop-shadow の違い
http://bricss.net/post/33158273857/box-shadow-vs-filter-drop-shadow
を見て日本語でも書いておこうと思って書いた。
でもサンプル見るほうが早いので(たぶん)わかりやすいサンプル作った。
サンプルは↓
スクショ↓
drop-shadowは見たままの影を作ってくれてます。
- 擬似要素で作った▼も影の形に反映され
- 透過PNGの透過部分は影にならず
- 文字もまるでtext-shadowのように。
素敵。
余談
2011年の12月頃にWebKit Nightly Buildsで-webkit-filterが実装されてました。
その頃作ったデモが↓
そして2012年の10月にはChrome、iOS6で-webkit-filterが使えるようになりました。
なぜかbox-shadowと似てると思われ、あまり注目を浴びないdrop-shadowが一番のお気に入りです。
“これを実装してほしいのは、やっぱりWebKitと、あとTridentだったりする。MozillaやOperaが大きめのCSS仕様を提案をすることがあまりないのと、Mozillaのみ、Operaのみサポートしてるプロパティ(拡張含む)はそこまで数も利用例もないので、@supportsを使ってまでっていう状況に出くわさない。
いっぽうWebKitはいろんなベンダーがいろんなものを追加しているし、MicrosoftもIE10から結構アグレッシブになってきている。
ベンダー固有の拡張だからよくない、というわけじゃないんだけど、標準化のスピードや他のブラウザへの実装が不透明になりがちなので、独自実装が入りやすいエンジンにこそ、オプトインでCSSを記述できるような仕組みが入って欲しい。
”
jsdo.itでScssを使おう
jsdo.itでScssが書けるようになりました!(やったね!
エディタのCSSタブ開いて、エディタの1行目に
/* #! scss */
って入れれば使えるようになるよ!
jsdo.itのブログでは一瞬しか触れられてないけどね!
(JSXやCoffeeScriptをサポートしたことについてはかいてあるけど)
いままでもCSSを直接参照する方法として
とかがあったけど
それで見ると、Scssが表示されるようなのでjsrun.itで見てみると
変換後のCSSが見れるみたいですねー。
どうせならCompassとか使いたいな~(チラッチラッ
余談
一応条件付きでjsdo.itのファイルを直接呼んだりすることもできますがScssで作った場合、ここに書いてある方法だとry
Tumblrでミラー
kottke.orgの真似をしてTumblrでこのWeblogの完全なミラーを作った。TumblrのDashboardで購読する用。リブログされたいとかスキされたいとかフォローされたいとかそういうのも勿論ある。あと緊急時の避難用とか面倒になった時の逃げ場とか……。検索避けされてる以外はほぼ同じはず。ミラーなのでタイトルはひっくり返した。
ミラーにはiftttを使った。ミラーであることを明記してもあんまり意味はない気がするので、特に何も追加したりしてない。iftttはTumblrの複数のブログを扱えないのはまだしも、Tumblrのパスワードが要求するのはどうにかしてほしい。ここらへんが改良されれば誰にでもオススメな感じ。
テーマはEffectorで、ちょっとだけCSSを書いてシングルカラムにした(HTMLはほとんど変えてない)。
.content-600 #page, .content-600 .inner { width: 600px; } .content-600 .right-sidebar #content { margin-right: 0; } #sidebar { display: none; }TumblrのテーマではEffectorが一番好きかなー。
こうやってTumblr等にミラーしたりするとURLの分散が起こってしまうのが難点なわけだけど、TumblrはTumblrの中で永久機関化される傾向が強いと思うので、検索避けするくらいでいいかなぁと。一応Permalinkではcanonicalで元記事のURLを吐くようにした。
{block:PermalinkPage} {block:Posts} {block:Link} <link rel="canonical" href="{URL}" title="{Name}" /> {/block:Link} {/block:Posts} {/block:PermalinkPage}を
head要素の閉じタグ直前に書いただけ。うまく出力されるようにはなっているけど、URLの分散に効果は……ないだろうな。SEOとかそういう面でもマイナス評価されかねないので真似しない方が良いと思う。ついでにリンクログもTumblrで作るようにした。Taberarelooのポスト先に追加しただけ。過去のブックマークのインポートは気が向いたらやる。
jQuery.fx.offですべてのアニメーションをカット
でも昔書いたのだけども、IE8以下ではopacityに対応していないので、jQueryでアニメーションしようとすると、色々なことが面倒。そこで、ばっさりIE8以下対応をさっさとやるのが以下。どうのこうのでブラウザ判別でもして
if (ieLessThan9){ jQuery.fx.off = true; }jQuery.fx.off = true にすれば、すべてのアニメーションが一瞬で終わるようになります。これでfadeした時でも一瞬で変わるから問題なしだぜイェイってねー。
※これはかなりUIに関するJSを書く必要があるケースを想定してます
おいおいおい、おれのクライアントはそんなので納得しないぜ?オイ?
とでもお思いですか?それは状況によりけりですよ。かかるコストとスケジュールと実現したいことで決めればいいんです。例えば、デザインが透過PNGだらけで、やりたいアニメーションをIE8以下向けに調節するのには相当の時間がかかってしまうことが見込まれる場合、普通に作るのと同じぐらいまでにはならないかもしれないけども、かなりの時間をかけて、ここはIE8以下はアニメーション無しでー、これはIE7以下はアニメーション無しでー…っていうようなコードをたっくさん書かないとダメですよ。そういう時、サービス残業してやるんですか? IE死ねとかツイートしながら。それは違うんじゃないんですかねー。どのブラウザではこういう特長があるからっていうのを始めに説明して、それに対応するには時間がかなり掛かることが見込まれるので云々って言っておき、工数を見積る材料にするべきですよ。その見積りだとIE8以下はアニメーションカットですねとかね。
あとはスケジュールが全然無いときとか。とりあえずIE8以下はアニメーション全てカットで完成させたらどうです?そこからIE8以下を細かく調節していったらいいんじゃないですかね。CSSが使われだした時、CSSを切ってもちゃんと見れるって、みんな重視してたでは無いですか。アニメーションを切ってもコンテンツは見れますよ。まぁ、広く見られるコンテンツであればサイトのアクセスログからブラウザの割合ぐらいは確認したほうがいいとは思いますけどね。
逆に、アニメーションをカットしたほうが良いこともあるんですよ。というのは、IE8以下は性能的にもかなり低いブラウザなので、色々一気にアニメーションさせちゃうと、そもそもサイトが重いーってんで辛いことも多いんです。そんな状態なら、逆にアニメーションを全部させないほうがサクサク閲覧できたりすることも多いですよ。
ということで、ひとつ、jQuery.fx.offでIE8以下アニメーション全カット - ってのを一つのボーダーラインとして考えてみるのはどうでしょう? もちろん開発者一人が勝手にそう思ってやりましたとか、後から言ってもダメですけど当然。
gruntで快適JS/CSSビルド生活
grunt というJS/CSSのビルドツールが便利だったので紹介します。(Mac/Linux)
このgruntってのは、JS,CSSを全部まとめて繋げる、まとめてJS lintする、minifyする見たいのをタスクとして登録しておくと、それ実行すればちゃちゃっとやってくれちゃうやつです。さらにwatchっていう機能使えば、ファイルが更新されたらそのタスクをやってくれるみたいなのも。
似たモノで、MakeとかRakeとかCakeとかそういうのがあります。多分、やってる人は前からやってるんですが、最近ちょっとCoffeeScriptをやり始めて、微妙に困ったことがあったので、どーすっぺと探してたら、これが自分にとってソリューションでした。
ここでは、3ステップでCoffeeScriptをコンパイルしてgrowlを出すところまでです。ここで使うサンプルは以下にまとめましたので必要であれば参考にでもすると良いかと思います。
とりあえず、gruntのインストールには、nodeとnpmが必要です。それインストールしたら以下を実行して準備OK。これでgruntコマンドが使える。
npm install -g gruntstep1: jsとcssまとめる。jsはminify
あーいっぱいcssとかjsとかあるけどまとめたい。さらにminifyもして欲しいわーという時。
. ├── common │ ├── css │ │ ├── _src # ここにcssのファイルら │ │ │ ├── style1.css │ │ │ ├── style2.css │ │ │ └── style3.css │ │ └── all.css # まとめたcss │ └── js │ ├── _src # ここにjsのファイルら │ │ ├── script1.js │ │ ├── script2.js │ │ └── script3.js │ ├── all.js # まとめたjs │ └── all.min.js # まとめたjsをminifyしたやつ ├── grunt.js # gruntの設定ファイル └── index.html上記みたいにディレクトリがあって、grunt.jsにこう書く。
config.init({ lint: { files : [ 'common/js/_src/script1.js', 'common/js/_src/script2.js', 'common/js/_src/script3.js' ] }, concat: { 'common/js/all.js' : [ 'common/js/_src/script1.js', 'common/js/_src/script2.js', 'common/js/_src/script3.js' ], 'common/css/all.css' : [ 'common/css/_src/style1.css', 'common/css/_src/style2.css', 'common/css/_src/style3.css' ] }, watch: { files: [ 'common/js/_src/script1.js', 'common/js/_src/script2.js', 'common/js/_src/script3.js', 'common/css/_src/style1.css', 'common/css/_src/style2.css', 'common/css/_src/style3.css' ], tasks: 'lint concat min' }, min: { 'common/js/all.min.js': [ 'common/js/all.js' ] } });そして、grunt.jsが置いてあるディレクトリまで行き、
grunt watchって打てばOK。_srcディレクトリに入れたファイルが更新されたらJS lintしてファイルまとめてminifyしてくれる。all.min.jsとall.cssを読み込んだがコレ。
step2: CoffeeScriptコンパイルし、jsとcssまとめる。jsはminify
やりたかったのがコレ。CoffeeScriptには、Cakeというビルドをまとめる方法があるんだけれども、CoffeeScriptまとめた後、他のJSとつなげたりどうのしたりっていうのが、なんか自分で書かないと行けないっぽかった。CoffeeScript使うとは言っても、他にjQueryプラグインだの何だのを使ったりするので、コンパイルしたファイルをまた他のとつなげたりしないといけない。なんかめんどいなーと思ってたら素敵grunt。
さっきのscript1.js、script2.jsをCoffeeScriptにした例。
. ├── common │ ├── css │ │ ├── _src │ │ │ ├── style1.css │ │ │ ├── style2.css │ │ │ └── style3.css │ │ └── all.css │ └── js │ ├── _src │ │ ├── script1.coffee # CoffeeScriptなファイル │ │ ├── script2.coffee # CoffeeScriptなファイル │ │ └── script3.js │ ├── _temp_coffeecompiled.js # コンパイルしたCoffeeScript │ ├── all.js │ └── all.min.js ├── grunt.js └── index.htmlgrunt.jsの中身はコレ
var proc = require('child_process'); config.init({ lint: { files : [ 'common/js/_src/script3.js' ] }, concat: { 'common/js/all.js' : [ 'common/js/_temp_coffeecompiled.js', 'common/js/_src/script3.js' ], 'common/css/all.css' : [ 'common/css/_src/style1.css', 'common/css/_src/style2.css', 'common/css/_src/style3.css' ] }, watch: { files: [ 'common/js/_src/script1.coffee', 'common/js/_src/script2.coffee', 'common/js/_src/script3.js', 'common/css/_src/style1.css', 'common/css/_src/style2.css', 'common/css/_src/style3.css' ], tasks: 'coffee lint concat min' }, min: { 'common/js/all.min.js': [ 'common/js/all.js' ] }, coffee: { 'common/js/_temp_coffeecompiled.js': [ 'common/js/_src/script1.coffee', 'common/js/_src/script2.coffee' ] } }); task.registerBasicTask('coffee', 'compile CoffeeScripts', function(data, name) { var done = this.async(); var command = 'coffee -j ' + name + ' -c ' + data.join(' '); var out = proc.exec(command, function(err, sout, serr){ if(err || sout || serr){ done(false); }else{ done(true); } }); });ここでは、coffeeというオレオレタスクをgruntに登録している。そんで、その中では、coffeeプロパティとして登録されたデータを見て、まとめてコンパイルするという流れになってる。そして、watch.tasksにcoffee lint concat minとすれば、さっきと同じ、ファイルが更新されたら、CoffeeScriptをコンパイル、JS lintして、ほかのJSと繋げてall.jsを作り、minify。こんな感じで、複雑なタスクもgruntを使えばかなり手軽に設定できる。(サンプル2)
step3: CoffeeScriptコンパイルし、jsまとめる。終わったらgrowl出す
Mac使ってる人ならほぼほぼ入れていると思われるgrowl。このgrowlは、インストーラに付いてるExtraを入れると、コマンドを打ってgrowlを出すことの出来る機能が追加される。【参考】
growlnotify -t "タイトル" -m "メッセージ"これを、ビルドが終わった時、CoffeeScriptのコンパイルが失敗した時に出す。構成はさっきと同じだけどcss外した。
. ├── common │ └── js │ ├── _src │ │ ├── script1.coffee │ │ ├── script2.coffee │ │ └── script3.js │ ├── _temp_coffeecompiled.js │ ├── all.js │ └── all.min.js ├── grunt.js └── index.htmlvar proc = require('child_process'); config.init({ lint: { files : [ 'common/js/_src/script3.js' ] }, concat: { 'common/js/all.js' : [ 'common/js/_temp_coffeecompiled.js', 'common/js/_src/script3.js' ] }, watch: { files: [ 'common/js/_src/script1.coffee', 'common/js/_src/script2.coffee', 'common/js/_src/script3.js' ], tasks: 'coffee lint concat min notifyOK' }, min: { 'common/js/all.min.js': [ 'common/js/all.js' ] }, coffee: { 'common/js/_temp_coffeecompiled.js': [ 'common/js/_src/script1.coffee', 'common/js/_src/script2.coffee' ] } }); task.registerBasicTask('coffee', 'compile CoffeeScripts', function(data, name) { var done = this.async(); var command = 'coffee -j ' + name + ' -c ' + data.join(' '); var out = proc.exec(command, function(err, sout, serr){ if(err || sout || serr){ proc.exec("growlnotify -t 'COFFEE COMPILE ERROR!' -m '" + serr + "'"); done(false); }else{ done(true); } }); }); task.registerTask('notifyOK', 'done!', function(){ proc.exec("growlnotify -t 'grunt.js' -m '\(^o^)/'"); });CoffeeScript書いてる時、エラーあるのが分かりづらいのでコレは便利!(サンプル3)
—
ほか、ファイルを繋げるときに好きにコメントを入れたりとかもできるので、なんか色々そういうのをやるときは融通が効きそう。ということで、ちょっとしばらく使ってみようと思う。サンプルのgruntファイルなんかもgithubに置いてある。
Bootstrap有害論
Bootstrapを使うと、複雑なCSSを書かなくても、綺麗な見た目のサイトを素早く作れて大変便利。なんだけど、UI的にはあまりよろしくない。はっきり言って、これは有害だ。
Bootstrapではタブやドロップダウンメニュー、モーダルダイアログといったUI要素を簡単に使えてしまうので、ついこれらに頼りすぎたUIになってしまう。これらのUI要素は、小さなウィンドウやモバイル機器のスクリーンといった狭い領域に情報を詰め込むための苦肉の策のようなもので、もし使わなくてすむなら使わない方が良い。タブとかドロップメニューがやたら多いアプリや管理画面ってだいたいゴチャゴチャしてて使いにくいですよね。
使いやすい画面を作るには、情報を取捨選択して、優先順位を考えて、適切な場所に情報を配置することが重要になる。けど、これらのUI要素を使うと好きなだけ情報を詰め込めんでしまえるので、情報の取捨選択をしなくなってしまう。さらに、優先度に応じて配置を変えることもできなくなってしまう。本来ならば、あれもこれも詰め込みたいところをグッと堪えて、優先度の低いものは思い切って切り捨てないといけない。考えなしにBootstrapを使うと、この「切り捨てる」作業が疎かになって、一瞬にして使いにくいアプリができあがる。
タブやドロップダウンメニューを使いたくなる気持ちはよく分かる。「この画面にこの機能を入れてよ」と上司やユーザーに言われたら、つい入れたくなってしまうのが人情で、その置き場所に悩んだ時に使ってしまうのがこいつらだ。みんなの意見の折衷案としてタブを使ってしまうことはよくありがち。だけど、それは多くの場合「考える」ことや「決断する」ことを止めてしまっているだけだ。
Bootstrapで特に有害なのがモーダルダイアログ。そもそもBootstrapに限らずモーダルダイアログは使い勝手を著しく損ねるので、どうしても必要な時以外は使うべきでない。これまではブラウザ上でモーダルダイアログを実装するのは面倒だったので、幸いにもあまり使われていなかった。ところがBootstrapではこのモーダルダイアログを簡単に作れてしまう上に、なんだかかっこいいエフェクトで表示されるので、つい使いたくなってしまう誘惑に駆られてしまう。BootstrapのTrapだ。
最初にも書いたとおり、Bootstrapは恐ろしく便利で魅力的だ。多くのWebエンジニアが待ち望んでいたものだと思うし、その名の通りWebサイト開発の立ち上げを助けてくれる。今後、色んなWebサイトで使われるようになるだろう。
Bootstrapは良い技術だと思っているだけに、そのせいで使いにくいWebサイトが増えてしまうのは残念に思い、あえてこんな釣りっぽい文章を書いてみた。Bootstrapのクールな見た目に吊られて、考えなしにBootstrapを使ってはいけない。
Tumblrのユーザーアイコンを円にしたりグロス効果を加えるカスタマイズ
どんなんかと言えばこんなん ↓ です。
テーマ<Single A>を使ってるTumblrで見たことあるかもしれません。
仕組み的なものですが、これCSSだけで表現していて、特に円にするための専用画像とかは使ってないんですね。
(※Single Aでは各アイコンを一つのボックスの背景画像に置き、CSS3のborder-radiusで切り抜いている)
このユーザーアイコンを円にする方法と、
他に角丸やグロス効果、トイカメラ風にしたり、ユーザーアイコンにいろんな加工をしてみるカスタマイズを記録。
と言っても流石にテーマごとにHTML構成が違うので、ここでは初期テーマ<Redux>のFollowingで遊んでみます。
IE 9以下に存在するセレクター数制限にはまった
開発中にいきなりCSSが壊れて原因を探っていたらこれに行き着きました。IE 9以下では1つのCSSファイル当たり4,095個までしかセレクターを認識しない。4,096個以上は無視される。ええええ。。MSにもページがある模様(@os0xさんに教えてもらった!)。
この問題は
- SCSSだと割とカジュアルにセレクター数が増える
- CSSは出来るだけ1ファイルにまとめたい(リクエスト数削減のため)
との組み合わせがやばい。SCSSはセレクターが他のページに影響しないように以下のように書いていました。
// 共通部分 @mixin foo { color: red; .foo { font-size: 2em; // たくさんの指定… ... } } // 影響範囲を以下のページのみに限定したい #page-a { @include foo; } #page-b { @include foo; color: yellow; } // 全ページに跨がる負の遺産 .foo { font-size: 5em; }これだと適用ページを増やそうと思うとページ倍にセレクターが増えることに。。共通で使うセレクターを安心して設定出来るようにきれいな環境にする必要があると思いました…。と言っていたら
extendを使うのもいいというアドバイスを頂きました。@yksk SCSSとか使ってるとカジュアルに超えますからね…。ちなみに、mixinじゃなくてextendにすれば、ある程度改善できると思いますよ alpha.mixi.co.jp/blog/?p=5737
— shogo ohta (@os0x) February 22, 2012一般的に問題になりそうなのはCSSの1ファイル化。対処方法としては溢れたら2ファイルに分ける、がありますw 1ファイル化後に毎回挙動が変わっていないかチェックするのは大変なので、セレクター数をチェック出来る仕組みがほしいところ。SCSSやCompass側で生成時に警告してくれたり自動的に分割するオプションがあるといいですね…。
IE 6、7、8、9と現行のIEでは必ず起こります。IE 10では直っているらしいです。
@yksk d.pr/fsYE一応スクショ。VirtualBox上のWindows 8 Developer PreviewでのIE10 PP4。
— Kyo Nagashima (@hell2u) February 22, 2012ちなみにIEにはCSSファイルを31個までしか読めない問題もあるので、たぶんページのセレクター数上限は126,945個になるんじゃないでしょうか…。確認はしてない。
- HTMLにインラインで書いたCSSでも起こるのか
- JSでセレクターを追加していっても起こるのか
辺りも特に調べていません。
reblogmachine wide and sukesuke style ( not wild style )
photo
quote
text
link
classやidに-を使うとか使わないとか のついでに
ずどさんがはまろぐってたからついでに。
昔いろいろ悩んでいた頃があって、前の会社にいたころいろいろ試してました。キャンペーンページのような、すぐ消えるであろうページだったのでいろいろやってました。
例えば「.」でつなげてみるとか。
<div class="mod.sample.vertical">サンプル縦長版</div>でもCSSも一手間加えないといけないのでやめました。CSSでは、「.」は普通には使えませんが、エスケープすれば使えます。
.mod\.sample\.vertical{ (snip) }あと、マルチバイト文字をクラス属性値にしてみたり。
<div class="大見出し">大見出し</div>.大見出し{ (snip) }マルチバイト文字は普通に使えます。たしか。
ただの文字列ですし、予約語とか気にせず好きにすればいいんじゃないですかね
“class/id の名前にハイフン区切りの文字列が使われているのはある程度歴史的経緯があります。
* CSS では、伝統的にプロパティの名前や擬似要素の名前などはハイフン区切りの文字列で統一されていました。
* CSS2 (CSS2.1 の1つ前の版)では、クラスセレクタ・IDセレクタの名前にアンダースコアを直に(エスケープせずに)含むことが文法的に許されていなかったのに対し、ハイフンは問題なく使用できました。
http://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#tokenization
* HTML4.0 (HTML4.01 の1つ前の版)では、要素の属性としてアンダースコアを含む文字列を指定する場合、クォーテーションマークを省略することが許されていませんでしたが、ハイフンを含む属性値に対してクォーテーションマークを省略することは許されていました。
http://www.w3.org/TR/1998/REC-html40-19980424/intro/sgmltut.html#h-3.2.2
(ただし、 HTML4.01/CSS2.1 ではアンダースコアを含んでも良いように文面が修正されました。おそらく世の中のページではアンダースコアがバンバン使われており、ブラウザもそれを受け入れていたために規格が修正されたのだと思います)
記事の筆者の方は他のプログラミング言語と比較されているようですが、 CSS はもともと文法的にハイフン区切りの文字列を推奨するように作られていた節があります。少なくとも、私の知る限り、ハイフン区切りの文字列が文法的に許可されていなかったことはありませんでした。
こういう経緯を見る限り、 class/id の名前にハイフン区切りの文字列を使うのは当たり前の帰結のように思えます。古い規格とは言えど、あえて文法違反を犯す必要はどこにもないですから……”








