Twitter Bootstrap を使う際に a:link などに color を設定するとボタンの色まで上書きされちゃう問題の対策

1年ぶりくらいに更新しますが、引き続きクロコスにおりまして (てかこの前の記事が去年の7月なんでその後ヤフーに買収されるなどいろいろあったりしましたが) 、まあまあ元気にやっております。

      • -

さて本題。普段 CSS 書くときは大抵、 Twitter Bootstrap からいくつかの LESS をインポートしつつ、必要に応じてスタイルを上書きする形式をとっています。
そんな中、なんかどうしてもボタン(buttons.less でスタイルをあてているやつ)の文字色が反映されない状況に陥りまして、なんでだろうと調べて一応解決したので書いておきます。

問題の概要

今回のケースでは、デフォルトの文字色を次のように設定していました。

@import "bootstrap/buttons.less";

a, a:link {
  color: #666666;
}
a:visited {
  color: #999999;
}

Bootstrap では .btn クラスをつけるとボタンの形式になり、 .btn-primary のようなボタンに意味を付与するクラスをつけると意味に応じた色がつく、といった仕組みになっています。

/* bootstrap/buttons.less */
.btn {
  ...
}
.btn-primary {
  color: #ffffff;
}

で、例えばこの状態で次のようにHTMLがあるとします。

<p><a href="#">いえーい</a></p>

<p><a href="#" class="btn btn-primary">いえーい</a></p>

実際にこの状態で画面を見てみると次のようになります。

f:id:Fivestar:20131113204105p:plain

.btn-primary を設定しているのに文字色が #ffffff になっていません。

僕は最初、「CSS は要素よりもクラスの方が優先度が高いはずなので .btn-primary が適応されないのはおかしい」と思ってしまったのですが、よくよく調べたら擬似クラスもクラスと同じだけ重み付けされるんで、「要素 + 擬似クラス」と「クラス」の差で a:link などのスタイルが単なるクラスのみの指定である .btn-primary より優先されてしまった、ということでした。

対策

で、最初は .btn に疑似クラスや要素をつけて上書きする方法を考えたのですが、無駄な感じでやりたくないなーと思って別の方法を探した結果、否定疑似クラス (:not()) を使えばもっとも簡単に制御できるという結論にいたりました。

a:not(.btn), a:link:not(.btn) {
  color: #666666;
}
a:visited:not(.btn) {
  color: #999999;
}

このようにしておくと .btn の色に干渉することがなくなるので、デフォルトのボタン色がそのまま使われるようになります。

f:id:Fivestar:20131113205539p:plain

Bootstrap みたいな CSS フレームワークを用いる際、特定のスタイルに干渉してほしくない場合なんかは :not() 知っておくとよさそうです。