border-radius + -moz-border-radius + (Nifty Corners * IE behavior)

これまではさほど関心を持っていなかった角丸なのですが、最近のはてなブックマークで角丸を扱った記事が多く取り上げられてたり、CSS Nite Vol.6(見に行ってました)でも角丸が取り上げられたりしていたので、今更ながらにわかに興味が出てきたのでした。

たぶん、自分が角丸へ関心を持つのを避けていたのは、作る側として「実現するのがややこしいから」ということだったと思うのですが、見る側からしてみると、角丸のもつ見た目の印象はかなり効果的だよなあ、と考えるようになってきました。最近見たものだと、Catalystでサンプルアプリケーションを作った時のデフォルトページが、-moz-border-radiusをつかったスタイルで、衝撃的でした。

さて角丸をどう実現するかですが、背景画像を使うのは画像を用意するのが面倒だし、HTMLソースに余計なマークアップを追加するのは極力避けたいところ。CSSの記述だけで実現できれば、作成も保守も楽だしHTMLに余計なマークアップを混ぜる必要も無いしで言うこと無いわけです。

W3CのCSS3草案では、border-radiusというプロパティが検討されており、開発中のWebKit(Safariで使われるHTMLレンダリングエンジン)では既に対応しているそうです。また、Firefoxでは-moz-border-radiusという独自拡張のプロパティが利用できます。なので、CSSのみで角丸を実現しようとするならば、

#round-corner {
    border-radius:10px;
    -moz-border-radius:10px;
}

という風にするのが現状でのせいいっぱい、ということになるかと思います。

※ 双方のプロパティは値の指定方法がかなり異なるので、border-radius - 徒委記 にまとめてみました。

* * *

いやいや、もう少し対象ブラウザをひろげられないのか、ということで、大口顧客であるところのWindows IEで何とかする方法も考えてみます。きっかけとなったのは、IEでもborder-radiusっぽいことをするbehaviorを改めて拝見したことでした。

IEでもborder-radiusっぽいことをするbehaviorでは、角の丸いboxを表示するためにVMLを、またそれを適用するためにIEのDHTML Behaviorを利用しています。実際には .htc ファイル内のスクリプトが動作しているのですが、それをCSS経由で適用できるというのは大きな利点だと思いました。

例えば、JavaScriptで角丸を実現するNifty Cornersでは、元のHTMLソースをcleanかつlightに保てるという利点を挙げていますが、それでもscript要素を入れる必要は出てくるのであり、また角丸スタイルを適用するためのRounded関数の使い方を覚える必要があります。しかしbehaviorであれば、script要素を入れる必要もなくなり、また、特殊な文法を覚えることなく、通常のCSSプロパティのように使うことができます。

ただ、VMLを使うというのは、角の丸いboxを描画するという目的には確かに理に適った方法なのですが、VMLを埋め込まれたHTMLはDTDに妥当とは言えなくなります。また、説明にある通り互換モードでしか動作しないというのも、実用するには難しい点ではないかと思います。

そんなわけで、最善ではないにしろ、適用後も妥当なHTMLとなり、また確実に動作するよう、Nifty Corners相当のマークアップ + スタイルを挿入する behavior を作ってみました。以下サンプルです。

CSSの記述はこんな感じです。

h1 {
    background-color:#096;
    border-radius:10px;
    -moz-border-radius:10px;
    behavior:url(round.htc);
}

HTMLソースは一見すっきりしていますが、実際に(IEの)内部でどのようなHTMLが適用されているかを見てみたい方は、IEのアドレスバーに以下のコードをコピー&ペーストしてEnterとしてみてください。(かなりひどいことになってます)

javascript:alert(document.getElementsByTagName('body')[0].innerHTML);

また、実用上でも以下の問題を抱えてます。

それでも、CSSにより、なるべく多くのブラウザで角丸のスタイルを見せたいと考えるならば、このサンプルのような border-radius + -moz-border-radius + behavior を併用する方法が、過渡的手段としては1つの解になるのでは、と考えてみましたが、いかがでしょう(あまり自信はありませんが……)。