Trennung von CSS und JavaScript

Es kann sein, dass Dir aufgefallen ist dass wir in allen vorhergehenden Beispielen zwar Wasser gepredigt, doch Wein getrunken haben.

Unser Fehler

Wir haben zwar die Struktur von dem Verhalten der Seite getrennt, andererseits aber Seitenstil per JavaScript definiert, was genauso schlecht ist.

Wir definierten den Seitenstil indem wir das style Attribut und dessen Unterattribute veränderten:

 if(!document.getElementById('errormsg')){
  var em=document.createElement('p');
  em.id='errormsg';
  em.style.border='2px solid #c00';
  em.style.padding='5px';
  em.style.width='20em';
  em.appendChild(document.createTextNode('Please enter 
  or change the fields marked with a '))
  i=document.createElement('img');
  i.src='img/alert.gif';
  i.alt='Error';
  i.title='This field has an error!';
  em.appendChild(i);
}

Das bedeutet, dass wann immer wir das Aussehen unserer Erweiterungen ändern wollen, wir das im JavaScript vornehmen müssen, was weder praktikabel, noch besonders schlau ist.

Es gibt mehrere Möglichkeiten CSS- Definitionen einem Element dynamisch hinzuzufügen. Eine Möglichkeit ist es die ID zu ändern, indem wir das ID Attribut neu belegen. Eine flexibelere Lösung ist Klassen hinzuzufügen, vor allem weil ein Element mehrere Klassen haben kann.

Die Struktur mehrerer Klassen

Um in einem Element mehr als eine Klasse zu verwenden, müssen die Klassen durch ein Leerzeichen getrennt hinzugefügt werden: <div class="special highlight kids"> Die meisten modernen Webbrowser unterstützen dies, ein paar haben jedoch Fehler in der Implementierung. MSIE auf Macintosh mag beispielsweise keine Klassen, die den Namen einer anderen beinhalten oder wenn vor der ersten oder nach der letzten Klasse ein Leerzeichen steht.

Klassen per JavaScript hinzufügen

Um eine Klasse einem bestimmten Element hinzuzufügen, ändern wir dessen className Attribut. Wenn wir beispielsweise das Aussehen eines Menus ändern wollen, wenn der Browser DOM unterstützt, geht das folgendermaßen:

HTML:
<ul id="nav">
  [...]
</ul>
Javascript:
if(document.getElementById && document.createTextNode)
{
  if(document.getElementById('nav'))
  {
    document.getElementById('nav').className='isDOM';
  }
}

Das erlaubt uns in unserem CSS zwei verschiedene Aussehen zu definieren:

ul#nav{
  [...]
}
ul#nav.isDOM{
  [...]
}

Allerdings wird in dem vorherigen Beispiel jede Klasse, die dem Element bereits hinzugefügt wurde, überschrieben. Wir müssen also prüfen, ob das Element bereits eine Klasse hat, und wenn dem so ist, ein Leerzeichen gefolgt von der neuen Klasse anfügen.

if(document.getElementById && document.createTextNode)
{
  var n=document.getElementById('nav');
  if(n)
  {
    n.className+=n.className?' isDOM':'isDOM';
  }
}

Das gleiche Problem tritt auf wenn wir Klassen entfernen, da manche Webbrowser class="foo bar " nicht unterstützen. Auf die Dauer kann das ziemlich nervig werden, daher ist es besser eine wiederverwendbare Funktion zu schreiben, um diese Aufgabe zu erledigen.

function jscss(a,o,c1,c2)
{
  switch (a){
    case 'swap':
      o.className=!jscss('check',o,c1)?o.className.replace(c2,c1): <-
      o.className.replace(c1,c2);
    break;
    case 'add':
      if(!jscss('check',o,c1)){o.className+=o.className?' '+c1:c1;}
    break;
    case 'remove':
      var rep=o.className.match(' '+c1)?' '+c1:c1;
      o.className=o.className.replace(rep,'');
    break;
    case 'check':
      return new RegExp('\\b'+c1+'\\b').test(o.className)
    break;
  }
}

Diese Beispielfunktion erwartet vier Parameter

a
gibt an, welche Aktion die Funktion ausführen soll.
o
das Objekt, auf das die Aktion angewandt wird.
c1
der Name der ersten Klasse
c2
der Name der zweiten Klasse

Mögliche Aktionen sind:

swap
tauscht Klasse c1 gegen Klasse c2 aus.
add
fügt Klasse c1 dem Objekt o hinzu.
remove
löscht Klasse c1.
check
prüft, ob Klasse c1 schon dem Objekt o hinzugefügt wurde und gibt true oder false zurück.

Als Beispiel wollen wir erreichen, dass der Besucher die Überschriften der zweiten Ebene aktivieren kann, um das darauf folgende Element zu verstecken und anzuzeigen. Weiterhin soll die Überschrift eine andere Klasse erhalten, wenn sie "aktiv" ist, oder wenn sich der Mauszeiger über ihr befindet.

CSS:
.hidden{
  display:none;
}
.shown{
  display:block;
}
.trigger{
  background:#ccf;
}
.open{
  background:#66f;
}
.hover{
  background:#99c;
}
JS:
function collapse()
{
// überprüfe ob DOM vorhanden, ansonsten breche ab
  if(!document.createTextNode){return;}

// Erstelle einen neuen Absatz, der erklärt, das die 
// Überschriften aktivierbar sind
  var p=document.createElement('p');
  p.appendChild(document.createTextNode('Click on the headlines to 
  collapse and expand the section'));

// gehe durch alle Überschrifen der zweiten Ebene
  var heads=document.getElementsByTagName('h2');
  for(var i=0;i<heads.length;i++)
  {
// nehme das nächste Element (die Schleife ist nötig,
// um Leerzeilenprobleme zu vermeiden
      var tohide=heads[i].nextSibling;
      while(tohide.nodeType!=1)
      {
        tohide=tohide.nextSibling;
      }
// verstecke das Element, indem die Klasse hidden 
// angefügt wird, und füge die Klasse
// 'trigger' an der Überschrift an
      cssjs('add',tohide,'hidden')
      cssjs('add',heads[i],'trigger')
// speichere das Element in einem Attriut
      heads[i].tohide=tohide;
// füge der Überschrift bei Mausberührung 
// die Klasse hover hinzu
      heads[i].onmouseover=function()
      {
        cssjs('add',this,'hover');
      }
// lösche die Klasse, wenn die Maus wegbewegt wird
      heads[i].onmouseout=function()
      {
        cssjs('remove',this,'hover');
      }
// wenn der Besucher die Überschrift aktiviert
      heads[i].onclick=function()
      {
// prüe, ob das folgende Element bereits 
// die Klasse hidden hat
        if(cssjs('check',this.tohide,'hidden'))
        {
// ersetze hidden durch shown und trigger durch 
// open
          cssjs('swap',this,'trigger','open');      
          cssjs('swap',this.tohide,'hidden','shown');      
        } else {
// und umgekehrt
          cssjs('swap',this,'open','trigger');      
          cssjs('swap',this.tohide,'shown','hidden');      
        }
      }
// füge den neuen Absatz vor der ersten Überschrift ein
  document.body.insertBefore(p,document.getElementsByTagName('h2')[0]);
  }
  function cssjs(a,o,c1,c2)
  {
    [...]
  }
}
window.onload=collapse;
Probiere dieses Beispiel aus.

Auf diese Art und Weise haben wir Struktur, Darstellung und Verhalten der Webseite vollkommen getrennt und einen ziemlich komplexen Effekt erstellt. Die Abänderung dieses Effekts ist einfach und erfordert kein JavaScript-Wissen.

Sichere css.js für deine eigenen Versuche, indem du das Ziel des Verweises auf deine Festplatte speicherst.

Creative Commons License Unless otherwise expressly stated, all original material of whatever nature created by Christian Heilmann and included in this web site and any related pages is licensed under the Creative Commons License.