CSSできれいな斜め線

斜め

CSSで斜めに線を引くようなことをするには多少なりとも工夫が必要だった。つまりCSSで作る吹き出し(もう5年前の記事だ)のようにborderプロパティーを使って頑張るしかなかったわけだ。今はlinear-gradient()があるので直感的に作ることができるようになった。しかしきれいに引くとなるとまだ工夫が必要そうだ。

View Demo: CSS Diagonal Line

borderプロパティーを使ったもの、linear-gradient()を背景で使ったもの、Data URI化したSVGを背景に使ったもの、以上の計3つのデモを作った。

.lg {
  background-image: linear-gradient(
    to right bottom,
    transparent 50%,
    #f0f 50%
  );
  background-repeat: no-repeat;
  background-size: cover;
  height: 3rem;
  width: 16rem;
}

2番目のlinear-gradient()を背景に使ったものが最も直感的に書けるが、Chrome 40ではぎざぎざになってしまう。Chromeはトップシェアで安定しだしたと考えられるので、今この方法で実装するのはかなり勇気がいる。

.border {
  border-bottom: 3rem solid #f0f;
  border-left: 16rem solid transparent;
  box-sizing: border-box;
  height: 0;
  width: 16rem;
}

1番目のborderプロパティーによる実装は安定の結果だ。以前はハードウェア・アクセラレーションを有効化するハックが必要だったが、今はいらない。とはいえ相変わらず意味のわからないCSSコードになる。加えてborderプロパティーで%を使えないため、不明な幅の要素に対してはうまく作ることができない。

.svg {
  background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221%22%20height%3D%221%22%20preserveAspectRatio%3D%22none%22%3E%3Cpath%20d%3D%22M0%201l1-1v1z%22%20fill%3D%22%23f0f%22%2F%3E%3C%2Fsvg%3E');
  background-repeat: no-repeat;
  background-size: 100% 100%;
  height: 3rem;
  width: 16rem;
}

しょうがないのでSVGをData URI化して埋め込むという奥の手を使った。斜めの画像があるという前提だと、概ね直感的なCSSだとは言える。Data URIも長いが、それでも226バイト程度なので、多少複雑なCSSグラデーションだと思えば許容範囲だろう。見逃しがちなのはbackground-sizeプロパティーで明示的にいっぱいいっぱいにリサイズしてやることくらいだ。

<svg
  xmlns="http://www.w3.org/2000/svg"
  width="1"
  height="1"
  preserveAspectRatio="none">
  <path
    d="M0 1l1-1v1z"
    fill="#f0f"/>
</svg>

SVGもこの程度の簡単なものだ。Chromeにかなり古くからあるリサイズ・バグへ対応するためにpreserveAspectRatio属性を指定することに注意が必要なくらいだ(これで30分くらいハマった)。


こういった斜めの線やブロックを作る場合にはCSS Transformを使って回転させる(rotate()する)というアプローチも可能だ。少し足りなかったりはみ出たりする部分は、widthプロパティーで大きく作り、overflowプロパティーで隠せば良い。中身も回ってしまうのは、回転軸に注意して子の要素で逆方向に回転させれば戻せるだろう。CSSは煩雑だが傾けたいから傾けるわけで、概ね直感的とも言えそうだ。

ただ必要としたページでは、斜めにしたいブロックの高さが一定ではないこと、斜めの角度ではなく高さを一定にしたかったことなどの条件があった。CSS Transformでも頑張って計算すれば可能そうだったが、面倒すぎるかと思い、背景画像によるアプローチに絞って考えていた。


安定なのはborderプロパティーで行う実装だが、不明な幅の要素で使いたい場合はSVGによる実装というのが現時点での妥当な選択だろう。Firefox 35で若干アンチエイリアスが甘いことも考慮すると、SVGで統一という選択も悪くはない。とにかくChromeでも早いところlinear-gradient()へきれいにアンチエイリアスかかるようになって欲しい。