CSSグラデーションにアンチエイリアスを
- プロダクション

目次
CSSグラデーションでは、滑らかに色が変化するグラデーションばかりでなく、くっきりとした境界をもったツートンカラーを作ることもできます。さまざまな場面で活用できる手軽で便利なテクニックなのですが、ひとつだけ困った問題があります。アンチエイリアスが効かないのです。
この記事では、CSSグラデーションでツートンカラーを表現する際に生じるこの問題について解決方法を考えていきます。
くっきりしたツートンを描く方法
ついでなので、本題に入る前にCSSグラデーションでツートンを描く方法を復習しておきましょう。CSSグラデーションはその名の通り背景などにグラデーションを描画する機能ですが、使い方しだいで境界のくっきりとしたツートンを描くこともできます。
.ex1 { background-image: linear-gradient(90deg, #f0f, #0ff); } .ex2 { background-image: linear-gradient(90deg, #f0f 50%, #0ff 50%); }
色の変化が始まる点と終わる点のことをカラーストップと言いますが、この2点間の距離が近ければ近いほどほど色の変化は急峻になります。そして、2点間の距離がゼロになると境界のくっきりしたツートンカラーになる、という理屈です。
CSSでは、2色のカラーストップに同じ値を設定するだけです。カラーストップにはカスタムプロパティを使うこともできますので、変数化しておくと動的にグラフを描くときなどに便利ですね。
※ @propertyルール用いるとlinear-gradient()のカラーストップもtransitionが可能になります。
アンチは効きません
本題に入りましょう。
CSSグラデーションのツートンにはアンチエイリアスが効きません(ほかの手段で描いたツートンにこの問題はありません)。ちょっきり水平方向や垂直方向のツートンではまったく問題にならないことですが、境界線が斜めだったり曲線だったりする時にジャギー(階段状のぎざぎざ)がはっきりと問題になってきます。
この挙動じたいはかなり古くから知られているので、ブラウザの実装が不十分なわけではなく、あえてこのような実装にしている可能性が高いと筆者は考えています。
解決方法
この問題は、前後のカラーストップ間の距離を完全なゼロとするのではなく、わずかな距離(オフセット)を持たせることで解決できます。その適切なオフセット量は1pxです。
具体的には、下記のいずれかの方法で実現できます。
- 前方のカラーストップ値から1pxを引く
- 後方のカラーストップ値に1pxを足す
- 前方のカラーストップ値から0.5px引き、後方のカラーストップ値に0.5px足す
/* 前方のカラーストップ値から1pxを引く */ background-image: linear-gradient(#000 calc(50% - 1px), #fff 50%); /* 後方のカラーストップ値に1pxを足す */ background-image: linear-gradient(#000 50%, #fff calc(50% + 1px)); /* 双方のカラーストップ値に0.5pxを引く&足す */ background-image: linear-gradient(#000 calc(50% - 0.5px), #fff calc(50% + 0.5px));
もっとも厳密な描画結果が得られるのは3番め(双方を0.5pxずつプラスマイナスする方法)ですが、1px未満の誤差が許容できるデザインであればわざわざこれを選ぶ必要はありません。
結果
厳密バージョンで検証しました。描画結果はほかの条件とほぼ一致し、1pxのオフセットが適切であることがわかります。また、厳密でないバージョン(前後どちらかのカラーストップを1pxずらす)でも、境界の位置がわずかにずれるだけでアンチエイリアスの質には影響はありませんでした。
解決できないケース
linear-gradient()とその亜種repeating-linear-gradient()、radial-gradient()とその亜種repeating-radial-gradient()は、上記の方法で擬似アンチエイリアスを発生させることができます。しかしこの方法が通用しないグラデーションもあります。円錐グラデーションconic-gradient()とその亜種repeating-conic-gradient()です。
円錐グラデーションは円周方向に色が遷移するため、カラーストップに指定できるのは角度だけです(pxなどの<length>値を指定すると構文エラーとなります)。また、色遷移の進行は円の内周部では小さく、円の外周部では大きくなります。つまり境界の端と端ではカラーストップのオフセット距離が異なってしまうのです。
2000pxほどの大きな半径を持つconic-gradient()で、アンチエイリアスが発生する最小限のオフセット(円周の4096分の1)をつけてみました。結果はご覧の通り、内周部ではジャギジャギ、外周部ではボケボケで、長い半径を持つグラデーションで使うにはいささか無理がある、という結果になりました。conic-gradient()におけるオフセット法は、ドーナツ円グラフのような限定された半径域で、アンチエイリアスのかかり方を細かくチューニングしながら扱う必要がありそうです。
この記事に関するご相談やご質問など、お気軽にお問い合わせください。
関連する記事
-
プロダクション
-
プロダクション
-
プロダクション/オピニオン