Internet Explorer 10のCSS 3D Transforms
公開:
更新:
とうとうWindows 7向けのIE 10が公開されましたね!(これを書いている時点ではRelease Previewですが)
IE 10ではCSS 3D Transforms, Animations, Transitionsなどが-ms-
なしで使えるようになりました。素晴らしい!
というわけでさっそく試してみたわけですが、どうもおかしい。表示はできるんですが、アニメーションやトランジションしたときに立体的に見えない。
調べてみるとMSDNに次のような記述が。
つまり、IE 10ではtransform-style: preserve-3d
をサポートしていないから子要素それぞれにしてくださいね、ということらしいです。transform-style
の初期値はflat
ですから、IE 10はflat
固定になるわけです。
分かりやすいと思われる例を。
4つのパネルがくるくる回るだけのサンプルを作ってみました。
上がtransform-style
にpreserve-3d
を指定したもの、下がflat
を指定したものになります。
transform-style: preserve-3d
のテスト
<div class="stage1">
<div class="view">
<div class="panel p1">1</div>
<div class="panel p2">2</div>
<div class="panel p3">3</div>
<div class="panel p4">4</div>
</div>
</div>
<div class="stage2">
<!-- 中身はstage1と同じ -->
</div>
.stage1,
.stage1 > .view {
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.stage2,
.stage2 > .view {
-webkit-transform-style: flat;
transform-style: flat;
}
.stage1,
.stage2 {
position: relative;
margin: 100px auto 0;
width: 100px;
height: 100px;
-webkit-perspective: 500px;
perspective: 500px;
}
.view {
position: absolute;
width: 100%;
height: 100%;
}
.panel {
position: absolute;
padding: 7px;
border: 3px solid red;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100px;
height: 100px;
background: rgba(255, 0, 0, 0.5);
color: white;
font-size: 80px;
line-height: 1;
text-align: center;
}
.p1 {
-webkit-transform: translateZ(200px);
transform: translateZ(200px);
}
.p2 {
-webkit-transform: rotateY(90deg) translateZ(200px);
transform: rotateY(90deg) translateZ(200px);
}
.p3 {
-webkit-transform: rotateY(180deg) translateZ(200px);
transform: rotateY(180deg) translateZ(200px);
}
.p4 {
-webkit-transform: rotateY(270deg) translateZ(200px);
transform: rotateY(270deg) translateZ(200px);
}
@-webkit-keyframes rotation {
from { -webkit-transform: rotateY(0); }
to { -webkit-transform: rotateY(360deg); }
}
@keyframes rotation {
from { transform: rotateY(0); }
to { transform: rotateY(360deg); }
}
.view {
-webkit-animation: rotation 4s linear infinite;
animation: rotation 4s linear infinite;
}
IE 10では下のようになってしまうわけですね。
これをどうやって各ブラウザに対応させるかを考えてみました。
(Operaはまだ3D Transformsに対応していませんが、標準構文を書いておけば大丈夫だと思います)
ここからは上記サンプルの 安全ではありますが……複雑なアニメーションや変形を行っている場合はかなり大変かもしれません。 FirefoxとWebkitは今までどおりでいいわけですから、IE 10と別に指定できるようにしてみます。 この判定には こんな感じでしょうか。 あとはCSSを書くときに、 このコードはGistに置いてあるのでよかったら改良してください。 Firefox 17から のように上書きします。ちなみにOperaも12.10から使えます。 何回も同じようなの書いてしまうことになりますが……。 現状だとWebkit向けにはメディアクエリで IE 10だけを振り分けるメディアクエリを使うやり方ですが、こういうのは好きじゃないのでできれば避けたいです。 IE 10に合わせておくのが無難かと思われます。 分岐させる場合には、多数のIE 10がIE 11に置き換わって他のブラウザと同じように動作するようになったときのことを考えると Modernizerを使って判別しつつJavaScriptオフの環境向けにはIE 10と同じ指定をしておくのが現実的かなーと思います。 IE 10で.stage1
を変更しながら説明します。transform-style: preserve-3d
のことは忘れてIE 10に合わせるtransform-style
にはflat
しかないんだ、という考えで作ります。.panel
の親をアニメーションさせるのではなく、自身をアニメーションさせる指定を行います。/* 値をflatに(指定しなくても同じ) */
.stage1,
.stage1 > .view {
-webkit-transform-style: flat;
transform-style: flat;
}
.stage1 {
position: relative;
margin: 100px auto 0;
width: 100px;
height: 100px;
/* 削除 */
/*
-webkit-perspective: 500px;
perspective: 500px;
*/
}
.view {
position: absolute;
width: 100%;
height: 100%;
/* 追加 --*/
-webkit-perspective: 500px;
perspective: 500px;
/*-- 追加 */
}
.panel {
position: absolute;
/* あまり関係ないので以下略(指定は同じ) */
}
.p1 {
-webkit-transform: translateZ(200px);
transform: translateZ(200px);
}
.p2 {
-webkit-transform: rotateY(90deg) translateZ(200px);
transform: rotateY(90deg) translateZ(200px);
}
.p3 {
-webkit-transform: rotateY(180deg) translateZ(200px);
transform: rotateY(180deg) translateZ(200px);
}
.p4 {
-webkit-transform: rotateY(270deg) translateZ(200px);
transform: rotateY(270deg) translateZ(200px);
}
/* 削除 */
/*
@-webkit-keyframes rotation {
from { -webkit-transform: rotateY(0); }
to { -webkit-transform: rotateY(360deg); }
}
@keyframes rotation {
from { transform: rotateY(0); }
to { transform: rotateY(360deg); }
}
*/
/* 追加 --*/
@-webkit-keyframes rotation {
from { -webkit-transform: rotateY(0) translateZ(200px); }
to { -webkit-transform: rotateY(360deg) translateZ(200px); }
}
@keyframes rotation {
from { transform: rotateY(0) translateZ(200px); }
to { transform: rotateY(360deg) translateZ(200px); }
}
/*-- 追加*/
/* 削除 - アニメーションは.panelに指定する */
/*
.view {
-webkit-animation: rotation 4s linear infinite;
animation: rotation 4s linear infinite;
}
*/
/* 追加 --*/
.panel {
-webkit-animation: rotation 4s linear infinite;
animation: rotation 4s linear infinite;
}
/* 各パネルの初期位置をずらすため、animation-delayで調節 */
.p2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
.p3 {
-webkit-animation-delay: -2s;
animation-delay: -2s;
}
.p4 {
-webkit-animation-delay: -3s;
animation-delay: -3s;
}
/*-- 追加 */
処理を分岐する
そうするとこで、IE 10には上記の指定をし、それ以外は今までどおりという指定ができます。3D Transformsとアニメーションやトランジションを組み合わせている部分でのIE 10はIE 9以下と同じように扱う、ということもできますね。Modernizrで判定
transform-style: preserve-3d
に対応しているかどうかを調べればいいので、Modernizrを使って判定してみました。Modernizr.addTest('csstransformspreserve3d', function () {
var prop,
val,
cssText,
ret;
prop = 'transform-style';
if ('webkitTransformStyle' in document.documentElement.style) {
prop = '-webkit-' + prop;
}
val = 'preserve-3d';
cssText = '#modernizr { ' + prop + ': ' + val + '; }';
Modernizr.testStyles(cssText, function (el, rule) {
ret = window.getComputedStyle ? getComputedStyle(el, null).getPropertyValue(prop) : '';
});
return (ret === val);
});
.no-csstransformspreserve3d .stage1
と.csstransformspreserve3d .stage1
のようにセレクタを分けて書いていきます。CSSだけで分岐 1
@supports
が使えるので(layout.css.supports-rule.enable
をtrue
にする必要があります)、まずはIE 10向けの指定を普通に書いた上で、@supports (transfrom-style: preserve-3d) { ... }
Webkitは近いうちに対応するようなので、それも考えると最終的には以下のような感じでしょうか。/*
IE 10向けの指定
*/
/*
@suuportsが使えないWebkit向けの指定
-webkit-が必要なのでIE 10とは被らない
*/
@supports (transform-style: preserve-3d) or
(-webkit-transform-style: preserve-3d) {
/* IE 10向けに指定したアニメーションなどを上書きして削除する指定 */
/* 標準構文と-webkit-付きを今までどおりに指定 */
}
というかもっといい書き方ができるんじゃないかと思います。-webkit-min-device-pixel-ratio: 0
を使えば振り分けられますが……やるとしても@supports
と併用したほうが安全な気がします。CSSだけで分岐 2
IE 11で予期しない動作をする可能性がないわけではないですし。
使うとしても応急処置的なものですね。結局どうするの?
もしくは@supports
で頑張るか。@supports
使えたら楽だったんですけどね……。