CSS, HTML und Javascript mit {stil}

querySelector / querySelectorAll

query Selector und query Selector All: Das erste Element oder alle Elemente

querySelector bzw. querySelectorAll wirken wie jQuery $(). Sie wählen Elemente anhand von CSS-Selektoren aus und geben ein einzelnes Element oder eine Liste der Treffer (Node List) zurück (ab IE8).

querySelector gibt das erste gefundene Element zurück, querySelectorAll gibt alle gefundenen Elemente in einer NodeList zurück.

Schon IE8 unterstützt querySelector() und querySelectorAll() – doch tatsächlich! Allerdings verstand IE8 nur CSS 2.1 Selektoren und funktionierte nicht mit HTML5-Tags.

querySelector

document.querySelector('h3')          selektiert das erste h3-Element     
document.querySelectorAll('h3')       selektiert alle h3-Elemente
document.querySelector('.ci')         gibt das erste Element mit der Klasse .ci zurück
document.querySelectorAll('.ci a')    gibt alle a-Elemente unterhalb der Klasse .ci zurück
document.querySelector('#postheader') gibt das Element mit id="postheader" zurück
document.querySelectorAll('li:nth-child(odd)') alle li-Elemente mit ungeradem Index 
document.querySelectorAll('div:not(.ignore)')  alle div-Elemente, die nicht zur CSS-Klasse .ignore gehören           

Und selbst das funktioniert:

document.querySelectorAll("h3, blockquote, .myclass")

sammelt alle h3- und blockquote-Elemente und alle Elemente mit der Klasse .myclass.

querySelector und querySelectorAll sind flexibler als document.getElementById() und getElementsByTagName() und obendrein schneller.

Beide Methoden können sowohl den ganzen DOM-Baum als auch einen einzelnen Zweig parsen. Jeder CSS-Selektor funktioniert als Parameter.

var bluetext = document.querySelector('h3[style="color:blue"]').innerText;

querySelectorAll

querySelectorAll() gibt alle Fundstellen als statische NodeList – staticNodeList – zurück. Eine NodeList sieht aus wie ein Array, verhält sich ähnlich wie ein Array, ist aber kein Array.

Eine statische NodeList ist von folgenden Änderungen des DOM-Baums nicht betroffen.

Die Eigenschaft length liefert die Anzahl der Fundstellen. Javascript kann also durch die Liste der Fundstellen wie bei einem Array iterieren.

var el = document.querySelectorAll ('li:nth-child(odd)');
for (var i=0; i<el.length; i++) {
   Mach was mit den li-Elementen mit ungeradem Index
}

Das ist nicht so komfortabel wie die each-Interation über alle Elemente in jQuery.

jQuery
$(selector).each(function(i, el){

});
Javascript
var el = document.querySelectorAll(selector);
Array.prototype.forEach.call(elements, function(el, i){

});

Ab IE 9

Das bequeme each() aus jQuery wird in Javascript durch Array.prototype.forEach.call() ersetzt: querySelectorAll gibt kein Array zurück, sondern eine NodeList, die nur aussieht als wäre sie ein Array.

querySelectorAll und forEach

Internet Explorer 9 unterstützt aber auch bereits Object.keys:

  • Erstes Element
  • Zweites Element
  • Drittes Element
var elems = document.querySelectorAll("#listelems li");
Object.keys(elems).forEach (function (val) {
   console.log (elems[val].innerHTML );
});
[LOG] Erstes Element
[LOG] Zweites Element
[LOG] Drittes Element

querySelector() und querySelectorAll() lösen komplexe CSS-Query-Strings auf, die klassische Methoden wie getElementById() und getElementsByTagName oder getElementsByClassName nur mit großem Aufwand umsetzen können. In einfachen Anwendungen ersetzen sie das Einbinden von jQuery (You might noch need jQuery). jQuery hat allerdings über die CSS-Querys hinaus Filter wie filter(), find(), children(), parent(), map(), not() und gleicht Browser-Inkonsistenzen aus.

querySelector und Pseudo-Elemente

Vor querySelector und querySelectorAll konnte Javascript keine Pseudo-Elemente wie ::before und ::after erreichen. In der Tat schafft das nicht einmal jQuery.

.circle:before {
	box-shadow: inset 150px 0 0 rgba(217, 127, 38, 0.2), 
                inset 0 150px 0 rgba(217, 127, 38, 0.2), 
                inset -150px 0 0 rgba(217, 127, 38, 0.2), 
                inset 0 -150px 0 rgba(217, 127, 38, 0.2);
}

Mit getComputedStyle funktioniert dann der Zugriff auf Pseudo-Elemente (gefunden bei treehouse):

var boxShadow = window.getComputedStyle (
    document.querySelector('.circle'), ':before').getPropertyValue('box-shadow');

liefert wie erwartet

rgba(217, 127, 38, 0.2) 150px 0px 0px 0px inset, 
rgba(217, 127, 38, 0.2) 0px 150px 0px 0px inset, 
rgba(217, 127, 38, 0.2) -150px 0px 0px 0px inset, 
rgba(217, 127, 38, 0.2) 0px -150px 0px 0px inset

Da wir hier ein Pseudo-Element vor uns haben und Pseudo-Elemente kein Teil des DOMs sind, kann Javascript die CSS-Regel nicht ohne Weiteres ändern.

Es gibt zwar getComputedStyle, aber kein setComputedStyle. Javascript kann allerdings ein style-Element anlegen und das Pseudo-Element mit innerHTML beschreiben. querySelector hängt das style-Element anschließend mit appendChild an das Ende von head.