Die Ecken, die keine sein sollen ...

Rounded Corners!!! Runde Ecken!!! So möchten wir es gerne haben, weil es so 'neuartig' aussieht und offensichtlich die AJAX-Ära begleitet. Und es gibt so viele Ansätze, runde Ecken zu zaubern. Bei Smileycat sind so um die 50 aufgeführt. Die spannenden Ansätze sind die, die per JavaScript und CSS eine vorgegebene kantige HTML-Box zu einer 'schönen' abgerundeten Box machen und auch den Hintergrund durchscheinen lassen.

Per Zufall entdecke ich auch noch eine einfache JavaScript-Lösung, die man auch auf Anhieb versteht.

Das hat meine Fantasie angeregt. Kann man damit auch die schönen abgerundeteten Kästchen zaubern, die jetzt in der neuen MS PowerPoint 2007-Version so schön aussehen? Mal probieren. Also aufsetzend auf das sequential.org-Skript (meinen Dank für die Ideen) wird das Ganze zu:

var cache = new Object();
var out = false;
function draw_upper( a, n, r, c ) {
  var l = r + '_' + a + '_' + c + '_' + 'u';
  var o = document.getElementById( n );
  if (!cache[ l ]) {
    cache[ l ] = '';
    for (var i = r-1; i >= 1; i--) {
      cache[ l ] += get_line( i, r, c, a );
    }
  }
  o.innerHTML = cache[ l ];
}
function draw_lower( a, n, r, c ) {
  var l = r + '_' + a + '_' + c + '_' + 'l';
  var o = document.getElementById( n );
  if (!cache[ l ]) {
    cache[ l ] = '';
    for (i = 1; i <= r-1; i++) {
      cache[ l ] += get_line( i, r, c, a );
    }
  }
  o.innerHTML = cache[ l ];
}
function get_line( i, r, c, a ) {
  var w = Math.sqrt( (r * r) - (i*i) );
  if (out) {
    w = Math.floor( r - w );
    a = a == 'left' ? 'right' : 'left';
  } else {
    w = Math.floor( w ) + 1;
  }
  return  '<div style="height: 1px; margin-' + a + ': auto; width: ' +
    w + 'px; background: ' + c + ';">&nbsp;</div>';   // &nbsp; is required by IE.
    // ev. noch font-size: 1px; und line-heigth: 1px; in den style aufnehmen
}
function draw_circle( r, ur, ll, lr ) {
  draw_upper( 'left',  ul, r, c );
  draw_upper( 'right', ur, r, c );
  draw_lower( 'left',  ll, r, c );
  draw_lower( 'right', lr, r, c );
}
function w(i)  { return ('width:'+i+'px;'); }
function hi(i) { return ('height:'+i+'px;'); }
function r(i)  { return ('right:'+i+'px;'); }
function l(i)  { return ('left:'+i+'px;'); }
function t(i)  { return ('top:'+i+'px;'); }
function lh(i) { return ('line-height:'+i+'px;'); }
function bg(i) { return ('background:'+i+';'); }
function mt(i) { return ('margin-top:'+i+';'); }
function tcl(i){ return ('color:'+i+';'); }
function draw_box(typ,e,c,text,h,cw,len,tm,tc) {
  o_ = typ & 1; u_ = typ & 2; l_ = typ & 4; r_ = typ & 8;
  if (!text) text='&nbsp;';
  if (!h)    h=18;
  if (!cw)   cw=16;
  if (!len)  len=100;
  if (!tm)   tm=10;
  if (!tc)   tc = '#fff';
  s = '<span style="position:absolute;';
  var $o = '';
  $o += (o_&&l_)?s+l(0)+t(0)+w(cw)+'"id="'+e+'1"></span>':'';
  $o += (o_&&r_)?s+r(0)+t(0)+w(cw)+'"id="'+e+'2"></span>':'';
  $o += (u_&&l_)?s+l(0)+t(h+cw)+w(cw)+'"id="'+e+'3"></span>':'';
  $o += (u_&&r_)?s+r(0)+t(h+cw)+w(cw)+'"id="'+e+'4"></span>':'';
  $o += (o_)?s+l(cw)+t(0)+w(len)+lh(cw-1)+bg(c)+'">&nbsp;</span>':'';
  $o += (u_)?s+l(cw)+t(h+cw)+w(len)+lh(cw-1)+bg(c)+'">&nbsp;</span>':'';
  $o += (l_)?s+l(0)+t(cw-1)+w(cw)+lh(h+1)+bg(c)+'">&nbsp;</span>':'';
  $o += (r_)?s+l(cw+len)+t(cw-1)+w(cw)+lh(h+1)+bg(c)+'">&nbsp;</span>':'';
  $o += s+l(cw)+t(cw-1)+w(len)+lh(h+1)+bg(c)+'">&nbsp;</span>';
  $o += s+l((l_)?0:cw)+t((o_)?0:cw)+w(len+((l_)?cw:0)+((r_)?cw:0));
  $o += hi(h+((o_)?cw-1:0)+((u_)?cw-1:0))+tcl(tc)+mt(tm)+'">'+text+'</span>';
  document.getElementById(e).innerHTML += $o;
  if (o_&&l_) draw_upper( 'left',  e+"1", cw, c );
  if (o_&&r_) draw_upper( 'right', e+"2", cw, c );
  if (u_&&l_) draw_lower( 'left',  e+"3", cw, c );
  if (u_&&r_) draw_lower( 'right', e+"4", cw, c );
  }
function box(id,top,left,width,h,cw,col1,text,tm,col2) {
   var b = document.getElementById("canvas");
   $o = '<div id="'+id+'" style="position:absolute;top:'+ top +'px;left:'+ left +'px;width:'+ width +'px;"></div>';
   b.innerHTML += $o;
   // draw_box(typ,e,c,text,h,cw,len,tm,tc)
   draw_box(15,id,col1,text,h,cw,width-2*cw,tm,col2);
   }
function box2(id,top,left,width,h,cw,b,text,tm,col1,col2,tc) {
   box(id,top,left,width,h,cw,col1,'',tm,tc);
   box(id+'a',top+b,left+b,width-2*b,h,cw-b,col2,text,tm,tc);
   }
function vl(top,left,height,col1) {
   var b = document.getElementById("canvas");
   $o = '<div style="position:absolute;top:'+ top +'px;left:'+ left +'px;';
   $o += 'height:'+ height +'px;width:4px;background:'+ col1 +';"></div>';
   b.innerHTML += $o;
   }
function hl(top,left,width,col1) {
   var b = document.getElementById("canvas");
   $o = '<div style="position:absolute;top:'+ top +'px;left:'+ left +'px;';
   $o += 'height:4px;width:'+ width +'px;background:'+ col1 +';"></div>';
   b.innerHTML += $o;
   }

Die Funktion draw_box(typ,e,c,text,h,cw,len,tm,tc) erwartet als Parameter: typ (Bitfeld für die Rundungen: 1=oben, 2=unten, 4=links, 8=rechts; 15 = alles), e (das Element, in das die Box hinein soll), c (die Hintergrundfarbe), text (der in der Box auszugebende Text), h (Höhe der Box), cw (der Radius der Eckenrundung), len (Breite der Box), tm (Abstand des Textes vom oben Rand [0 wird durch 10 ersetzt]) und tc (die Farbe des Textes). Die Funktionen box() und box2() dienen dazu, die Box vorzubereiten bzw. eine Doppelbox (siehe Beispiel) zu erzeugen. Bei box2() wird mit b die Breite der Umrandungslinie definiert. Die Funktionen hl() und vl() zeichnen die horizontalen und vertikalen Linien. Die Position und die Formatierung des Textes kann den Funktionen per <div> übergeben werden, damit sind auch alle anderen Spielarten, wie z. B. ein <a href=...> möglich.

Ach ja, da gibt es noch was. Wenn man sich das sequential.org-Skript anschaut, sieht man einen kleinen Cache, der mit den Ecken gefüttert wird, so dass man nicht mehrfach die gleiche Arbeit tun muß. Sehr sinnvoll! Leider wird als Index nicht der Farbwert mit abgespeichert, so dass man bei unterschiedlichen Farben nicht neu den Cache füttert. Da muß man den Index noch um den Farbwert (wie hier auch verwendet) ergänzen, sonst wird das nichts mit unterschiedlichen Farben:

var l = r + '_' + a + '_' + c + '_' + 'u';

Aufgerufen werden die Boxen und Linien mit

<script>box('b0',0,0,272,165,8,'#ddd',
'<div style="text-align:right;margin-right:10px;
font:11px calibri,sans-serif;">Beispiel</div>',
1,'#000');
box2('b1',20,10,250,16,18,4,
'<div style="text-align:center;font:16px calibri,sans-serif;">HMTL</div>',
0,'#f66','#666');</script>
<script>hl(143,60,100,'#f33');</script>
<script>vl(69,60,52,'#f66');</script>
<script>vl(69,210,52,'#f66');</script>
<script>box2('b2',120,10,100,16,18,4,
'<div style="text-align:center;font:16px calibri,sans-serif;">JavaScript</div>',
0,"#f33",'#666');</script>
<script>box2('b3',120,160,100,16,18,4,
'<div style="text-align:center;font:16px calibri,sans-serif;">CSS</div>',
0,"#f33",'#666');</script>

wie hier auch gezeigt. Noch was ist mir aufgefallen: man braucht einen vernüftigen XHTML-Prolog für die Geschichte, sonst sieht es manchmal nicht so gut aus :)