読者です 読者をやめる 読者になる 読者になる

クロスブラウザな css3 linear-gradient が面倒になりそうな件について

2012 年の 4月に CR(勧告候補) になった,CSS Image Values and Replaced Content Module Level 3 とそこで規定されてる,Linear Gradients: the ‘linear-gradient()’ notation の幾つかのブラウザでの対応具合が面倒な事になってるなぁってお話.

経緯とか

最初期

もともと,グラデーションだーと提案された頃には,WebKit の独自実装としてこんな感じの書式だった.(cf. Introducing CSS Gradients)

background: -webkit-gradient(linear, 
  left top /* 始点 */,
  left bottom /* 終点 */, 
  from(#000) /* 始点の色 */, 
  to(#FFF) /* 終点の色 */);

途中にもっと色を挟むとか透明度を変化させるとか細かい指定は割愛.

これに対して Gecko(Mozilla) が提案してきたのが,以下の様なちょっと違う書式だった.

background: -moz-linear-gradient(
  top /* 始点 */,
  #000 /* 始点の色 */, 
  #FFF /* 終点の色 */);

このあたりはMDNの linear-gradient #History of_the syntax を参照.

混迷期

当然といえば当然だが,当初から別の書式が提案されてきたために,2010年頃には2つの「独自実装に対応する」にはこう書くといった記事や,Gradient generator などと呼ばれる各実装用のコードをお手軽に生成するようなサービスが跳梁跋扈する運びとなっていた.

ここで,さらに IE 用に filter を使ったり,Opera 用に SVG を使ったりと言った,そもそも working draft であるとか,vendor-prefix 付きであるとかいうことの意味を無視したかのような how to や主張が見られたり,揺り返し的に vendor-prefix 再考といった動きにつながったりしてたけど,そのへんはまた別のお話.

background: #000000; /* Old browsers */
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
background: -moz-linear-gradient(top,  #000000 0%, #ffffff 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#000000), color-stop(100%,#ffffff)); /* Chrome,Safari4+ */
background: linear-gradient(top, #000000 0%, #ffffff 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#ffffff',GradientType=0 ); /* IE6-8 */

Ultimate CSS Gradient Generatorでの生成から調整.

さらにこれに CSS 外(IE のコンディショナルコメントや navigator.userAgent などのブラウザ判定など)といろいろな組み合わせて何とかしてた.

安定期

で,2011年に入って,まず,WebKit -moz-linear-gradient と同じ書式に対応,4月にはOpera が 11.10(Presto/2.8.119) で -o-linear-gradient() として対応,5月にはIE10pp1 で -ms-linear-gradietn() として対応 となって,vendor-prefix 付ける必要はあるけど,ほぼ同じ書式に統一されて,linear-gradient が使えるようになった.

この頃になると,古いブラウザはとりあえず置いといて広く使えるようになってきたことや,open web やら,CSS フレームワークの普及やらで,以下の様な書き方がされるようになり一応の収束を見る.

 background: -webkit-linear-gradient(top, #000, #fff);
 background: -moz-linear-gradient(top, #000, #fff);
 background:   -o-linear-gradient(top, #000, #fff);
 background:  -ms-linear-gradient(top, #000, #fff); /* for ie10 platform preview */
 background:      linear-gradient(top, #000, #fff);

ところが,ここで,大元の CSS3 の仕様に破壊的な変更が入り再び混乱期に突入となる.

再混乱期?

20110712版のWDでの変更が始まりである.

linear-gradient では方向の指定に top/bottom/left/right といったキーワードの他に,角度(deg) での指定ができる.

20110712 版までは,上が黒で下が白のグラデーションの場合,(top, #000, #fff) と書くか,(-90deg,#000,#fff) と書いていた.角度の数値は,X軸正の方向を0,Y軸正の方向を90とし,反時計回りに増加する数学的な象限と同様だった.

これが,20110712 版以降では,Y軸正の方向を0,X軸正の方向を90とし,時計回りに増加する座標系が採用され,これまでと同様の効果を得るには,(180deg,#000,#fff) と書くように変更された.

これは他の CSS の仕様や SVG の仕様との統一性の観点から議論となり変更となった(参照 CSSグラデーションでの角度の解釈 ).

20120712 版での変更を踏まえて,次の20110908版のWDで,キーワード to が追加され,これまでの topto bottomへ,leftto right へと変更になった(参照 CSSグラデーションの構文変更とベンダー接頭辞).

この仕様変更に追随したのが,MozillaOpera だった.

まず,Mozilla685400 - Add a new syntax to -moz-linear-gradient per latest css spec にて,to 有りと無し両方の記述に対応することになった.

Opera は 11.60 あたりからやはり,有り無し両方の記述に対応することになった.(CSS3 Image Values/Replaced Content support in Opera Presto 2.9#linear-gradient(); 11.5x が Presto 2.9.x なので対応しているように読めるが Desktop 版 11.52 では to 無しのみ対応 )

ただし,MozillaOpera も vedor-prefix がついているうちは,20110712 版での角度での変更には対応せず,従来通りの反時計回りを正とする指定のままとなっている.

つまり,古いブラウザをある程度捨てたとしても,仕様と各ブラウザの実装との折り合いをつけると以下の様に書くことになる.

 background: -webkit-linear-gradient(top, #000, #fff);
 background:    -moz-linear-gradient(top, #000, #fff);       /* -moz-liner-gradient(to bottom, #000, #fff); */
 background:      -o-linear-gradient(top, #000, #fff);       /*   -o-liner-gradient(to bottom, #000, #fff); */
 background:     -ms-linear-gradient(top, #000, #fff);       /* for ie10 platform preview */
 background:         linear-gradient(to bottom, #000, #fff);

角度での指定では以下の様になる.

 background: -webkit-linear-gradient(-90deg, #000, #fff);
 background:    -moz-linear-gradient(-90deg, #000, #fff);    /* -moz-liner-gradient(180deg, #000, #fff); */
 background:      -o-linear-gradient(-90deg, #000, #fff);    /*   -o-liner-gradient(180deg, #000, #fff); */
 background:     -ms-linear-gradient(-90deg, #000, #fff);    /* for ie10 platform preview */
 background:         linear-gradient(180deg, #000, #fff);

ここまでが,2012 年8月現在の状況である.

2012 年の秋冬に待ち受ける事態

さて,問題はこれからの話しにある.再混乱期で十分に面倒な雰囲気にはなりつつあるが,2012年の秋か冬には少なくとも 2つ変化がやってくる.

IE10 のリリースと Opera 12.50 のリリースである.

IE10 での linear-gradient

Windows 8 Release Preview に搭載された IE10 では,toキーワードありのみに対応し,角度の指定は CR である 20120412版に対応する.なおかつ -ms- の vendor-prefix を持たない.Unprefixed CSS3 Gradients in IE10.

したがって,-ms-linear-gradient の付いたものを単純に削除して,IE10 用は(CR以降の)新しい書式を使うことになる.IE9 以下用はこれまで通り,コンディショナルコメントの向こう側に押し込めるなどしておく.

 background: -webkit-linear-gradient(top, #000, #fff);
 background:    -moz-linear-gradient(top, #000, #fff);       /* -moz-liner-gradient(to bottom, #000, #fff); */
 background:      -o-linear-gradient(top, #000, #fff);       /*   -o-liner-gradient(to bottom, #000, #fff); */
 background:         linear-gradient(to bottom, #000, #fff);

Opera 12.50 での linear-gradient

Opera 12.50 では,2012/08/10 の Snapshot/ 12.50.1546 から vendor-prefix が無くなり,IE10同様,to 有りのみに対応し,角度の指定も CR 版に対応するようになった.さらに -o- 付きの指定は,すべて無視されるようになった.

したがって,vendor-prefix 付きで古い書式と vendor-prefix 無しでの CR 版以降の書式を併記することで,Opera 11.1x 以降には特に問題なく適用されることになる.

今後やってくる面倒な事態の可能性

つまるところ,混乱期や安定期の頃によく見られた vendor-prefix 付きと無しと同じ内容でつらつらと列挙した CSS では,IE10 や Opera 12.50 以降に対応できない.top や left の指定では完全に無視されて背景がでないといった事態になり,角度での指定では全く違う方向のグラデーションが指定される事態になる.

再混乱期?の節で理想的な指定方法を挙げたが,実際にこの様に to や角度の意味論を vendor-prefix の有り無しで分けて書いている例をそれほど見ない(前述の,Ultimete Gradient Generator は対応済み).CR 版やその前段階の 20110711 版での仕様変更に関する言及も,当初 gradient が喧伝された頃に比べ少なく,それらの古い仕様での解説記事が更新されない可能性も高い.さら,すでに稼働中のコードはいろいろな事情で更新されない可能性が高いため,「OS を新しくしただけ」,「ブラウザを新しくしただけ」で,サイトが使い物にならなくなったとなる事態が少なからず発生する可能性が高い.

まとめ

Linear Gradients: the ‘linear-gradient()’ notation のこれまでの経緯と,2011年秋にあった全く意味が異なるほどの仕様変更と,2012年の秋冬にはこの仕様にのみ対応するブラウザが少なくとも 2つリリースされる予定なので,関係者の方はそろそろ新しい仕様への書き換えが必要なんじゃないでしょうかというお話でした.

追記

 

続編 (どう書くのがベターかって話,Firefox 16 での話,Opera 12.50 が 12.10 になって -o- 付きが復活した話) あとで書く

Opera 12.50 の場合,さらに -webkit-prefix に絡んだ話があり,すこし面倒くさい

Mobile の方で -webkit- ばっかりだから,うちも -webkit-対応するぞ,と何言ってんだこいつらみたいな発表があって,その後実際に,Desktop 12.50.1497 で実装.この時点でいくつかの CSS プロパティは -o- と -webkit- 両対応となった.さらに,12.50.1546 で,このうちのいくつかについて -o- が外れることになり,プレフィックスなしと -webkit- 付きとがサポートされることとなった.

12.50 以降の liner-gradient() はこの,プレフィックス無しと -webkit- 付きとがサポートされるプロパティのうちの一つなのだが,-webkit- 付きの方は 20110712 版以前の古い書式のみがサポートされ,プレフィックス無しの方は CR 版のみがサポートされている.(cf. CSS vendor prefixes in Opera 12.50 snapshots)

このため,新旧の書式と,-o- を含めたプレフィックスのある無しとを列挙するときには,その順番等によって異なる結果を生む.

基本的に,CSS の一般的な文法に則って,「最後に指定された有効なプロパティが適用」される.

http://jsfiddle.net/4wHLD/ のサンプル群は,Opera 11.1x+ ではすべて同じ白から緑へのグラデーションになるが,12.50 では,いくつかのケースで異なる結果となる.

例えば,2a のケースでは,プレフィックス無しだ採用されそうだが,to キーワードも無いため,結局 -webkit- 付きが採用され,白から青へのグラデーションと成っている.2b のケースでは,プレフィックス無しの指定が採用され白と赤のグラデーションになっているが,角度の解釈が新仕様のため方向が上下ではなく左右となっている.