Ruby on Rails チュートリアル
-
- 第1章CSSのあらまし
- 第2章「スタイル指定」の作法
- 第3章CSSの値: 色とサイズを指定する
- 第4章ボックスモデルを完全攻略する
- 第5章レイアウトを組み立てる
- 第6章ページのテンプレートとfrontmatterの書き方
- 第7章Flexboxで特殊なレイアウトページを構築する
- 第8章ブログを追加する
- 第9章モバイルとメディアクエリ
- 第10章細部を仕上げる
|
||
|
||
購入する |
CSS & Design
CSSを
学ぶチュートリアル
- 第1章CSSのあらまし
- 第2章「スタイル指定」の作法
- 第3章CSSの値: 色とサイズを指定する
- 第4章ボックスモデルを完全攻略する
- 第5章レイアウトを組み立てる
- 第6章ページのテンプレートとfrontmatterの書き方
- 第7章Flexboxで特殊なレイアウトページを構築する
- 第8章ブログを追加する
- 第9章モバイルとメディアクエリ
- 第10章細部を仕上げる
第2章「スタイル指定」の作法
私たちがCSSを操作するとき、主に「ブラウザ」と「テキストエディタ」という2つのレベルで考えるとよいでしょう。ブラウザ目線からすれば、CSSで「クラス」「id」のどちらが使われているかはどうでもよいことです。実際、ブラウザというプログラムの立場だけを考えれば、「ひと目で意味がわかる完璧なクラス名を持つ、非の打ち所のないほど美しいCSS」と「あらゆる要素にインライン方式スタイルを見苦しく付けて回るCSS」にはほとんど違いがありません1。
しかしテキストエディタ目線では、つまりテキストエディタでWebサイトのHTMLやCSSを書く人間にとっては、その違いこそが重要なのです。ブラウザというプログラムからすれば、CSSの書き方が人間にとってどんなにぐちゃぐちゃで見苦しかろうが混乱の極みであろうが2関係ありません。しかし人間にとってはそれこそが重要なのです。
さらに、ダメなCSSを放置しているとプロジェクト全体が最初から最後まで苦しめられ、コストや工数が何倍にも膨れ上がってしまいます。だからこそ最初が肝心、CSSの最初の1行を書くときが肝心なのです。「今さえよければいい」ではなく、「ここは今後必ず変更される」ことを肝に銘じて、常に書式を整えながらCSSを書くことです。
本章では、このような「スタイル指定のスタイル(作法)」を理解し身につけることに全力で集中します。サイト構築のできるだけ早い段階で、さまざまなパーツに良い名前を与えるコツ、適切に組み立てる方法を選ぶコツを学びます。これを会得すれば、HTMLやCSSのコードは驚くほど柔軟性が保たれ、今後サイトを改修する他の開発者(これには「将来の自分」も含まれます)が気持ちよくメンテナンスできるようになります。言い換えれば、未来の自分を苦しめないように、未来の自分が喜ぶようにCSSを書く方法を学ぶのです。
2.1 命名の技術
コンピュータサイエンティストPhil Carltonがかつてこんなことを述べました。「コンピュータサイエンスにおいて困難なものはたった2つしかない: キャッシュをいつ無効にするか(cache invalidation)と、適切な名前を付けることだ」。後者の「適切な名前を付ける」は、フロントエンド開発者にとっても重要な課題です。
クラスやidに名前を付けるときは、その「機能」や「目的」を思い浮かべながら行うようにするのが何かと便利ですし、実際多くの場合それが最適です。"box1"
はダメなクラス名の例です。3これでは大雑把すぎて、特に大規模なプロジェクトともなると今後再びこのbox1を見かけたときに「これって何だったっけ?」と思い出せなくなってしまうでしょう。たとえば"bio-box"
のようなクラス名の方が、これがページの特定の要素を指すことが名前だけでわかる、よりよい名前です4(コラム 2.1)。
クラスやidを使うということは、クラスやidの名前をひとつひとつ考え出すということです。生まれた子どもに良い名前を付けたり、ファンタジー小説で登場人物や地名やアイテムや事件に架空の名前を付けたりすることがどれだけ大変かを想像すればおわかりかと思いますが、命名はしんどい作業です。実際、プログラミングにおいてもっとも時間を取られるのが命名作業であるという調査結果もあります。
経験豊富なプログラマーほど、最初の変数名やクラス名を付けるときにかなり時間をかけて考え抜きます。そうまでする理由は「最初にダメな名前を付けてしまうと、それをお手本にしてダメな名前が次々に拡散してしまって後からの修正が難しくなり、後々ひどい悪影響が生じる」からです。逆に最初にいい名前を与えることができれば、他の作業者はその名前をお手本にするだけで短時間でもっと楽に名前を付けられるようになり、開発期間も短縮され、読みやすさも向上します。良い名前を付けるメリットはそれほどまでに大きく、ダメな名前を放置するデメリットも計り知れないほど大きくなります。だからこそ、特に最初の段階で良い名前を付けることに頑張る価値があるのです。
命名でひとつ重要なポイントがあります。クラスやidの名前に「その要素がページでどう見えるか」という見た目をそのまま取り入れるのは避けましょう。その理由を具体的な例で示します。たとえばテストページにある.bio-box
の末尾の項目で何らかの警告を表示したいとしましょう。具体的には、その人物のボックスの背景色を赤色に変えたいとします(リスト 2.1)。CSSスタイルではセレクタにスペース文字に続けてそのスタイルを追加します(リスト 2.2)。
.red
を.bio-box
に追加する index.html
.
.
.
<div class="bio-box">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box red">
<a href="https://example.com/">I'm a link</a>
</div>
.
.
.
.red
クラスのスタイル指定を作成する index.html
.
.
.
<style>
a {
color: red;
}
#exec-bio {
background-color: lightgray;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
.red {
background: red;
}
</style>
.
.
.
変更を保存してブラウザ画面を更新すると、末尾のボックスの背景色が変わるはずです(図 2.1)。
しかし後に、この赤色はやぱり警告用に使いたくないという決断が下されたとしましょう。そして今度は紫色にしたいとしましょう(色選びのセンスはこの際おいておきます)。そのときはプロジェクトファイルをエディタで開いて、CSSのbackground
プロパティの値をpurple
に変更します(リスト 2.3)。
index.html
.
.
.
<style>
a {
color: red;
}
#exec-bio {
background-color: lightgray;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
.red {
background: purple;
}
</style>
.
.
.
すると、red
というクラス名と画面上の紫色が一致しなくなってしまいます。これでは作業者が確実に混乱します(図 2.2)。
作業対象がこのテストページひとつであれば、このぐらいどうということはないじゃないかと思う方もいらっしゃるかもしれません。しかし、この要素がもしプロジェクト全体で繰り返し使われるようになったらどんなことになるか、ここでいったん立ち止まってよく考えてみましょう。そうなってしまったら道は2つです。工数が余分にかかるのを覚悟で「その要素をすべて見つけてクラス名を残らず修正する」か、工数が認められず「クラス名の修正は諦めて混乱するに任せる」かです。
このように見た目を安直にクラス名に取り入れるのをやめて、目的ベースで名前を付ける、つまりページのその要素はどんな意図で使われるのかを考え、その目的を名前に取り入れれば、"alert"
というずっとわかりやすい名前になります。この名前なら、警告の背景色を何色に変更してもびくともしなくなり、名前が表示と矛盾したり名前で作業者が混乱したりする心配もなくなります(リスト 2.4)。
index.html
.
.
.
<style>
a {
color: red;
}
#exec-bio {
background-color: lightgray;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
.alert {
background: purple;
}
</style>
.
.
.
<div class="bio-box alert">
<a href="https://example.com/">I'm a link</a>
</div>
.
.
.
リスト 2.4のような命名にしたことで、後に警告色を赤色から紫色に変更することが決定されても、作業者がコードを見たときに首をかしげることはなくなります。その他の例もご紹介します。クラス名を"small"
のような見た目をそのまま取り入れた名前にするのではなく、たとえば"collapsed"
(縮小)のように「機能」「役割」を表す名前を使いましょう。ユーザーが操作できなくなった要素を灰色で示すときには、"gray"
のような名前ではなく、"disabled"
(無効)のように抽象化した名前にしましょう。
もちろん物事には例外はつきものですし、最終的にどんな名前を付けるかはすべてあなた次第です。しかし、機能を取り入れた名前を付けるよう常日頃から心がけることがやはり肝心です。この習慣はぜひ身に付けてください(コラム 2.2)。
近年、クラス名の命名法を厳密に定めることが流行っていますが、それにはそれなりの理由があります。従来の命名法はプロジェクトによってそれこそ千差万別、てんでバラバラでした5。このような厳密な命名法は、プロジェクトが始まってから終わるまでの間に大勢の開発者が関わる大規模かつ長期のプロジェクトでよく採用されます(大企業が開発・運営しているWebアプリを想像してみるとよいでしょう)。
本チュートリアルでは、箸の上げ下ろしまでビシビシ締め付けるような厳密きわまる命名法を皆さんに押し付けるつもりはありません。しかし、そのような厳密な命名法が存在し、求められ、実際に用いられることもあることは知っておいて損はありません。今後フロントエンド開発に関わる機会が増えるのであれば、以下にリストアップしたいくつかの命名流派がどんなものかについて軽く知っておくのも悪くないでしょう。
- BEM (Block Element Modifier)
- OOCSS(Object Oriented CSS)
- SMACSS(Scalable and Modular Architecture for CSS)
これら流派のどれが役に立つかが重要なのではありません。プロジェクトや開発によっても変わるでしょう。重要なのは、何らかの手段でCSSの「一貫性」を保つよう頑張ることです。
2.2 クラスとidの使い分け
CSSを書くときには、「どんなときにクラスを使うべきか」「どんなときにidを使うべきか」についても考えて決めておかなければなりません。 1.5でも解説したように、idはページ内のただひとつの要素を指すためのものですが、クラスは複数の要素を指すことができます。HTMLの設計上、ひとつの要素に複数のクラス名をいくつでも(スペース区切りで)書けますが、ひとつの要素にはidをひとつしか書けないよう制約6がかけられています。しかし問題はここからです。クラスとidはブラウザ上での扱いが異なるのですが、クラスとidをどう使い分けるかで流派間の「聖戦」が勃発しがちなのです。
私たちは国連ではありませんので、使い分けの流派に対して中立の立場を保つわけにもいきません。本チュートリアルでは、クラスとidの使い分けについて以下の(最も妥当と思われる)立場をとります。
どうしても利用が避けられない場合(例: JavaScriptの都合で要素にidを指定しなければならず、かつJavaScript以外でidを使わない場合)を除いて、idは極力使わないようにすること。
1.5では最初のdiv
にidをわざわざ追加してそれに対してスタイルを指定したことを覚えていると思いますが、あれはあくまで説明のためのものであり、現場では一般にidの利用を避けるべきです。その理由は、スタイル指定にいったんidを使ってしまうと、(よほど見苦しいハックを駆使しない限り)そのスタイル指定を他のCSS宣言で上書きできなくなってしまうからです。
その理由を実例で説明します。リスト 2.5では、最初のdiv
に.alert
クラスが新しく追加されています。このdiv
には、#exec-bio
というidも指定されていることにご注意ください。さらに、警告色をred
に戻してあります。
index.html
<style>
.
.
.
.alert {
background: red;
}
</style>
.
.
.
<div id="exec-bio" class="bio-box alert">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box">
<a href="https://example.com/">I'm a link</a>
</div>
<div class="bio-box alert">
<a href="https://example.com/">I'm a link</a>
</div>
.
.
.
このコードを反映してブラウザ画面を更新してみてください。すると、最初のdiv
の背景色が赤色になりそうなものなのに、まったく変わっていないことに気づくでしょう。このとき、実際のブラウザ画面は図 2.1のようになります。
ここでの問題は、idで指定されたスタイルは、クラスで指定されたスタイルよりもブラウザ上での「詳細度(specificity)」が高くなるということです。CSSにおいて、詳細度の高いスタイルは、詳細度の低いスタイルを上書きします。逆に言うと、詳細度の低いスタイルは詳細度の高いスタイルに「負けてしまう」のです。CSSでは、この詳細度という「概念」をしっかり理解しておくことが重要です。
たとえるなら、CSSのクラスは小口径の銃口をたくさん備え付けたマシンガンのようなものであり、idはロケットランチャーのようなものです。マシンガンからいくら豆鉄砲をばらまいたところで、ロケットランチャーから発射された弾丸(つまりidで指定したスタイル)一発で勝敗はひっくり返ってしまいます。ざっくり言うと、idの方がクラスより全般に「強い」のです。
訳注: わかりにくいのですが、CSSの詳細度という概念は、CSSの「優先度(priority)」という概念と少し異なることにご注意ください。詳しくは本セクションで後述されます。
.alert
クラスのスタイルを効かせる方法のひとつは、詳細度を高くすることです。たとえば以下のように、CSS宣言のセレクタで、#exec-bio
というidと.alert
というクラス名を「両方とも持つ要素」を対象にスタイルを指定する方法が考えられます(リスト 2.6)。
index.html
.
.
.
<style>
a {
color: red;
}
#exec-bio {
background-color: lightgray;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
.alert {
background: red;
}
#exec-bio.alert {
background: red;
}
</style>
.
.
.
上のリスト 2.6のCSSでは、#exec-bio.alert
のようにidとクラスをつなげて一括でセレクタとして指定しています。つまりこの場合、リスト 2.5の最初のdev
に赤い背景色が表示されるようになります(図 2.3)。
上のようにスタイル指定のセレクタでidとクラスを組み合わせたことで、背景色の変更に成功しました。しかしこの方法は、idとクラスを両方持っている要素でしか使えないことにご注意ください。皆さんが(運悪く)idによるスタイル指定を使いまくっているWebサイトで長期間作業するようなことがあれば、この方法でidに勝つ(つまりidで指定されたスタイルを上書きするピンポイントのCSS宣言を書く)ようになってくるかもしれません。しかし、このようなその場しのぎのやり方は、効果的にCSSを使う方法としてベストとは言えません。もっと優れた方法はあるのです。
長期的に見てより優れた方法は、「モジュール化」を取り入れることです。つまりWebサイトのフロントエンドを設計するときや開発するときに、あたかもレゴブロックを組み立てるときのようにWebサイトの各種パーツを組み上げられるようにすることです。パーツをレゴのようにモジュール化して扱えるようにしておけば、ある要素にあるクラスを追加してスタイルを指定するときに、クラスが確実にその要素に効くことに自信を持って作業できるようになります。
念のために申し上げておくと、ブラウザ内では最終的にCSSのさまざまなスタイル宣言が合流しますが、互いに衝突しているプロパティをブラウザ内部で一定の規則に基づいて並べ替え、それによって最終的な詳細度が決定されます。つまり、より「強力なスタイル宣言」がオブジェクトのすべてのスタイルを上書きするのではなく、その「強力なスタイル宣言」に囲まれているプロパティのみを上書きすることを意味します。先ほどから雑に手を加えている.bio-box
クラスのすべてのプロパティは、リスト 2.7では一様に適用されています。
.bio-box
に影響するすべてのスタイル
#exec-bio {
background-color: lightgray;
}
.bio-box {
border: 1px solid black;
}
.alert {
background: red;
}
#exec-bio.alert {
background: red;
}
ブラウザ内部では魔法を駆使して、これらのスタイル指定をひとつに合流させ、互いに矛盾するスタイル指定を自動的に解決します。リスト 2.7の場合、最終的にリスト 2.8のような形のスタイル指定がブラウザ内部で生成されます(ここでは、使われなくなったスタイル指定がCSSのコメント構文でコメントアウトされていますが、これについて詳しくは 2.4で解説します)。
{
/* background: red; */
/* background-color: lightgray; */
background: red;
border: 1px solid black;
}
#exec-bio.alert
のようにidとクラスを組み合わせたことで詳細度がクラス単独やid単独の場合よりも高まり、それによって1行目のbackground: red
という大雑把なスタイル指定と、2行目ももう少し詳細なbackground-color: lightgray
というスタイル指定が上書き(つまりコメントアウト)されています7。
どのスタイル指定を優先するかをブラウザがどのように決定しているかを、もう少し詳しく見ていきましょう。
2.3 優先度と詳細度
CSSは、さまざまな場所に配置されているさまざまなスタイルシートを集約してひとつのドキュメントに適用したときに、表示が致命的に破壊されないよう設計されています。その結果生まれたのが、 2.2でやってみたような、互いに矛盾するスタイル宣言を順当に解決するための「優先度(priority)」と「詳細度(specificity)」を決定するシステムです。
これらをもう少し詳しく理解するために、リスト 2.9のようなよりシンプルな例を見てみましょう。ここでは、ボックスの幅を決めるwidth
の値をパーセントで指定しています(パーセント記法の扱いについて詳しくは 3.4で解説します)。
index.html
.
.
.
<style>
.
.
.
.bio-box {
width: 75%;
}
.bio-box {
width: 50%;
}
</style>
.
.
.
テストページのstyle
の内容を上のように更新してブラウザ画面を更新してみると、ページ下半分のボックスのサイズは(75%ではなく)50%になります。つまり、リスト 2.9の1番目のスタイルではなく、2番目のスタイルが適用されたのです(図 2.4)。このルールは次のように一般化できます。「CSSスタイルが衝突した場合は、最後に出現したスタイルが適用される」、つまりこのような場合は「後勝ち」になります。
CSSの優先度ルールについては表 2.1に完全なリストをまとめてあります。この表を丸暗記する必要はありませんのでご心配なく。CSSの修行を重ねるうちに、優先度のしくみを身体で覚えられるようになるでしょう。さらに申し上げれば、この中でぜひとも理解しておかなければならない優先度ルールは「3」および「5〜8」しかありません。
なお、冒頭のルール1とルール2は最後の手段に取っておくべきです。これらは最後の最後になるまで利用を避けてください。ルール1についてはコラム 2.3で解説します。ルール2は、使えば使うほどコードがメンテしづらくなります。
ルール4とルール9は、Webサイトの開発者からコントロールしようがありません。
1 | 最優先 | 値の後ろに!important を追加する (例: width: 100% !important )ことであらゆるスタイルを上書きできる(ただし!important の利用は禁じ手とする: コラム 2.3) |
2 | インライン方式 | 要素の中でスタイルをstyle= で直接指定する |
3 | Media Type | メディアクエリ経由でスタイルを指定した場合(詳しくは第9章で) |
4 | ブラウザのユーザーがカスタム定義したスタイル | 多くのブラウザにはこの「ユーザー定義CSS」のようなアクセシビリティ機能がある |
5 | セレクタの最終的な詳細度 | クラスやidで指定したスタイルは、一般的なスタイル指定を上書きする |
6 | 後勝ちルール | 最後に出現するスタイルが優先される |
7 | 親からの継承 | 子でスタイルが指定されていない場合は親のスタイルを継承する |
8 | クラスやidを使わないCSS | 外部/内部スタイルシートやページのstyle ブロック内にあるCSSのうち、クラスやidを使わないで要素だけを指定したスタイル |
9 | ブラウザのデフォルトCSS | ブラウザ内部に組み込まれている最小限のCSSであり、最も優先度が低い |
「なるほど、でも優先度がまったく同じでスタイルの異なる2つ指定を適用したら、一体どうなるんですか?」という疑問が浮かぶ方もいらっしゃるでしょう。その場合は、優先度と同時に、もうひとつ別の概念である「詳細度(specificity)」も考慮する必要が生じます。詳細度は、このように同じ優先度の中で複数のスタイル指定がかち合う状況を解決するのに用いられます。
ここで最も基本的かつ重要な点を押さえておきましょう。詳細度とは、あくまで「要素の指定方法を詳しくすればするほど(指定を増やして具体的に絞り込めば絞り込むほど)、それに応じてブラウザ上でそのスタイル指定の強さがアップする」という意味でしかありません。
たとえば、すべてのa
要素を灰色にする大雑把なスタイル指定を考えてみましょう(リスト 2.10)。
a {
color: gray;
}
上のやる気のない大雑把なスタイルの詳細度は、実はクラスやidを使わなくても少しアップできるのです。仮に、h1
ヘッダーの中にあるa
タグのリンク文字をすべて緑色にしたいのであれば、リスト 2.11のように書けます。
h1 a {
color: green;
}
最初のa
というセレクタより、h1 a
(つまりh1
の内側にあるa
を指す)の方が指定が1個増え、その分少しだけ詳しくなっています。つまり指定を増やしたことで対象がその分絞り込まれています。そのためh1 a
の方が詳細度が高くなり、リンク文字は灰色ではなく緑色になります(これは既に 1.11で使ったテクニックですね)。
表 2.2に、ブラウザでさまざまなセレクタに割り当てられる詳細度の「点数」をリストにしたものです。詳細度は表の下に行くほど高くなるので、下のスタイルは上のスタイルを上書きするということになります。
ところで、表 2.2の詳細度の番号付けは、先の表 2.1のシンプルな優先度順位付けと違って、何だかごちゃごちゃしています。というのも、詳細度では普通の順位付けではなく、「カンマ+数字」という独特の記法を用いる順位システムを採用しているからです。何ともややこしいですよね。残念ながら、詳細度を普通の順位付けに変更してこの問題を解決してくれるような奇特な開発者もいそうにありませんが、念のためこの表も掲載することにしました。
要素を1個だけ指定したシンプルなHTMLセレクタ | em {color: #fff;} |
1 |
他の要素の内側にある要素を指定するHTMLセレクタ | h1 em {color: #00ff00;} |
2 |
CSSクラス名 | .alert {color: #ff0000;} |
1,0 |
HTML要素にクラス名を直結 | p.safe {color: #0000ff;} |
1,1 |
CSS idのみを指定 | #thing {color: #823706;} |
1,0,0 |
CSS idとクラス名を両方指定 | #thing .property {color: #823706;} |
1,1,0 |
インライン方式 | style="color: transparent;" |
1,0,0,0 |
これだけではもう何が何だかよくわかりませんよね。
実を言えば、詳細度のこの謎ルールを完全に理解している人は開発者にすらほとんどいませんのでご安心を。その代わり、次のようなもっと簡略化した「掟」に従っています。いわく「CSS宣言は極力シンプルかつ一般的に保つべし」「それでできない場合はクラスを用いるべし」「idでスタイルを指定するべからず」「!important
は禁じ手とする」といった具合です(コラム 2.3)8。そのうち皆さんもこの謎ルールが腑に落ちるようになりますのでご心配なく。
訳注: Specificity Calculatorというサービスを使うと、セレクタの詳細度を計算したり比較したりできます。
!important
は最終手段
!important
(なお発音するときは「!」を含めません)を追加して無理やりスタイルを効かせるのは、CSSスタイル指定におけるもうひとつの定番の悪手として知られています。確かにこれを追加すれば、どんなに言うことを聞かない頑固なスタイル指定でも自動的に上書きできます(表 2.1)。!important
については「これを使うしかない状況に追い込まれたら、それまで蓄積したスタイル指定は完全な失敗である」ぐらいに考えるべきです。
!important
の何が問題かというと、ひとたびこれに頼り始めると麻薬中毒のようにやめられなくなってしまうことです。というのも、!important
を追加したスタイルをさらに上書きしようとすれば、上書きする側のスタイルにも!important
を付けて無理やりねじ伏せる以外に方法がないからです。このようにCSSが!important
だらけになって手に負えなくなる現象は「CSSのトリブル化9」と呼ばれています。
「トリブル増えた...」
スタイル指定で!important
を使いたい誘惑にかられたら、必ず立ち止まって他の方法を検討してください。その方が確実によい方法です。誘惑に負けてしまえば、皆さんの同僚や未来の自分に恨まれること請け合いです。
!important
がどういうものかが理解できましたので、ただちに皆さんの記憶から完全に消去してください。
「お前は何も見なかった」「私がここにいたこともだ、いいな?」
CSSが複雑怪奇になって、スタイルをひとつ変えただけでさまざまなページでスタイルがぶっ壊れてしまうような悲惨な状況を避けるための方法はいくつか考えられますが、そのひとつは「セレクタをできるだけシンプルに保つこと」です(リスト 2.12)。言うことを聞かせようとするあまり、セレクタにあれやこれやを追加してこじらせてはいけません(リスト 2.13)。
.bio-box a {
color: green;
}
.alert {
background: red;
}
body div#exec-bio.bio-box a {
color: orange;
}
最後に勝つのは、たいてい「シンプルさ」です。
2.3.1 演習問題
-
!important
をあえて使い、.alert
クラスの背景色を赤色に変更してください(作業前に#exec-bio.alert
スタイルを削除しておくこと)。 - 上の演習問題1で行った変更を元に戻し、もう一度コラム 2.3を読み返しましょう。
-
.bio-box a
のリンクの文字色を変更してください。ただし、既存のcolor
プロパティを変更するのではなく、同じセレクタをもうひとつ下に追加して、そこでcolor
をpink
に変更すること。
2.4 スタイル指定の一級市民になろう
では、コードを読む人の認知に負担を強いず、複雑な優先度ルールや詳細度ルールを正しくコントロールしながらCSSセレクタを縦横に使いこなす、そんな優秀な開発者になるにはどうすればよいのでしょうか?手始めに、 2.2で解説した概念を取り上げます。
クラスはレゴのように組み合わせ、結果を容易に予測できるようにしましょう。
モジュール化を取り入れた設計を選び、スタイル指定をひとつのモジュール内に完全に閉じ込めてサイトの他の部分に影響しないようにしましょう。
何かをモジュール化するときは、「それをどこに配置するか」「それがどんな状態か」に応じて方法が少し変わってきます。
ひとつの要素にクラスを複数書くこと自体はクラスセレクタの正当な使い方ですが、だからといってページ内の要素には必ずクラスを書かなければいけないなどと早とちりしないでください。時と場合によっては、要素にクラスを複数書くのが悪手になることもあるのです。クラスが少なすぎたり多すぎたりしないよう、バランスを見極めましょう。
本チュートリアルでこれまで指定してきたスタイルでは、なぜ.bio-box
の中にあるリンクには独自のクラスを特に追加していないのか気になる方がいるかもしれません。もちろんリンクに独自のクラスを書くことは可能ですし、書いたところで何か問題が発生するわけでもありませんが、これはスタイル指定において意見の分かれる部分のひとつでもあり、必ずこうすべきとは言い切れません。これを判断するのに役立つ方法のひとつは、スタイル指定を「グローバルスタイル(サイト全体の一貫性を演出するためにさまざまな場所で多用される)」と「個別のセクション(機能やコンテンツが自己完結したモジュール)」という2つのカテゴリに分けて考えることです。
たとえば、Webサイト内でひとつのボックスにつき必ずリンクをひとつ含むような箇所に、上述の.bio-box
を指定することが決まったとしましょう。そうした箇所は、繰り返し用いられるレギュラーのモジュールになります。このような場合は個別のリンクにクラス名をわざわざ書かなくても、単に「.bio-box
の中にあるa
タグ」を対象として、より一般的なスタイル指定を適用するという方法が考えられます。これなら、新しいスタイルをあちこちで追加して回らずに済みます。ただし、そのボックスの中にリンクをもうひとつ追加することになったら、2つ目のリンクのスタイルを1つ目のリンクのスタイルと同じにしてよいのか、それともいけないのかを検討して決定しなければなりません。後者の場合は、おそらく他の方法で要素を指定する必要があるでしょう。
それではページにコンテンツを少し追加して、このアイデアを具体的に実践してみましょう。ダミーの.bio-boxes
をリスト 2.14のマークアップに置き換えてください。このリストにはページのマークアップ全体を収録しているので、ここまでの作業や演習問題でズレが発生していてもここで取り戻せます。
特に、新しいマークアップには例のexec-bio
idが含まれていないことにご注目ください。 2.2で解説したように、idは最後の手段なので、絶対的に必要でない限りidは使わないことをおすすめします。また、CSSのスタイル指定も整理してスリムにしてあります。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Test Page: Don't Panic</title>
<meta charset="utf-8">
<style>
a {
color: red;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
</style>
</head>
<body>
<h1>I'm an h1</h1>
<ul>
<li>
<a href="https://example.com/">Link</a>
</li>
<li>
<a href="https://example.com/">Link</a>
</li>
<li>
<a href="https://example.com/">Link</a>
</li>
</ul>
<h2>I'm an h2</h2>
<div class="bio-box">
<h3>Michael Hartl</h3>
<a href="https://twitter.com/mhartl">here</a>
<p>
Known for his dazzling charm, rapier wit, and unrivaled humility,
Michael is the creator of the
<a href="https://www.railstutorial.org/">Ruby on Rails
Tutorial</a> and principal author of the
<a href="https://learnenough.com/">
Learn Enough to Be Dangerous</a> introductory sequence. Michael
is also notorious as the founder of
<a href="http://tauday.com/">Tau Day</a> and author of
<a href="http://tauday.com/tau-manifesto"><em>The Tau
Manifesto</em></a>, but rumors that he's secretly a supervillain
are slightly exaggerated.
</p>
</div>
<div class="bio-box">
<h3>Lee Donahoe</h3>
<a href="https://twitter.com/leedonahoe">here</a>
<p>
When he's not literally swimming with sharks or hunting powder stashes on
his snowboard, you can find Lee in front of his computer designing
interfaces, doing front-end development, or writing some of the
interface-related Learn Enough tutorials.
</p>
</div>
<div class="bio-box">
<h3>Nick Merwin</h3>
<a href="https://twitter.com/nickmerwin">here</a>
<p>
You may have seen him shredding guitar live with Capital Cities on Jimmy
Kimmel, Conan, or The Ellen Show, but rest assured Nick is a true nerd at
heart. He's just as happy shredding well-spec'd lines of code from a tour
bus as he is from his kitchen table.
</p>
</div>
<div class="bio-box">
<h3>??</h3>
<p>
The Future
</p>
</div>
</body>
</html>
変更結果を保存してブラウザ表示を更新すると、ページ下半分にあるボックス内のリンク文字がすべて緑色に統一されたことがわかります(図 2.5)。
訳注: 既にお気づきの方もいるかと思いますが、本チュートリアルのスクリーンショットでは基本的にMac版Safariブラウザを利用していますので、Chromeブラウザなど他のブラウザで表示すると、デフォルトのフォントが図と異なる可能性があります。ブラウザやOSのデフォルトフォントはときどき変更されることがありますので、ブラウザやデフォルトフォントが変わっても同じフォントで表示するには別途工夫が必要になります。これについて詳しくは本チュートリアルで後述されます。
リスト 2.14を見返してみると、バイオグラフィーごとにその人物のTwitterアカウントへのリンクがひとつずつ含まれていますが、このTwitterリンクは他のリンクとスタイルを変える方がよさそうです。リンクのスタイルについては今後も本チュートリアルで改良を繰り返しますが、さしあたって今はTwitterリンクの色だけを青色にし、他は緑色のままにすることにします。
リンク文字を上のように変更する方法のひとつは、リンクがp
(パラグラフ)タグの内側にある場合にのみリンク文字を緑にするよう、スタイルの対象を変更することです(リスト 2.15)。
index.html
.bio-box p a {
color: green;
}
この変更によって、Twitterリンクが赤色に変わりました。この赤色は、リスト 1.10で指定したアンカータグ全般を対象としたスタイル指定によるものです。p
タグの内側にあるリンク文字は無事緑色のままになっています。
さて、このあたりでそろそろ「セレクタは3つまで」の原則についてお話しすることにしましょう(コラム 2.4)。
理由はいくつかありますが、ひとつのCSS宣言内に書くセレクタの数は一般に「最大でも3つまで」に抑えておくのがよい方法です。現在のサンプルページのようなウルトラシンプルなページであればおそらく楽勝ですが、現場で複雑なWebサイトを扱っているとセレクタの数が増え続けて手に負えなくなることもあります。
セレクタの数を増やさない方がよい理由のひとつは、セレクタが少ない方が明らかに読みやすいからです。セレクタが短ければ短いほど、作業者がCSSの広いセクションの中から該当箇所を見つけやすくなります。
もうひとつの理由はブラウザ内部のしくみ(実装)によるものです。ブラウザはCSSのセレクタを「右から左」に読み取るので、「セレクタの数が多い」かつ「使うセレクタが大雑把(つまりクラスやidでない一般的な要素)」であればあるほど、ブラウザが画面上でレンダリングするときの負荷が増加します。
これは一見直感に反しているように思われがちです。ここまで学んできた方であれば「え?普通に考えてブラウザはセレクタを左から右に読み取って、そのたびにスコープを順に絞り込んでいくんじゃないの?」と推測するのも無理はありません。しかし技術的な理由によってブラウザはそのようになっていないのです。
つまり、#first-table tr td h1
というセレクタでスタイルを指定するとブラウザで次のように処理されます。
1. ブラウザはまずページをくまなくスキャンしてh1
がページ内のどこにあるかをすべて識別します。
2. 次もまたページをくまなくスキャンしてtd
タグがページ内のどこにあるかをすべて識別します。
3. 次もまたページをくまなくスキャンしてtr
タグがページ内のどこにあるかをすべて識別します。
4. 最後にやっと、#first-table
というidによって対象となる要素が絞り込まれます。
訳注: ブラウザがスキャンする対象は、厳密にはページのマークアップそのものではなく、マークアップを論理的に圧縮する形で木構造に変換したDOM(Document Object Model)です。また、このような内部実装はブラウザによって異なる可能性もあります。
ページ内の要素が極端に増えてくると、この種の非効率性によってページのレンダリング(描画)速度がかなり落ちる可能性があります。私たち開発者のためにも、ブラウザを見ているユーザーのためにも、セレクタの数を増やさないよう普段から心がけておくのは有用です。
リスト 2.15では将来の変更作業で手こずらないようにする方法に注目していただく必要があったので、スタイル指定そのものはこれでも問題ありません。しかしせっかくなので、詳細度ルールをうまく適用して、例の「セレクタは3つまで原則」(コラム 2.4)を今後も破らずに済む、より変更に強い手法に差し替えましょう。
そのためには、先のスタイルセレクタを.bio-box a
に戻し、すべてのTwitterリンクに.social-link
クラスを追加します(リスト 2.16)。
index.html
.
.
.
<a href="https://twitter.com/mhartl" class="social-link">here</a>
.
.
.
<a href="https://twitter.com/leedonahoe" class="social-link">here</a>
.
.
.
<a href="https://twitter.com/nickmerwin" class="social-link">here</a>
.
.
.
続いて、このリンクにスタイルを指定する新しいクラス宣言をCSSにひとつ追加します(リスト 2.17)。新しいクラス宣言は、.bio-box a
宣言の下の適当な場所に置けます。
index.html
.
.
.
a {
color: red;
}
.bio-box {
border: 1px solid black;
}
.bio-box a {
color: green;
}
a.social-link {
color: blue;
}
.
.
.
これで、パラグラフ内のリンク文字はすべて緑色のままで、SNSリンク文字がいい感じの青色に変わりました(図 2.6)。
実は、.bio-box a
のような「クラス名」「タグ名」をスペース区切りで並べたセレクタよりも、a.social-link
のように「タグ名」「クラス名」をスペースなしで直結したセレクタの方が詳細度が高くなるのです。
試しにa.social-link
からa
を取り去って.social-link
というセレクタにすると、リンク文字が緑色に戻ります。理由は、セレクタが2つでクラスが1つの.bio-box a
(緑色のリンク文字)の方が、セレクタが1個のクラスである.social-link
(青色のリンク文字)よりも詳細度が高いからです。
さて、この初歩的な練習の大事な点はどこだかおわかりでしょうか?
リンク文字を何色にするかは別に重要ではありません。しかし、プロジェクトの初っぱなでセレクタの詳細度を見誤ってしまうと、後々プロジェクトで問題を引き起こしてしまいます。今回のいかにも初心者向けのシンプルなコード例ですら、将来そのページで開発するときに「しこり」を残さないために、事前に考えておかなければならない点が山ほどあります。繰り返しますが「最初が肝心」なのです。最初の段階で選択ミスをやらかしてしまい、元のコードが大雑把すぎたり制約が強すぎたりした場合、いつの日かプロジェクトをいったん停止して引き返し、コードを全面的に書き直すはめになりかねません。
たとえば、リンク文字を緑色にするのに.bio-box p a
というセレクタを使っていたとします(既に3つもありますよね)。後になって、そのリンクを文字ではなく画像に変えて欲しいという注文を受けたとします。このセレクタにimg
を単純に足すと.bio-box p a img
のように4つになってしまい、セレクタが深くなってしまうので、そのためのクラスを該当の画像すべてに改めて追加しなければならなくなるでしょう。画像がせいぜい数個程度であれば、img
要素にクラスを追加して回るのは大した手間ではありませんが、画像の数が多い場合は面倒な作業です。
p
タグに.bio-box
クラスを直結してp.bio-box a
とすれば、セレクタの深さが2になるので、これらの問題をすべて回避することも可能です。しかしこの場合、今後パラグラフが複数になったらどうしますか?p
を足すたびにクラスを付け忘れないよう常に気をつけなければならなくなりますし、そういう要素が大量に増えてくるとマークアップがごちゃついてストレスがたまるでしょう。
簡単な解決方法は、そのテキスト部分全体をdiv
タグで囲んで.bio-copy
のようなクラス名をそこに追加し、それから.bio-copy a
セレクタでdiv
タグ内のリンクを選択し、.bio-copy img
セレクタでリンク画像を選択することです。
それでは、より正確にスタイル指定を狙い撃ちできるよう、クラス名を持つ要素でテキストコンテンツを囲むとどうなるかを実際の例で見てみましょう。ここでは、各バイオグラフィーの原稿(copy)を新たにdiv
タグで囲み、.bio-copy
クラスを与えています(リスト 2.18)。4つ目の.bio-box
クラスにはまだa
タグはありませんが、今のうちに.bio-copy
クラスを追加しておきましょう。
div
で囲んで狙い撃ちしやすくするindex.html
.
.
.
<div class="bio-box">
<h3>Michael Hartl</h3>
<a href="https://twitter.com/mhartl" class="social-link">here</a>
<div class="bio-copy">
.
.
.
</div>
</div>
<div class="bio-box">
<h3>Lee Donahoe</h3>
<a href="https://twitter.com/leedonahoe" class="social-link">here</a>
<div class="bio-copy">
.
.
.
</div>
</div>
<div class="bio-box">
<h3>Nick Merwin</h3>
<a href="https://twitter.com/nickmerwin" class="social-link">here</a>
<div class="bio-copy">
.
.
.
</div>
</div>
<div class="bio-box">
<h3>??</h3>
<div class="bio-copy">
<p>
The Future
</p>
</div>
</div>
.
.
.
ここで、ちょっと気の利いた工夫も加えましょう。リスト 2.17のa.social-link
というスタイル宣言はすべての.social-link
を対象としていますが、あくまでこのスタイル指定を使い続けようとすると、ひとつ気にかかる点があります。「ある要素の.social-link
にスタイル指定する場合、その要素が実はリンクでない可能性はあるだろうか?」これは一見妙な疑問に思えるかもしれません。しかし、a
タグでないものにリンク用のスタイルを指定することは、実は意外によくあるのです。
リンクでないものをリンクにする例として、ナビゲーションメニューのリンクがあります。ナビゲーションメニューにさまざまなリンクが置かれている場合、「現在表示しているページそのものにジャンプするリンクは無効にしたい(クリックしても効かないようにしたい)」「でもそれ以外のリンクは有効にしたい」ということはよくあります。このような場合、無効にしたリンクは何らかの方法によってa
タグではなくなりますが、それでもそのリンクは他のリンクと同じスタイルを継承する必要があるでしょう。
実は、先ほどのa.social-link
のようにa
と.social-link
を直結したセレクタにしてしまうと、このようにa
タグがあったりなかったりする場合に都合が悪いのです。
a.social-link
のような直結を避けて.social-link
クラスでリンクのスタイルを指定できるようにするには、現在の大雑把なセレクタを見直し、リスト 2.18の.bio-copy
クラス名を活用して対象をより絞り込むべきです。つまり、リスト 2.12で適用した.bio-box
による現在のスタイル指定を、以下のように対象をより絞り込んだスタイル指定に変更するということです。影響を受けるのは、ボックスの.bio-copy
セクション内にあるリンクだけです。
.bio-copy a {
color: green;
}
ついでに、直結のa.social-link
セレクタもシンプルな.social-link
に変更してしまいましょう。
.social-link {
color: blue;
}
本章で学んだすべてを盛り込んだ最終的なCSSをリスト 2.19に示します。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Test Page: Don't Panic</title>
<meta charset="utf-8">
<style>
a {
color: red;
}
.bio-box {
border: 1px solid black;
}
.bio-copy a {
color: green;
}
.social-link {
color: blue;
}
</style>
</head>
<body>
.
.
.
</body>
</html>
ここで行った変更は単なるCSSのリファクタリングなので、見た目は何も変わらないはずです(図 2.6)。
いよいよ最後の仕上げです。今後作業する人の助けになるよう、わかりやすいCSSコメントをいくつか追加します。このとき、CSSスタイル指定を「グローバル」「SNS」「バイオグラフィー」というカテゴリに沿ってに並べ直してから、CSSコメントでタイトルを追加しましょう。このようにCSSに一手間加えておけば、後々読みやすく、探しやすく、編集しやすくなります(コラム 2.5)。
コメントを追加した結果をリスト 2.20に示します。これもフルページなので、手元のマークアップとのズレを取り戻すのにもお使いいただけます。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Test Page: Don't Panic</title>
<meta charset="utf-8">
<style>
/* グローバルスタイル */
a {
color: red;
}
/* SNSスタイル */
.social-link {
color: blue;
}
/* バイオグラフィースタイル */
.bio-box {
border: 1px solid black;
}
.bio-copy a {
color: green;
}
</style>
</head>
<body>
<h1>I'm an h1</h1>
<ul>
<li>
<a href="https://example.com/">Link</a>
</li>
<li>
<a href="https://example.com/">Link</a>
</li>
<li>
<a href="https://example.com/">Link</a>
</li>
</ul>
<h2>I'm an h2</h2>
<div class="bio-box">
<h3>Michael Hartl</h3>
<a href="https://twitter.com/mhartl" class="social-link">here</a>
<div class="bio-copy">
<p>
Known for his dazzling charm, rapier wit, and unrivaled humility,
Michael is the creator of the
<a href="https://www.railstutorial.org/">Ruby on Rails
Tutorial</a> and principal author of the
<a href="https://learnenough.com/">
Learn Enough to Be Dangerous</a> introductory sequence. Michael
is also notorious as the founder of
<a href="http://tauday.com/">Tau Day</a> and author of
<a href="http://tauday.com/tau-manifesto"><em>The Tau
Manifesto</em></a>, but rumors that he's secretly a supervillain
are slightly exaggerated.
</p>
</div>
</div>
<div class="bio-box">
<h3>Lee Donahoe</h3>
<a href="https://twitter.com/leedonahoe" class="social-link">here</a>
<div class="bio-copy">
<p>
When he's not literally swimming with sharks or hunting powder
stashes on his snowboard, you can find Lee in front of his computer
designing interfaces, doing front-end development, or writing some of
the interface-related Learn Enough tutorials.
</p>
</div>
</div>
<div class="bio-box">
<h3>Nick Merwin</h3>
<a href="https://twitter.com/nickmerwin" class="social-link">here</a>
<div class="bio-copy">
<p>
You may have seen him shredding guitar live with Capital Cities on
Jimmy Kimmel, Conan, or The Ellen Show, but rest assured Nick is a
true nerd at heart. He's just as happy shredding well-spec'd lines
of code from a tour bus as he is from his kitchen table.
</p>
</div>
</div>
<div class="bio-box">
<h3>??</h3>
<div class="bio-copy">
<p>
The Future
</p>
</div>
</div>
</body>
</html>
当たり前の話のようですが、皆さんの書いたコードを今後目にするであろう人類を気遣う優しい心が少しでもあれば、CSSの荒ぶる神がお怒りにならないためにも、ぜひ以下を心がけていただくよう謹んでお願いいたします。いつか必ずあなたの身を助けます。
どうか常日頃からCSSのスタイル指定を上述のようにきちんと分類してあげてください。
ひとつのグループに含まれるスタイル指定が、常にサイトの同じパーツを対象とするよう、ばらつくことのないよう心がけてください。
一言二言でもよいので、グループの意味がひと目でわかるCSSコメントをグループごとに付けてやってください。
訳注: 上記以外のコメントをソースコードにみだりに追加すると、逆にノイズになって他の作業者の迷惑になる可能性が高まりますので、業務では原則として避けましょう。慣れないうちはついソースコードのコメントに走り書きしたり言い訳を書きたくなったりするものですが、そこをぐっとこらえて、「GitHub issueに書く」「Gitのメッセージに書く」「GitHubリポジトリのコメント機能を使う」「チャットで相談する」など他の方法を検討しましょう。具体的な方法は職場やプロジェクトによって異なるので、わからない場合はまずプロジェクトリーダーに問い合わせましょう。
CSSコメントは、以下のように/* */
の内側に書けます。10
/* homeページ向けスタイル */
CSSコメントはブラウザには表示されませんが、ここでひとつご注意。ユーザーがブラウザでソースコードを表示すれば、HTMLやCSSのコメントも丸見えになってしまいます。CSSコメントに恥ずかしいことを書いたり、顧客の悪口や秘密を書いたりするのはやめておきましょう。
本チュートリアルではこれより、CSSのグループごとに/* homeページ向けスタイル */
のような形式でコメントをしばしば追加します。スタイルを既存の特定のグループに加える必要がある場合は、この形式で都度指定します。
/* homeページ向けスタイル */ . . . .some-style { }
具体的には、「このスタイルは/* homeページ向けスタイル */
に置いてください」と指定したときは、CSSの既存のグループのタイトルの後ろ(つまりドットが縦に並んでいる行)のどこかに置いてください。
ただし、続けて同じグループに別のスタイルを追加するときは、簡略化のためグループ名を指定しません。
2.4.1 演習問題
-
div
要素全般を対象として、border: 1px solid green
というボーダースタイルを指定してください。作業後にブラウザを更新すると、.bio-box
を除くすべてのdiv
に緑色のボーダー(枠線)が表示されるはずです。次に、そのセレクタをdiv.bio-box
に変更して保存し、ブラウザ表示を更新して結果を確認してください。 -
h1
要素に.social-link
クラスを追加し、ブラウザ表示を更新して結果を確認してください。h1
はリンクではありませんが、リンクと同じ色に変わるはずです。 - 同ページのCSS(
style
セクション)の冒頭にhtml{background:red;}
をCSSコメントとして追加してから、ブラウザ表示を更新して結果を確認してください。結果を確認したら、今追加したコメント冒頭の/*
をわざと削除し、ブラウザ表示を更新して結果を確認してください。ページの表示がまるで変わってしまうはずです。コメントの開始タグ/*
と終了タグ*/
は常に対応させることが大事です。
"box1"
のように名前に数字を安易に含めると、ダメな名前になりやすい傾向があります。たとえば"box1"
だけでは全部でいくつ名前があるかがわからないのが困った点です。一般に命名では、同じ要素が複数あってもできるだけ数字を使わないようにする方がよい書き方につながります(数字を使わずに扱う方法は今後学習します)。特に、"a1"
のような「意味のない名前」と「数字」の合わせ技は、確実にダメな名前です。background
宣言では、さまざまな背景色指定オプションが組み合わせられます。詳しくはStack Overflow(英語)のQ&A『What is the difference between background and background-color』をどうぞ。/* */
のすぐ内側のスペースはなくても動作は変わりませんが、統一のため常に上のように内側にスペースを両側に1個ずつ置くことをおすすめします。
Railsチュートリアルは YassLab 社によって運営されています。
コンテンツを継続的に提供するため、書籍・動画・質問対応サービスなどもご検討していただけると嬉しいです。
研修支援や教材連携にも対応しています。note マガジンや YouTube チャンネルも始めたので、よければぜひ遊びに来てください!