VMLやSVGを用いた角丸コーナー

category-icon

 おはようございます。時間があるときに、以下のようなサイトを作成しているのですが、この2枚のスクリーンショットは、違うところがあります。どこが違うのかというと、2枚目のやつは、ボックスのコーナーが丸っこくなっていて、いわゆる角丸コーナーと言われるものになっています。

shot1

shot2
こっちの方がパリっぽい!?

 ちょっとお洒落っぽいサイトデザインにしようと思っているのですが、そのためには、角張ったデザインよりも、角が取れたデザインの方が良いかなと考えました。で、角丸コーナーは、FirefoxやWebKit系のSafariやChromeは、以下のような感じでCSSでの指定が可能です。

-moz-border-radius: 10px; // Firefox
-webkit-border-radius: 10px; // Webkit系

問題は、これらのCSSに対応していないOperaやIEです。Operaは、近い将来にサポートするでしょうけど、IEは、今後数年は期待できないかもです。なので、これら2つのブラウザに対しては、JavaScriptを通じてのアプローチを取ることになります。

 IEでは、VMLを利用するのがよさげです。しかも角丸コーナーのためにあるようなroundrectというのが予め実装されているので、これを使うのが簡単そうですが、例えば最初に挙げたサイトショットにあるように、ナビ―ゲーションタブの上側だけ丸っこくしたいとかいう場合の制御が難しいです。なので、VMLを使うにしても、もうちょっと、凝ってみることにします。そもそも角丸コーナーを実現するには、以下のようなアプローチを取るのが自然でしょう。

principle
この考えでいけば、Firefoxなどのradiusと同じ値を指定できるだろう。

 要は、4つの各コーナーに小さい円を描いて、それをクリッピングすれば良いわけです。これなら、ボーダー半径は、FirefoxやWebkit系で指定する値と同様に振る舞うことが期待出来ます。で、それを実際に書き下したのが以下。

<div style="background:#fffacd; position:absolute; right:-20px; bottom:-20px; width:50px; height:50px; clip:rect(25px 50px 50px 25px);">
 <v:group style="width:50px; height:50px; position:absolute;" coordsize="50,50">
  <v:oval fillcolor="#fff" strokeweight="20px" strokecolor="#ffd700" style="left:9px; top:9px; width:30px; height:30px;" />
 </v:group>
</div>

 これをIEで見ると、以下のように見えます。なかなか良い感じですね。

shot3

 残りの角についても同様にすればOKです。ただし、IEのVMLバグなのかどうか分かりませんが、作成したVML画像の位置が1ピクセルぐらい微妙にずれる場合があるようです。理論的には、OKのはずなんですが。。

 さて、Operaの場合はどうでしょうか。OperaはVMLはサポートしませんが、代わりにSVGをサポートします。なので、これを用いて、上で述べたようなアプローチを取ればOKですね。大体以下のようなスクリプトでOKでしょう。

function svg_corner(id, location, r, obg){
 var d = document, e = d.getElementById(id);
 if(e.currentStyle.position == 'static'){
  e.style.setProperty('position', 'relative', null);
 }
 r = r || 10;
 var svg = d.createElementNS('http://www.w3.org/2000/svg', 'svg');
 svg.style.setProperty('position', 'absolute', null);
 var ibg = e.currentStyle.backgroundColor;
 ibg = ibg == 'transparent' ? '#fff' : ibg;
 if(!obg){
  var p = e.parentNode;
  while(p && p.currentStyle.backgroundColor){
   obg = p.currentStyle.backgroundColor;
   if(p.nodeName == "HTML") break;
   if(obg && obg != "transparent") break;
   p = p.parentNode;
  }
 }
 obg = (!obg || obg == "transparent") ? "#fff" : obg;
 var bc = e.currentStyle.borderColor;
 bc = (!bc || bc == "transparent") ? "#fff" : bc;
 var bw = parseInt(e.currentStyle.borderWidth);
 var rect = d.createElementNS('http://www.w3.org/2000/svg', 'rect');
 var oval = d.createElementNS('http://www.w3.org/2000/svg', 'circle');
 var attr = [];
 switch (location){
  case 'tl' : attr = [r + bw/2, r + bw/2, 'top', -bw, 'left', -bw]; break;
  case 'tr' : attr = [0, r + bw/2, 'top', -bw, 'right', -bw]; break;
  case 'bl' : attr = [r + bw/2, 0, 'bottom', -bw, 'left', -bw]; break;
  case 'br' : attr = [0, 0, 'bottom', -bw, 'right', -bw]; break;
 }
 oval.setAttribute('fill', ibg);
 oval.setAttribute('cx', attr[0]); oval.setAttribute('cy', attr[1]);
 oval.setAttribute('r', r);
 oval.setAttribute('stroke', bc); oval.setAttribute('stroke-width', bw + 'px');
 rect.setAttribute('fill', obg);
 rect.setAttribute('width', r * 2 + bw + 'px'); rect.setAttribute('height', r * 2 + bw + 'px');
 svg.appendChild(rect);
 svg.appendChild(oval);
 svg.style.setProperty(attr[2], attr[3] + 'px', null); svg.style.setProperty(attr[4], attr[5] + 'px', null);
 svg.style.setProperty('width', r + bw/2 + 'px', null); svg.style.setProperty('height', r + bw/2 + 'px', null);
 e.insertBefore(svg, e.firstChild);
}

 これらをまとめると、以下のようなデモンストレーションが出来ます。このデモでは、ID指定した要素に対して角丸を発動していますが、特定のクラス名を持ったものに対して、ということも簡単に出来るでしょう。

どのブラウザでもほぼ見た目が同じな角丸コーナーのデモLink

 上のサンプルでは、ついでにFirefoxやWebkit系でも、スクリプトでボーダー属性を指定するようにしています。このふたつ、指定の仕方が微妙に違うんですよねぇ。ちょっとはまりました。以下の感じ。
document.getElementById(id).style.WebkitBorderTopLeftRadius = radius + "px"; // Webkit系
document.getElementById(id).style.MozBorderRadiusTopleft = radius + "px"; // Firefox。leftのLも小文字。

 なお、OperaでのSVGの使い方は、「Operaで丸角を実現するCSSを試してみた (解決)Link 」や「角丸にするためにライブラリを作ってみるLink 」が参考になりました。

— posted by martin at 01:15 pm   commentComment [0]  pingTrackBack [0]

この記事に対する TrackBack URL:

設定によりTB元のページに、こちらの記事への言及(この記事へのリンク)がなければ、TB受付不可となりますのであらかじめご了承下さい。

コメントをどうぞ。 名前(ペンネーム)と画像認証のひらがな4文字は必須で、ウェブサイトURLはオプションです。

ウェブサイト (U):

タグは使えません。http://・・・ は自動的にリンク表示となります

:) :D 8-) ;-) :P :E :o :( (TT) ):T (--) (++!) ?;w) (-o-) (**!) ;v) f(--; :B l_P~

     
T: Y: ALL: Online:
Created in 0.0031 sec.
prev
2021.9
next
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30