latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

CSSのセレクタ部分(IDやCLASS)にハイフンとか使われるの好きじゃないなー。ボクはあまり好きじゃないなー

CSS の ID 名や CLASS 名の単語の連結にハイフンを使うべき、キャメルケースとかアンダーバーとかダメ」的な主張を去年ぐらいにどこかで読んだ記憶があるのですが(うろおぼえ)、

/* たしか… これがオススメのスタイルで */
.hoge-huga-piyo {...} 

/* これとか… */
.hoge_huga_piyo {...}

/* これはイケてない(らしい) */
.hogeHugaPiyo {...}

個人的には「ちょっとそれ CSS に寄り過ぎてて、視野せまくないかー」という考えをもっていたので、つらつらと書いてみます。

E:first-child や E[key|="value"] などのハイフンを前提とした構文に関してはもちろんありですよ。ここで取り上げてるのは、属性セレクタや擬似クラスセレクタについてではなく、IDセレクタ と CLASSセレクタ についてです。

本来のハイフンの働き

ハイフンは、連語(複数の単語から構成される言葉)をつなぐ記号として、
また紙面の都合で改行する場合にハイフネーションとして使われるものです。
# 他にも用法あるけど省略

CSS は単独で生きられない

CSS は HTML や JavaScript と別れて生きられません。
CSS超兄貴といえども、それだけではご飯が食べられないのです。

サーバサイドで生成するなら Java,Perl,Ruby,Python,PHP のルールも意識する必要があるでしょう。

CSSだとこう書けるから!」と独自性を追求するよりも、宿主(LL言語)の作法に倣うと良いのではないでしょうか。

プログラマー的用法

以下(↓)は、一連の単語の「単語と単語の区切りをどう表現するか」をロジックにしたものです。

function getJointMethod() {
    var method = "スペースで単語を区切る";

    if (PascalCaseが推奨されている) {
        return "PascalCaseで単語をつなげる";
    }
    if (camelCaseが推奨されている) {
        return "camelCaseで単語をつなげる";
    }
    if (Uppercaseが推奨されている) {
        return "Uppercaseで単語をつなげる";
    }
    if (スペースが利用できない) {
        method = "アンダーバーを使って単語をつなげる";
    
        if (アンダーバーが利用できない) {
            method = "ハイフンを使って単語をつなげる";
        }
    }
    return method;
}

ハイフン(-)は、大抵のプログラミング言語で「演算子」です。
CSS3 でもプログラミング言語と同様に、ハイフンを演算子として解釈する文脈もあります。

CSS = ハイフンを積極的に使うべき」という認識は個人的には無く、ハイフンが自然な場所ならハイフンを使います。

            
E > F > G { background-color: red     }
---------   ----------------  -------
selector        property       value

            -------------------------
                     declaration

---------------------------------------
                rule

むしろ、property の部分に登場する文字列は全て CSS(とベンダープリフィクス付き)の予約語なのだから特別にハイフン付きのキーワードが使えるのであって、ユーザはハイフンを使うべきではないのでは?とも考えています。selector 部分にはハイフン使わなくてもアンダーバーでいいでしょと。

言ってる事がよくわからないけど、どういうこと?

えと、

  • JavaScript では変数名に $ を勝手に使うのは重大なルール違反です(でした)(ES5でECMA側が折れた)。
  • C/C++ では __ (アンダーバー2個) で始まる識別子を勝手に使うのは重大なルール違反です。

これらはパーサーやコンパイラを書く人の都合を考えて、規格書レベルで厳格にルール化されています。

CSS はそういうルールは特にないようですが(無いのかな? あんまり自信ない)、
以下のようなケースでは、
予約語を ID や CLASS に書かれちゃうと、( ´・ω) (´・ω・) えーと? (・ω・`) (ω・` ) ってなります。

  1. CSSやHTMLをオンラインで編集できるエディタを js で作るとします
  2. そのエディタは { に対して } が少ない(書きかけで対応がとれていない)コードであっても、解釈できる範囲で頑張ってカラーリングするとします
  3. 編集中の(壊れている状態の)CSSであっても、js で内容をリアルタイムにパースして表示しようとすると、速度的にゴニョりたくもなります

とかね。

これ(↓)だと極端な例ですが、言いたい事はつたわるかなと。

/* 邪悪なCSS */
<style>
.font-size{font-size:20pt}
.background-color{background-color:gold}
</style>
<p class="font-size">20pt</p>
<p class="background-color">gold</p>
「いやーキャメルケースとか読みづらくて苦手なんすよねー」とか

むむむ、きっとプログラム書くよりも、他の事やってるほうが幸せになれると思います。

「ハイフン区切り(a-b-c)が読みやすい」と言うのであれば、アンダーバー(a_b_c)でも読みやすさはさほど変わらないはずです。

キャメルケースが嫌ならアンダーバーで良いのでは無いでしょうか?

昔は CSS でアンダーバーが使えなかったからー という Pentium 3 時代の記憶

10年前なら「ネスケが…」だったのですが、現在はそんな知識は不要ですし、むしろ JavaScript と連携するならハイフンは邪魔です。

ネットスケープはアンダーバーどころではなく CSS の解釈自体が破綻していたという事も、ぜひ思い出してください。

ハイフン区切りは保守性が悪い

簡単にハイフンを含むワードが選択できないという問題

私が使っているエディタでは、ハイフンを含むワードはダブルクリックで選択できません。
しかし、アンダーバーで連結されたワードはダブルクリックで一気に選択できます。

これは私のエディタだけに限らず、Chrome の IDE などもそのような動作をします。
Vim でも同様に、ハイフンを含むワードは、選択もコピペも無駄に手間がかかります。

多くのシーンでは、検索するために選択したいだけだったりするのに、ハイフンがあると無駄に手数が増えますね。

a-b-c ← これは一気に選択できない

a_b_c ← これは一気に選択できる

プログラムを書く上では、ハイフンで連結したコードは「非効率」なのです。

一貫性

JavaScript と連動するなら、JavaScript で使いやすいような ID名や CLASS名にしてくれないと困ります。

// CSS で使っている名前と JavaScript で使っている名前に一貫性が無い書き方

<style>
.hoge-huga-piyo {...}
</style>
<script>
//  hoge_huga_piyo <- .hoge-huga-piyo 
var hoge_huga_piyo = document.querySelector(".hoge-huga-piyo");

//  hogeHugaPiyo <- .hoge-huga-piyo
var hogeHugaPiyo = document.querySelector(".hoge-huga-piyo");
</script>

(↑)などと書かれていると、検索に引っかからず修正漏れとか発生します。

「そういうもの」って考える人もいるでしょうが、これってただの無駄です。
最初から統一してください(↓)。

// CSS で使っている名前と JavaScript で使っている名前に一貫性が有る書き方

<style>
.hoge_huga_piyo {...}
</style>
<script>
//  hoge_huga_piyo <- .hoge_huga_piyo
var hoge_huga_piyo = document.querySelector(".hoge_huga_piyo");
</script>


// または

<style>
.hogeHugaPiyo {...}
</style>
<script>
//  hogeHugaPiyo <- .hogeHugaPiyo
var hogeHugaPiyo = document.querySelector(".hogeHugaPiyo");
</script>

CSS という狭い領域の中で一貫性があったとしても、
CSS/HTML/JavaScript/サーバサイド言語が絡むシステム全体で一貫性がなければ意味がありません。
1つの物を示す ID が2つあるのは間違いの元です。

仮に
  • JavaScript が絡まず、HTML からしか参照されないスタイルの ID / CLASS 名はハイフンで区切っても良い。 (.hoge-huga-piyo)
  • JavaScript と連動する要素は camelCase を使う。 (.hogeHugaPiyo)

というアイデアもあるかもしれませんが、それこそ一貫性がなくなります。

生産性優先? 保守性優先?

コードは生産される(書かれる)時間に対して、保守・メンテナンスする時間が圧倒的に長いものです。
書く人はたった1人でも、少なくとも10人には読まれるでしょう。
1時間で書いたコードが、数年間も生き残るのはザラにあることです。
# その時コードの原作者はもっと楽しい仕事をしている事でしょう

経験上、保守性(検索性)を無視して、自分勝手に「書きやすいから」「オレが見やすいから」とオレオレワールドを展開するプログラマーは、そのうち「忙しい」と、誰かに押し付けたりするものです。

一週間しか公開しないとか、誰も見に来ないようなサイトであれば、
保守性を無視して生産性を追求するのもやぶさかではないのですが、
その繰り返しに未来があるとも思えません。

結局

CSS だろうが、JavaScript だろうが、C++ だろうが原則は一緒です。

業務で使うコードのスタイルは、個人の好き嫌いという主観では決められません。保守を考えて言葉を発するべきです。

趣味のコードなら、おもいっきり自由でいいと思います。

反対ばかりして対案はないのかと

はい、ここからそれ書きます。

"js" プリフィクス付けてます

年季が入ったサイトだと、

  • js 詳しくないデザイナーさんが、イベント終了と共に js から見ている HTML と CSS をがっつり削って js がエラーになったり
  • ヘルプで入ってくれたコーダーさんが引継ぎされてないもんだから js から見ているスタイルをまるごと削っちゃって js がエラーになったり

といった感じで無駄に js のエラーが作り出され、その原因を探ったら「…またやられた」という事が多々あると思います(あります!)。

「このスタイルは JavaScript から見てるよ。削るとJavaScript側で問題がでるよ」と、
デザイナーさんやコーダーさんに意識させるために、
削られると問題になるような識別子には "js" プリフィクス付けてます。

この(↓)ように

<style>
#jsPreview {...} /* camelCase style */

.js_list_style_xxx {...} /* snake_case style */
</style>

<div id="jsPreview"></div>

<ul>
  <li class="js_list_style_xxx"></li>
</ul>

<script>
var jsPreview = document.querySelector("jsPreview");
</script>

これ、一定の効果がありました。

jQuery のように「要素が見つからなければ何もしない」というざっくりな方針でゴミを見逃し続けると、チリツモで大変な事になるんだわ…

uupaa.js (ver 0.8) には「存在しない node にスタイルや属性を設定しようとして assert が発動すると、強制的に document.body.style.backgroundColor = "red";」という強烈なデバッグ機能がありまして…

おまけの昔話し

10年前、とあるプロジェクトで、

入社3年目元気ハツラツ A君 C言語三項演算子がどうにも読みづらくて苦手なのでコーディングルールで禁止しましょう!!」
中堅 Bさん 「いやいや、数少ないショートコードのチャンスをどーして奪うんだ! ただでさえダラダラと長いんだぞ!」
いつも直球? Eさん 「おまえは今、三項演算子大好きなオレに Excelを使うな、Wordを使えって言ったようなもんだぞ(謎」
嫌々チームリーダーな Cさん 「ぼくは反対だなー、どうしてもっていうならルールに従うけど、ぼくは反対だなー」
uupaaの飼育員 「突然どうしたんですか?」
窓際 Dさん 「… (タバコ吸いにいく)」

という、和気あいあいなエンジニアトークがあったのを思い出しました。

話をよく聞くとA君が言いたかったのは、多段化された三項演算子がイヤだと

// これはいいけど
a = b ? c : d;
// 括弧の対応もよくわからないような、これ(↓)は無理
a = b ? (c ? d : e) : d ? f : g ? h : i;

いう話で、それについては極力なくそうと言う感じにルール化されました。とさ

// 括弧入れても、やっぱりよく分かりません。
a = b ? (c ? d : e)
      : (d ? f
           : (g ? h : i));

おしまい。
# 犯人は B さんね


「いやーそれは違うわー」という反論とか対案とか、
「それいいわー」とかあれば(あるのか?)、
Twitter まで どうぞー @uupaa