kniffelig: passenden Selektor finden
![](/uploads/default_avatar/thumb/missing.png)
- css
2 J o
0 1unitedpower0 Felix Riesterer
0 Rolf B
0 1unitedpower0 Rolf B
0 1unitedpower0 Rolf B
0 dedlfix
0 Rolf B
0 1unitedpower
0 dedlfix
0 Rolf B
Liebe Mitlesende,
ich suche das jeweils erste Element, das zu einer bestimmten Klasse gehört:
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td class="a">3</td>
<td class="a">4</td>
<td>5</td>
<td class="a">6</td>
<td class="b">7</td>
<td>8</td>
<td class="b">9</td>
<td>10</td>
</tr>
</tbody>
Ich habe folgendes versucht, was aber nicht greift:
tbody .a:first-of-type { font-weight: bold; }
tbody .b:first-of-type { color: red; }
Folgerichtig findet der FF auch mit JavaScript nichts:
document.querySelectorAll("tbody .a:first-of-type"); // leere NodeList
Mit welchem Selektor erreiche ich mein Ziel?
Liebe Grüße
Felix Riesterer
Hey,
die einzige Möglichkeit die ich dafür kenne ist tbody .a {...} tbody .a ~ .a {...}
.
Gruß
Jo
Hallo,
die einzige Möglichkeit die ich dafür kenne ist
tbody .a ~ .a
.
also:
tbody .a {
font-weight: bold;
}
tbody .a ~ .a {
font-weight: normal;
}
Gruß
Kalk
Hey,
Genau, mir ist erst hinterher aufgefallen das ich die wichtige Anweisung vergessen habe. Man überschreibt ja die vorherige Regel wieder für alle Siblings. Hier nochmal im Fiddle.
Gruß
Jo
Hallo,
Hier nochmal im Fiddle.
Die Idee mit dem inherit
ist bestimmt sinnvoll. Warum nimmst du das nicht auch bei der Farbe?
Gruß
Kalk
Hallo,
Hier nochmal im Fiddle.
Die Idee mit dem
inherit
ist bestimmt sinnvoll. Warum nimmst du das nicht auch bei der Farbe?
Damit wollte ich natürlich andeuten das man die folgenden Siblings auch in einer anderen Farbe darstellen lassen kann.
Nein ich habe das nur schnell noch hinzugefügt und dann nicht mehr dran gedacht.
Gruß
Jo
@@Tabellenkalk
Die Idee mit dem
inherit
ist bestimmt sinnvoll.
Die Idee mit dem inherit
ist mit Vorsicht zu genießen. Das funktioniert nicht, wenn die Tabellenzellen eine Hintergrundfarbe haben. Ebensowenig revert
und unset
.
In dem Fall muss man die Hintergrundfarbe von .a ~ .a
auf die Hintergrundfarbe zurücksetzen. Custom properties können helfen, den Code DRY zu halten.
☞ Codepen
LLAP 🖖
@@Gunnar Bittersmann
In dem Fall muss man die Hintergrundfarbe von
.a ~ .a
auf die Hintergrundfarbe zurücksetzen. Custom properties können helfen, den Code DRY zu halten.
Einfach die Selektoren in einer Regel aufzuzählen aber auch: neuer Codepen.
LLAP 🖖
Lieber Tabellenkalk,
vielen Dank! Mit Deiner Idee komme ich zu meiner gewünschten Darstellung.
Liebe Grüße
Felix Riesterer
Hallo,
Mit Deiner Idee
äh, meinten Sie: Mit J os Idee?
Mir war sie nur unterbewusst und ich sah, dass J o den wesentlichen Trick zu erwähnen vergaß.
Gruß
Kalk
ich suche das jeweils erste Element, das zu einer bestimmten Klasse gehört […]
Folgerichtig findet der FF auch mit JavaScript nichts:
document.querySelectorAll("tbody .a:first-of-type"); // leere NodeList
Mit welchem Selektor erreiche ich mein Ziel?
In JavaScript sollte document.querySelector("tbody .a")
helfen.
Lieber 1unitedpower,
In JavaScript sollte
document.querySelector("tbody .a")
helfen.
damit finde ich das erste Element, das zu dieser Klasse gehört. In den anderen Zeilen der Tabelle fände ich die jeweils ersten Elemente nicht mehr, da Du ja nicht querySelectorAll
einsetzt. Außerdem war der Weg über JavaScript nur ein Test, um zu sehen, dass der Browser an sich mit den Selektoren nichts findet - weder mit CSS noch mit JavaScript.
Liebe Grüße
Felix Riesterer
Hallo Felix,
damit finde ich das erste Element, das zu dieser Klasse gehört.
Ja. Das war doch dein Wunsch, oder nicht? Das erste Element, das Klasse a hat, soll fett angezeigt werden. Und das Problem in deinem Versuch ist, dass .a:first-child
dann matcht, wenn das Element die Klasse a hat UND das erste Kind-Element ist.
Ok, lese gerade 1ups Beitrag - bei mehreren TBODY funktioniert es nicht. Dann sieht das JS etwas komplizierter aus...
Rolf
Lieber Rolf,
Und das Problem in deinem Versuch ist, dass
.a:first-child
dann matcht, wenn das Element die Klasse a hat UND das erste Kind-Element ist.
ich dachte, ich hätte :first-of-type
notiert...
Liebe Grüße
Felix Riesterer
Hallo Felix,
ich dachte, ich hätte :first-of-type notiert...
Ja gut, hast Du, aber die Argumentation ist die gleiche. Das getroffene Element muss das erste seines Typs (hier also td) sein und die Klasse a tragen. Dann gibt's den Match.
Was Du willst, ist der von mir im anderen Beitrag erwähnte of Operator für nth-of-type. Das ist eine Umbenennung vom W3C, vorher hieß das nth-match. Steht so im Spec Draft, sonst hätt ich das auch nicht gewusst.
Rolf
In JavaScript sollte
document.querySelector("tbody .a")
helfen.
Noch nicht ganz. Ich habe den Fall vergessen, dass es mehrere tbodys geben kann. Jos Idee lässt sich aber auch auf JS übertragen:
[...document.querySelectorAll('tbody .a')].filter(e => !e.matches('.a ~ .a'));
Hallo 1unitedpower,
document.querySelectorAll('tbody .a')].filter(e => !e.matches('.a ~ .a'));
Da fehlt was:
if (!Nodelist.prototype.filter)
Nodelist.prototype.filter = Array.prototype.filter;
Weil querySelectorAll ja eine Nodelist liefert, kein Array.
Rolf
if (!Nodelist.prototype.filter) Nodelist.prototype.filter = Array.prototype.filter;
Weil querySelectorAll ja eine Nodelist liefert, kein Array.
Deshalb habe ich ja aus der NodeList zuvor ein Array gemacht. Mit der Kurzschreibweise [...xs]
.
Hallo 1unitedpower,
AUTSCH. Das habe ich nicht als JS Syntax erkannt.
Nachlesen geh
Aber - wäre das nicht das Erstellen einer Kopie?
Rolf
Tach!
AUTSCH. Das habe ich nicht als JS Syntax erkannt.
Ja, das ist so ein neumodischer Kram, der im Standardbrowser IE6 nicht mehr läuft. Kein Wunder, dass man das nicht kennt ... 😉
Aber - wäre das nicht das Erstellen einer Kopie?
Jein, nur eine Kopie der Referenzen.
dedlfix.
Hallo dedlfix,
Standardbrowser IE6
Lach nur. Solange mein Brötchengeber den IE11 in der Breite einsetzt, ist das meine Baseline, auf der mein Code laufen muss. Das wird sich hoffentlich bald ändern...
Aber solange der IE11 noch über 7% der Desktop-Browser repräsentiert (Quelle: sowohl Can I use wenn man die Quote bei Desktop ausrechnet, also auch Statista), ist er für mich ein relevanter Browser. JavaScript, das auf diesem Browser nicht läuft, ist zu vermeiden. Und da ich bisher keinen Bock auf einen Transpiler in meinem Toolstack hatte, bleibe ich eben bodenständig...
Rolf
Aber - wäre das nicht das Erstellen einer Kopie?
Möglich, dass das eine shallow copy erstellt wird. Andererseits könnte eine JavaScript-Engine den Kopiervorgang auch über Stream Fusion wegoptimieren. Ob das relevant für die Performance oder den Speicherbedarf ist, müsste man durch Profiling herausfinden. Grundsätzlich optimiere ich aber zunächst nur für die Lesbarkeit. Performance-Optimierung auf Verdacht ist nicht sonderlich effektiv und effizient.
Tach!
Nodelist.prototype.filter = Array.prototype.filter;
Weil querySelectorAll ja eine Nodelist liefert, kein Array.
Auf den ersten Blick sah mir diese Lösung recht clever aus. Einfach nur eine Referenz umbiegen, und schon hat die NodeList alle Methoden eines Arrays. Aber dann kamen mir Zweifel, ob das wirklich eine gute Idee ist. Eine definitive Antwort habe ich nicht und kann nur meine Bedenken äußern.
Wenn das funktionieren soll, muss die NodeList in ihren Datenstrukturen einem Array entsprechen, so dass die Array-Funktionen exakt zugreifen können und nicht im Leeren oder auf etwas anderem landen. Oder aber die Array-Methoden verwenden ihrerseits (zufälligerweise?) nur genau die Zugriffswege, die auch die NodeList bietet. Und das müsste auf allen Implementationen gleichermaßen funktionieren.
Ist das denn vorgesehen, dass sowas problemlos klappen kann? Oder sind meine Bedenken anderweitig unbegründet?
dedlfix.
Hallo dedlfix,
ob ich die filter-Methode in den Prototypen der Nodelist kopiere oder ob ich
Array.prototype.filter.call(nodelist, callback)
schreibe, hat den gleichen Effekt. Dieses Vorgehen funktioniert bei vielen Array-Funktionen, weil die nämlich nichts weiter brauchen als den Indexierungs-Operator und die length Eigenschaft. Garantiert ist das nicht, aber zumindest für die forEach Methode schlägt sogar MDN vor, die forEach Methode des Array-Prototypen mit call aufzurufen. Und weil dieses „Unterschieben eines fremden this“ in JavaScript durch call/apply nichts ungewöhnliches ist, kann man davon ausgehen, dass die Array-Prototypfunktionen auf Leiharbeit dieser Art eingerichtet sind. Einen Beweis oder eine Garantie dafür habe ich natürlich nicht...
Natürlich hat es Risiken, eine Nodelist ist live und ein Array ist statisch. Man findet auch Beispiele, die es so machen:
Array.prototyle.slice.call(nodelist).filter(callback)
was die Elemente der Nodelist ebenfalls zunächst in ein temporäres Array kopiert.
Ich frage mich aber, was passieren kann. JavaScript ist singlethreaded, und da man während des filter-Callbacks typischerweise nicht am DOM herumfummeln wird, sollte sich die Nodelist während des Filter-Durchlaufs nicht ändern können.
Rolf
Tach!
Dieses Vorgehen funktioniert bei vielen Array-Funktionen, weil die nämlich nichts weiter brauchen als den Indexierungs-Operator und die length Eigenschaft. Garantiert ist das nicht,
Klingt zumindest plausibel, wenn der Indexzugriff alles ist, was die Array-Methoden brauchen.
Natürlich hat es Risiken, eine Nodelist ist live und ein Array ist statisch.
Ich frage mich aber, was passieren kann. JavaScript ist singlethreaded, und da man während des filter-Callbacks typischerweise nicht am DOM herumfummeln wird, sollte sich die Nodelist während des Filter-Durchlaufs nicht ändern können.
Sehe ich auch so. Die Risiken sollten nur entstehen, wenn man die NodeList zwischenzeitlich unbeaufsichtigt lässt. Asynchrone Ereignisse grätschen ja nicht dazwischen, sondern stellen sich hinten an die Event-Loop an. (Absichtliche Modifikationen, wie Breakpoint aktivieren und währenddessen am DOM manipulieren halte ich für vernachlässigbar.)
dedlfix.
Hallo Felix,
das W3C arbeitet noch dran.
Der Selektor wäre dann td:nth-child(1 of .a). Es scheint aber, als ob das noch kein Browser unterstützte.
Update: Hier ist die caniuse-Seite dazu.
Bis dahin muss es wohl bei der Fummelei mit Geschwisterselektoren bleiben.
Rolf
Lieber Rolf,
das W3C arbeitet noch dran.
Der Selektor wäre dann td:nth-child(1 of .a).
interessant. Warum ist mein Selektor vom Gedankengang her falsch? Warum würde es den obigen dafür benötigen?
Es scheint aber, als ob das noch kein Browser unterstützte.
Habe vor Deinem Posting auch noch nichts davon gehört. Bin nicht so an der Entwicklerfront...
Bis dahin muss es wohl bei der Fummelei mit Geschwisterselektoren bleiben.
Mir wäre es lieber gewesen, wenn die Logik an sich bereits gegriffen hätte. Warum sollte :nth-of-kind
nur für Element-Namen gelten? Warum nicht für alle Elemente, auf die das Kriterium an sich zutrifft?
Liebe Grüße
Felix Riesterer
@@Felix Riesterer
Warum sollte
:nth-of-kind
nur für Element-Namen gelten?
Es heißt :nth-of-type
und zielt – wie der Name verspricht – auf Elementtypen.
LLAP 🖖
Hallo Felix,
Habe vor Deinem Posting auch noch nichts davon gehört. Bin nicht so an der Entwicklerfront...
Ich auch nicht 😂. Frisch ergoogelt.
Warum dein Selektor nicht greift habe ich oben beschrieben.
Rolf
Mir wäre es lieber gewesen, wenn die Logik an sich bereits gegriffen hätte. Warum sollte
:nth-of-kind
nur für Element-Namen gelten? Warum nicht für alle Elemente, auf die das Kriterium an sich zutrifft?
Die Frage hast du dir hier selber schon beanwortet. Du hättest dann das gleiche Problem, an dem mein erster JavaScript Vorschlag leidet.
Aloha ;)
Die Frage hast du dir hier selber schon beanwortet. Du hättest dann das gleiche Problem, an dem mein erster JavaScript Vorschlag leidet.
Hmmm, weiß ich nicht. Sicher?
Die leere Node-List als Ergebnis ist damit eigentlich nicht zu erklären. Ein Element (das erste, aus dem ersten tbody) müsste so ja eigentlich gefunden werden?
Grüße,
RIDER
Hmmm, weiß ich nicht. Sicher?
Vielleicht habe ich Felix auch missverstanden.
Die leere Node-List als Ergebnis ist damit eigentlich nicht zu erklären. Ein Element (das erste, aus dem ersten tbody) müsste so ja eigentlich gefunden werden?
Wird es auch. Zitat Felix:
damit finde ich das erste Element, das zu dieser Klasse gehört
Aloha ;)
Wird es auch. Zitat Felix:
damit finde ich das erste Element, das zu dieser Klasse gehört
War das nicht auf deinen Vorschlag bezogen, im Kontrast zu seinem Selektor?
Grüße,
RIDER
War das nicht auf deinen Vorschlag bezogen, im Kontrast zu seinem Selektor?
Das hab ich in diesem Kontext geschrieben, ja. Das Problem mit meinem Code, auf das Felix dann aufmerksam gemacht hat, ist aber das gleiche Problem, das man sich einfahren würde, wenn man die Semantik von nth-of-type
so ausweitet, wie Felix es in diesem Teilthread gewünscht hat.
Mir wäre es lieber gewesen, wenn die Logik an sich bereits gegriffen hätte. Warum sollte :nth-of-kind nur für Element-Namen gelten? Warum nicht für alle Elemente, auf die das Kriterium an sich zutrifft?
Ich verstehe Felix hier so, dass er mit dem Kriterium den Selektor meint, der vor der Pseudoklasse :nth-of-type
steht. Ein Selektor tbody .a:nth-of-type(1)
bzw. tbody .a:first-of-type
würde dann ein einziges Element matchen. Wie schon gesagt, möchte ich nicht ausschließen, dass ich Felix in diesem Punkt missverstanden habe.
Aloha ;)
Hm, vielleicht reden auch wir beide aneinander vorbei.
Ich verstehe Felix hier so, dass er mit dem Kriterium den Selektor meint, der vor der Pseudoklasse
:nth-of-type
steht. Ein Selektortbody .a:nth-of-type(1)
bzw.tbody .a:first-of-type
würde dann ein einziges Element matchen.
Ja, ganz genau! Das würde dann ein einziges Element matchen. Eben das meine ich ja, und im OP hat sich das angehört, als würde eben nicht ein einziges Element matchen, sondern gar keines, und das kam mir seltsam vor.
Wie schon gesagt, möchte ich nicht ausschließen, dass ich Felix in diesem Punkt missverstanden habe.
Vielleicht hab auch ich ihn missverstanden. Aber selbst wenn er sich auf das bezog, was du meintest - bleibt für mich die im OP geschilderte Situation trotzdem nicht nachvollziehbar.
Grüße,
RIDER
@@Camping_RIDER
Ich verstehe Felix hier so, dass er mit dem Kriterium den Selektor meint, der vor der Pseudoklasse
:nth-of-type
steht. Ein Selektortbody .a:nth-of-type(1)
bzw.tbody .a:first-of-type
würde dann ein einziges Element matchen.Ja, ganz genau! Das würde dann ein einziges Element matchen.
Nei-en.
Eben das meine ich ja, und im OP hat sich das angehört, als würde eben nicht ein einziges Element matchen, sondern gar keines, und das kam mir seltsam vor.
Was ist daran seltsam? Es matcht keines, weil es kein Element der Klasse a gibt, welches das erste seines Typs ist.
Wie schon gesagt, möchte ich nicht ausschließen, dass ich Felix in diesem Punkt missverstanden habe.
Vielleicht hab auch ich ihn missverstanden.
Felix habt ihr schon richtig verstanden. Den Selektor habt ihr nicht richtig verstanden.
LLAP 🖖
Felix habt ihr schon richtig verstanden. Den Selektor habt ihr nicht richtig verstanden.
Wir redeten über ein fiktives Szenario was wäre, wenn sich der Selektors anders verhielte. Natürlich trifft das nicht auf die Realität zu, das ist die Natur der Sache.
@@1unitedpower
Felix habt ihr schon richtig verstanden. Den Selektor habt ihr nicht richtig verstanden.
Wir redeten über ein fiktives Szenario was wäre, wenn sich der Selektors anders verhielte. Natürlich trifft das nicht auf die Realität zu, das ist die Natur der Sache.
Ah. Dann war ich es, der euch nicht verstanden hat.
LLAP 🖖
Aloha ;)
Felix habt ihr schon richtig verstanden. Den Selektor habt ihr nicht richtig verstanden.
Wie wärs denn bitte, wenn ich schon offensichtlich was nicht verstanden habe, dass du mir erklärst, wo mein Denkfehler liegt? Immerhin hab ich genau danach gefragt.
Eben das meine ich ja, und im OP hat sich das angehört, als würde eben nicht ein einziges Element matchen, sondern gar keines, und das kam mir seltsam vor.
Was ist daran seltsam? Es matcht keines, weil es kein Element der Klasse a gibt, welches das erste seines Typs ist.
Erklär mir das. Ich sehe da ein Element der Klasse a, das das erste seiner Art („Element der Klasse a“) innerhalb seines Elternelements ist.
Inwiefern arbeitet der Selektor anders? Das war von Anfang an meine (und im Übrigen auch Felix') Frage.
Grüße,
RIDER
P.S.: Ich empfinde ein
Nei-en.
als sehr viel arroganter/hochnäsiger als ein einfaches „Nein“. Nur um das mal rückzuspiegeln.
@@Camping_RIDER
Was ist daran seltsam? Es matcht keines, weil es kein Element der Klasse a gibt, welches das erste seines Typs ist.
Erklär mir das. Ich sehe da ein Element der Klasse a, das das erste seiner Art („Element der Klasse a“) innerhalb seines Elternelements ist.
first-of-type heißt nicht „das erste seiner Art“, sondern „das erste seines Typs“. Das sagte ich doch vor Stunden schon.
Bei
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td class="a">3</td>
<td class="a">4</td>
<td>5</td>
<td class="a">6</td>
<td class="b">7</td>
<td>8</td>
<td class="b">9</td>
<td>10</td>
</tr>
</tbody>
ist das erste td
-Elements seines Typs das mit der 1 drin. Das gehört aber nicht der Klasse a an.
Das gesuchte erste Element, das der Klasse a angehört, ist das mit der 3 drin. Das ist aber nicht das erste seines Typs, sondern das dritte.
LLAP 🖖
Aloha ;)
first-of-type heißt nicht „das erste seiner Art“, sondern „das erste seines Typs“. Das sagte ich doch vor Stunden schon.
Ah, ich verstehe. Für mich war „Typ“ nicht gleichzeitig synonym mit „Elementtyp“. Denke das war auch das Problem, dem Felix da aufgesessen ist.
Vielleicht müsste die Erkenntnis noch im Wiki aufgenommen werden.
Bei
<tbody> <tr> <td>1</td> <td>2</td> <td class="a">3</td> <td class="a">4</td> <td>5</td> <td class="a">6</td> <td class="b">7</td> <td>8</td> <td class="b">9</td> <td>10</td> </tr> </tbody>
ist das erste
td
-Elements seines Typs das mit der 1 drin. Das gehört aber nicht der Klasse a an.Das gesuchte erste Element, das der Klasse a angehört, ist das mit der 3 drin. Das ist aber nicht das erste seines Typs, sondern das dritte.
Danke für die Erklärung!
Grüße,
RIDER
@@Camping_RIDER
P.S.: Ich empfinde ein
Nei-en.
als sehr viel arroganter/hochnäsiger als ein einfaches „Nein“. Nur um das mal rückzuspiegeln.
Deine Empfindung.
Meinerseits war es das nicht. Ich war leicht genervt, weil du offenbar meinen zuvor schon gegebenen Hinweis, dass „Typ“ Elementtyp meint, ignoriert hattest.
LLAP 🖖
Aloha ;)
Deine Empfindung.
Meinerseits war es das nicht.
Denk ich mir, deshalb sag ichs dir.
Ich war leicht genervt, weil du offenbar meinen zuvor schon gegebenen Hinweis, dass „Typ“ Elementtyp meint, ignoriert hattest.
Ne, nicht ignoriert. Zwar gelesen, aber irgendwie nicht richtig geistig durchdrungen.
Nach deiner erneuten Erklärung hab ich mir dann auch erstmal an den Kopf gefasst, weil ja eigentlich alles schon dastand.
Grüße,
RIDER