CSS
CSS3

css hacks for IE11 ( & Edge )

続編

続編(?)を投稿しました。

はじめに

2017年04月にVistaのサポートが終了したことで、
一般向け(?)WindowsOSのIE10以下のサポートが終了したのですが、
とはいえ、MS社に振り回される状況は依然続くわけなので、
IE11 と Edge の css hack を考察してみることにしました。

2017年07月時点のhackです。
ご利用は自己責任の上でお願い致します。

結論

素人の結論を先に記載しておきます。

IE11 only

_:-ms-lang(x)::-ms-backdrop, .selector {}

Edge only

_:-ms-lang(x)::backdrop, .selector {}

demo
code

-ms-high-contrast & -ms-backdrop

@media all and (-ms-high-contrast:none) {
    *::-ms-backdrop, .selector {
        color: blue;
    }
}

IE11の css hack を検索すると、検索結果の上部に出てくる上記のhackですが、
当時はそういうもの、として、あまり深く考えていませんでした。
上記は二つの部位で構成されていますが、各々どういう役割でしょうか。

@media all and (-ms-high-contrast:none) {}
-ms-high-contrastのhackはIE10以上用のhackとして有名(?)です。
なのでIE9以下を切る役割なのでしょう。

*::-ms-backdrop, .selector {}
では上記の役割は?

-ms-backdrop

MSDNを見てみます。
ちんぷんかんぷんですが、重要なのは中段の表です。

IE11未満は未実装
IE11はベンダープレフィックスが必要
Edgeはベンダープレフィックスが不要

と記載されています。

んっ!?、なら以下だけでよくね?

*::-ms-backdrop, .selector {}

IE11反応あり、Edge反応なし、Chrome反応なし、Firefox反応なし、Safari(iOS)反応なし。
(・∀・)イイ!!

念の為、
IE11のドキュメントモードを変更して旧IEの反応も見ていきます。
IE10とIE9とIE8までは反応ないのですが、
IE7とIE5は、カンマの実装方法が違うのか、反応します。
(・A・)イクナイ!!

-ms-high-contrast & -ms-backdrop

つまり、
@media all and (-ms-high-contrast:none) {} => IE11,IE10
*::-ms-backdrop, .selector {} => IE11,IE7,IE5
これを同時に指定することで、IE11のみが反応する、という状態のようです。

-ms-fullscreen

ちなみに、
::-ms-backdrop と同時期に実装されたと思われる
:-ms-fullscreenも同様の実装状況となっており、
::-ms-backdrop と同様のhackが出来そうです。

*:-ms-fullscreen, .selector {}

media queries & -ms-backdrop

しかし、
IE7以下が反応しなければよいわけですから、
@media all and (-ms-high-contrast:none) {}
の箇所は検討の余地がありそうです。

そもそも、
-ms-high-contrastどうこう以前に、
IEのメディアクエリの多くの実装はIE9からです。

IE7以下を切る役割であれば、
@media all and (-ms-high-contrast:none) {}
などとする必要はなく、
レスポンシブ時によくお世話になる、
@media all and (min-width:hoge) {}
@media all and (man-width:hoge) {}
などを利用すればよいだけなのかと。
( ただし @media all {} @media {} だけではだめ... )

@media all and (min-width:0px) {
    *::-ms-backdrop, .selector {
        color: blue;
    }
}

-ms-backdrop & root

ただ、出来れば、
@media@support を使用せず、
ワンライナー的にいける方法が欲しいところです。

IE7以下が反応しないhackで、すぐ思い浮かぶのは :root hack です。
:root はIE8以下未実装なのでIE7,IE5は反応しません。
ただ、詳細度が変化してしまうのが玉にきずです。

*::-ms-backdrop, :root .selector {}

-ms-backdrop & -ms-lang

次に思い浮かんだのは、
IE10以上用hackである_:-ms-lang(x),の利用です。
これと組み合わせてみたところ、うまくいきました。
詳細度の変動もないはずです...

*::-ms-backdrop, _:-ms-lang(x), .selector {}

ところで、
先頭の *_ とはなんでしょうか...

asterisk

*全称セレクタだと思いますが、
以下が*::-ms-backdrop,の自分なりの解釈です。

例えば、
* { color: blue; }
こうすると全要素の文字が青くなります。
*::after { color: blue; }
こうすると全要素の::afterの疑似要素の文字が青くなります。
ということは、
*::backdrop { color: blue; }
こうすると全要素の::backdropの疑似要素の文字が青くなります。
( ::backdropがどんな要素なのかは知りませんが... )
*::-ms-backdrop { color: blue; }
こうすると全要素の::-ms-backdropの疑似要素の文字が青くなります。
( ::-ms-backdropが実装されたブラウザであるIE11のみ )

また、
a, p { color: blue; }
こうするとa要素とp要素の文字が青くなります。
a::after, p { color: blue; }
こうするとa要素の::afterの疑似要素とp要素の文字が青くなります。
*::after, p { color: blue; }
こうすると全要素の::afterの疑似要素とp要素の文字が青くなります。
この時、
::afterの疑似要素は絶対使用しない、と、取り決めしたとします、その場合、
*::after部分に反応する要素は絶対ないので、
*::after, p { color: blue; }p { color: blue; } は同じ効果になります。

では、
*::-ms-backdrop, p { color: blue; }
の場合はどうでしょうか。
::-ms-backdropの疑似要素、使いますか?、使わないよね?、使わないなら、
*::-ms-backdrop, p { color: blue; }p { color: blue; } は同じ効果だよね。
ということは、
*::-ms-backdrop, .selector {}.selector {} は同じ効果だよね、と、なり、
その際、
他のモダンブラウザにとっては、
-ms-backdropという未定義のキーワードがあるため、
*::-ms-backdrop, .selector {}
というスタイル規則(or規則セット)自体が無視され、
結果、-ms-backdropが実装されているIE11だけが反応する、
と、いうことなのだろうと思われます。

つまり、
*::-ms-backdrop, .selector {}は、
-ms-backdropの疑似要素を使用しない、
という暗黙の約束事の上に成り立っているhackなのではないかと。

underscore

_ とは何でしょうか。
正直はっきり分かりません...

The W3C CSS Validation Serviceで、
_ { color: blue; }を検証してもエラーやワーニングは出ません。
なので _ を使用しては駄目ということはないようです。

次にW3Cの仕様書を探してみます。

Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification
4 Syntax and basic data types
4.1.2.1 Vendor-specific extensions
上記によると、
  -_ を識別子の先頭に使用可能、
  -_ で始まるキーワードやプロパティはベンダー固有の拡張用として予約、
  -_ の予約は将来において保証、
ということのようです。

また、
CSS Syntax Module Level 3
10.7. Experimental implementations
CSS3にもCSS2.1の上記の予約の件が記載されています。

つまり、
_ 一文字ではセレクタなどになることは将来的にもないし、
_ 一文字でベンダープレフィックスとするブラウザも普通に考えればないでしょう。
なので、
_ にマッチするものは一切ない、
ということなのだろうと思われます。

underscore + -ms-backdrop | -ms-fullscreen & -ms-lang

ですので、素人判断ですが、
IE11の css hack は以下のどちらかがよいのかな、と思う次第です。

_::-ms-backdrop,  _:-ms-lang(x), .selector {}
_:-ms-fullscreen, _:-ms-lang(x), .selector {}

または ( hack的な意味合いで ) さらに短縮して、以下は如何でしょうか。

_:-ms-lang(x)::-ms-backdrop,  .selector {}
_:-ms-lang(x):-ms-fullscreen, .selector {}

Edge

ちなみに、
IE11未満は未実装
IE11はベンダープレフィックスが必要
Edgeはベンダープレフィックスが不要
なわけなので、

_:-ms-lang(x)::backdrop,  .selector {}
_:-ms-lang(x):fullscreen, .selector {}

とすれば Edge のみが反応。
( のはずが:fullscreenは何故か反応しない... )

蛇足

話の流れで、
IE11のhackでIE7以下を切るのに_:-ms-lang(x),を使用しましたが、
以下のように、
括弧を利用した疑似クラスと::-ms-backdropの組み合わせで、実は大丈夫です。

_:lang(x)::-ms-backdrop, .selector {}
_:lang(x):-ms-fullscreen, .selector {}
_:nth-child(1)::-ms-backdrop, .selector {}
_:nth-child(1):-ms-fullscreen, .selector {}
_:nth-of-type(1)::-ms-backdrop, .selector {}
_:nth-of-type(1):-ms-fullscreen, .selector {}
_:nth-last-child(1)::-ms-backdrop, .selector {}
_:nth-last-child(1):-ms-fullscreen, .selector {}
_:nth-last-of-type(1)::-ms-backdrop, .selector {}
_:nth-last-of-type(1):-ms-fullscreen, .selector {}

では、Edgeも同様に _:lang(x)::backdrop, .selector {} などと、
括弧を利用した疑似クラスと::backdropの組み合わせにしてしまうと、
Chromeなどが、(=゚ω゚)ノぃょぅ、となってしまうのでだめです。
ただ、IE11以下のIE全てを切れるので、
括弧を利用した疑似クラスと::backdropの組み合わせに、
-ms-ベンダープレフィックス付きの疑似クラスか疑似要素のうち、
Edge対応のものを併記してあげればよさそうです。
-ms-ベンダープレフィックス付きの疑似クラスか疑似要素は、
Pseudo-classesPseudo-elementsなどを参考に。

_:lang(x)::backdrop, _:-ms-keyboard-active, .selector {}
_:lang(x)::backdrop, _::-ms-check, .selector {}
_:lang(x)::backdrop, _::-ms-clear, .selector {}
_:lang(x)::backdrop, _::-ms-expand, .selector {}
_:lang(x)::backdrop, _::-ms-fill, .selector {}
_:lang(x)::backdrop, _::-ms-fill-lower, .selector {}
_:lang(x)::backdrop, _::-ms-fill-upper, .selector {}
_:lang(x)::backdrop, _::-ms-reveal, .selector {}
_:lang(x)::backdrop, _::-ms-thumb, .selector {}
_:lang(x)::backdrop, _::-ms-ticks-after, .selector {}
_:lang(x)::backdrop, _::-ms-ticks-before, .selector {}
_:lang(x)::backdrop, _::-ms-tooltip, .selector {}
_:lang(x)::backdrop, _::-ms-track, .selector {}
_:lang(x)::backdrop, _::-ms-value, .selector {}
_:nth-child(1)::backdrop, _:-ms-keyboard-active, .selector {}
_:nth-child(1)::backdrop, _::-ms-check, .selector {}
_:nth-child(1)::backdrop, _::-ms-clear, .selector {}
_:nth-child(1)::backdrop, _::-ms-expand, .selector {}
_:nth-child(1)::backdrop, _::-ms-fill, .selector {}
_:nth-child(1)::backdrop, _::-ms-fill-lower, .selector {}
_:nth-child(1)::backdrop, _::-ms-fill-upper, .selector {}
_:nth-child(1)::backdrop, _::-ms-reveal, .selector {}
_:nth-child(1)::backdrop, _::-ms-thumb, .selector {}
_:nth-child(1)::backdrop, _::-ms-ticks-after, .selector {}
_:nth-child(1)::backdrop, _::-ms-ticks-before, .selector {}
_:nth-child(1)::backdrop, _::-ms-tooltip, .selector {}
_:nth-child(1)::backdrop, _::-ms-track, .selector {}
_:nth-child(1)::backdrop, _::-ms-value, .selector {}
_:nth-of-type(1)::backdrop, _:-ms-keyboard-active, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-check, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-clear, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-expand, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-fill, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-fill-lower, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-fill-upper, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-reveal, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-thumb, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-ticks-after, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-ticks-before, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-tooltip, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-track, .selector {}
_:nth-of-type(1)::backdrop, _::-ms-value, .selector {}
_:nth-last-child(1)::backdrop, _:-ms-keyboard-active, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-check, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-clear, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-expand, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-fill, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-fill-lower, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-fill-upper, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-reveal, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-thumb, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-ticks-after, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-ticks-before, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-tooltip, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-track, .selector {}
_:nth-last-child(1)::backdrop, _::-ms-value, .selector {}
_:nth-last-of-type(1)::backdrop, _:-ms-keyboard-active, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-check, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-clear, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-expand, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-fill, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-fill-lower, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-fill-upper, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-reveal, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-thumb, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-ticks-after, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-ticks-before, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-tooltip, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-track, .selector {}
_:nth-last-of-type(1)::backdrop, _::-ms-value, .selector {}