!importantの誘惑
2012年2月13日(月曜日)
!importantの誘惑
公開: 2012年2月25日23時5分頃
こういう状況がありました。
- コンテンツ内に、クリックすると動いたり出たり消えたりする物体がある。
- その物体の動作はjQueryの animate() fade() などで制御されている
- 特定の画面幅になったときに、その物体を非表示にしたい。
特定の画面幅のときに要素を消すというのは、Media Queries (www.w3.org)を使ってdisplay: noneにすれば良いだけで、とても簡単です。
……と、思いきや、うまく行かずに難航。調べてみると、消したい要素にstyle属性でdisplay:blockが指定されており、CSSファイル内に書いたdisplay:noneがの指定が負けていたのでした。
jQueryで要素を表示したり非表示にしたりするメソッドは、要素に対してにdisplay:blockやdisplay:noneをセットすることがあります。これはstyle属性でつくので、意外なところにstyle属性がついていて、勝てない場合があるという話です。
CSSで普通にdisplay:noneを指定しても、style属性のdisplay:blockに打ち勝つことはできません。実は昔のCSS2ではstyle属性の優先度ははっきり書かれていなかったのですが、CSS2.1では明記されています。
- count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
- count the number of ID attributes in the selector (= b)
- count the number of other attributes and pseudo-classes in the selector (= c)
- count the number of element names and pseudo-elements in the selector (= d)
というわけでstyle属性が最強です。Selectors Level3ではどうかというと、
Note: the specificity of the styles specified in an HTML style attribute is described in CSS 2.1. [CSS21].
以上、Selectors Level 3 9. Calculating a selector's specificity より
「CSS2.1を見ろ」というスタンスで、つまりはCSS2.1と同じくstyle属性最強です。"CSS Style Attributes" にもこういう記述があります。
The declarations in a style attribute apply to the element to which the attribute belongs. In the cascade, these declarations are considered to have author origin and a specificity higher than any selector. CSS2.1 defines how style sheets and style attributes are cascaded together.
以上、CSS Style Attributes より
どう転んでもstyle属性最強です。そこで一瞬だけ脳裏をよぎったのが……「!importantを使えば勝てる」という考え。
宣言の後ろに!importantをつけると、普通のスタイル (Author normal style sheets) を上書きできるので、勝つことができるようになります (CSS Cascading and Inheritance Level 3 9. Computing weight (www.w3.org))。
しかし、!importantは禁断の技です。単独のページを作るときならともかく、汎用的なコンポーネントを設計している時に使うべきではありません。そんなことをすると、運用者がカスタマイズできなくなって困ることになるからです。!importantをつけると、それだけで複雑なルールにも勝てますが、他の人が後でこのルールに勝とうとしたとき、地雷を踏むことになります。
しかし、!importantを使ってしまえば、目前の課題はあっさり解決する上、運が良ければ問題が発覚することもない、というのも事実。
誘惑としばらく戦って、結局、このように解決することにしました。
- style属性がつく要素の親要素となるようなdivを挿入する
- そのdivをdisplay:noneする
display:noneに限って言えば、親要素に指定すれば子孫要素は全部消えます。子孫要素のstyle属性でdisplay:blockが指定されていても関係ないわけです。
どうせstyleがつくのはJavaScript有効の時だけですから、スクリプトでdivを入れて、そのdivにMedia Queriesで良い感じのスタイルが当たるように調整して完了。
今回は!importantの誘惑を何とか回避できましたが、危ないところでした。
- 「!importantの誘惑」にコメントを書く
関連する話題: Web / HTML / CSS / JavaScript
- 前(古い): OCNで他人のメールパスワードが変更できた話
- 次(新しい): UDID取得は業界の常識!?