Login schließen
Hinweis: In Ihrem Browser müssen Cookies und JavaScript aktiviert sein!
Login login
Übersichtliche Checkboxen

Ich wollte für interne Zwecke eine Verwaltungsseite schreiben. Auf der Seite würde dann eine größere Anzahl an Checkboxen zu sehen sein. Wenn man mehrere Spalten mit Checkboxen hat und die Seite so lang wird, dass man scrollen muss, dann verliert man schnell den Überblick, welche Box jetzt eigentlich was bedeutet.


Beispiel für viele Checkboxen: Drupal-Rechteverwaltung

Ich wollte deshalb die Boxen durch kleine Bilder ersetzen, die in deaktiviertem Zustand ausgegraut sind:

Das ganze klingt recht einfach, einfach eine unsichtbare Checkbox und zwei Grafiken; dazu ein wenig jQuery, welches beim Klick auf eine Grafik den Zustand der Checkbox ändert und passend dazu eine der beiden Grafiken ausblendet.

HTML:
<span class="image_checkbox">
    <input type="checkbox" name="active" style="display:none">
    <img class="img_off" src="img/active-off.png">
    <img class="img_on" src="img/active-on.png">
</span>

Javascript:
$(function() {
    // Bei Änderung der Checkbox Grafiken anpassen
    $('span.image_checkbox input').change(function(){
        if ($(this).prop('checked'))
        {
            $(this).siblings('.img_off').hide();
            $(this).siblings('.img_on').show();
        }
        else
        {
            $(this).siblings('.img_off').show();
            $(this).siblings('.img_on').hide();
        }
    });
    
    // Klick auf die Grafik ändert die Checkbox
    $('span.img_checkbox img').click(function(){
        var box = $(this).siblings('input');
        box.prop('checked',!box.prop('checked'));
        box.change();
    });
    
    // Grafiken nach dem Seitenaufbau synchronisieren
    $('span.img_checkbox input').change();
});

Wie sich zeigte, ist es aber gar nicht so einfach, die Grafiken synchron zur Checkbox zu halten. Der change-Eventhandler reagiert nämlich nur auf Änderung per Maus oder Tastatur. Für Checkboxen, die per checked-Attribut vorselektiert sind, muss man den Eventhandler nach dem Seitenaufbau „per Hand“ aufrufen. Das Gleiche gilt für Änderungen mittels Javascript, weshalb auch im click-Eventhandler der Grafik ein box.change() steht. Ein Klick auf den Reset-Buttons des Formulars löst ebenfalls kein change-Ereignis aus, sondern nur ein reset-Ereignis, allerdings VOR dem Reset.

Auch dieses Problem lässt sich lösen, indem man beim Auftreten eines reset-Ereignisses die Checkboxen selbst zurücksetzt und danach den change-Eventhandler aufruft:

$('form').on('reset',function(){
    $(this).find('span.image_checkbox input').each(function(){
        $(this).prop("checked", this.hasAttribute('checked'));
        $(this).change();
    });
});

$(this).attr('checked') ist übrigens nicht geeignet, um den initialen Wert zu ermitteln. attr() gibt aus Gründen der Abwärtskompatibilität den aktuellen Zustand der Checkbox aus.

Es gibt noch ein Ereignis DOMAttrModified, aber ich musste feststellen, dass auch dieses Ereignis nicht bei jeder Änderung der Checkbox eintritt.

Ich habe es schließlich aufgegeben, die verschiedenen Arten der Checkboxänderung einzeln per JavaScript abzufangen, denn ich habe dann noch eine einfachere Lösung gefunden: CSS

HTML:
<span class="image_checkbox">
    <input type="checkbox" name="active">
    <img src="img/active-off.png">
    <img src="img/active-on.png">
</span>
 
Javascript:
$(function() {
    $('span.img_checkbox img').click(function(){
        var box = $(this).siblings('input');
        box.prop('checked',!box.prop('checked'));
    });
});
 
CSS:
span.checkbox input  {
    display:none;
}

span.checkbox input ~ img  {
    display:none;
}

span.checkbox input + img  {
    display:inline;
}

span.checkbox input:checked ~ img  {
    display:inline;
}

span.checkbox input:checked + img  {
    display:none;
}

Hier mache ich mir die Geschwister-Selektoren zu Nutze: + wählt ein Element aus, das auf gleicher Ebene direkt hinter einem anderen Element steht. ~ wählt alle nachfolgenden Elemente auf der gleichen Ebene aus.

In Zukunft könnte das ganze noch simpler werden, denn CSS3 wird eine Eigenschaft namens filter haben, mit der man unter anderem Bilder grau färben kann. Man braucht dann nur noch eine Grafik. Funktionieren wird das ganze dann ungefähr so:

span.checkbox input + img  {
    filter:grayscale(1);
}

span.checkbox input:checked + img  {
    filter:none;
}

Im Moment ist die Browserunterstützung aber noch recht mangelhaft. filter:grayscale(1) versteht im Moment noch kein Browser, mit folgendem Code funktioniert es zumindest in manchen:

span.checkbox input + img  {
    filter: url(filters.svg#grayscale); /* Firefox 3.5+ */
    filter: gray; /* IE5+ */
    -webkit-filter: grayscale(1); /* Chrome 18+ */
}

span.checkbox input:checked + img  {
    filter: none;
    -webkit-filter: grayscale(0);
}

Die Firefox-Lösung benötigt dazu noch eine Datei, die den Filter beschreibt:

<svg xmlns="http://www.w3.org/2000/svg">
 <filter id="grayscale">
  <feColorMatrix type="saturate" values="0"/>
 </filter>
</svg>

Die aktuelle stabile Version von Chrome ist 17. Derzeit ist die Variante mit filter also noch nicht praxistauglich.

veröffentlicht am 21.02.12 um 11:01 Uhr
Tags: Webentwicklung, Computer

Kommentare

Es sind keine Kommentare vorhanden.

Kommentar verfassen

Name (notwendig)
Email (optional, wird nicht veröffentlicht)
Homepage (optional)

Kommentar:


Bitte übertrage die Zahl in umgekehrter Reihenfolge in das Feld Spamschutz!

Spamschutz (notwendig)