How can you select all child elements recursively?
div.dropdown, div.dropdown > * {
color: red;
}
This class only throws a class on the defined className and all immediate children. How can you, in a simple way, pick all childNodes like this:
div.dropdown,
div.dropdown > *,
div.dropdown > * > *,
div.dropdown > * > * > *,
div.dropdown > * > * > * > * {
color: red;
}
Use a white space to match all descendants of an element:
div.dropdown * {
color: red;
}
x y matches every element y that is inside x, however deeply nested it may be - children, grandchildren and so on.
The asterisk * matches any element.
Official Specification: CSS 2.1: Chapter 5.5: Descendant Selectors
The rule is as following :
A B {
/* B is descendant of A */
}
A > B {
/* B is direct child of A */
}
So
div.dropdown *
instead of
div.dropdown > *
Descendant combinator
The descendant combinator — typically represented by a single space ("
") character — combines two selectors such that elements matched by
the second selector are selected if they have an ancestor (parent,
parent's parent, parent's parent's parent, etc.) element matching the
first selector.
details details {
margin-left:48px;
}
<details>
<summary>A</summary>
A is a letter in the alphabet.
</details>
<details open>
<summary>B</summary>
B is a letter in the alphabet.
<details open>
<summary>1</summary>
1 is a number.
<details open>
<summary>*</summary>
* is a character.
</details>
</details>
<details open>
<summary>2</summary>
2 is a number.
</details>
</details>
Related
Can somebody help translate bracket usage in Tailwind.css?
In Example 1: - what does [&_*] mean?
In Example 2: what does the nested bracket combined with _& mean?
Example 1:
document.documentElement.classList.add('[&_*]:!transition-none')
Example 2:
<LightIcon className="hidden h-4 w-4 fill-slate-400 [:not(.dark)[data-theme=system]_&]:block" />
The closest I can get is the [] refers to attribute selection (in general) for .css and the Ampersand in is used by PostCSS processing in "normal" SASS nesting rules (as defined by tailwind's default nesting declaration support provided by postcss-nested).
What you are seeing is the usage of Tailwind's arbitrary variants feature.
Inside the square brackets is a CSS selector (or media query, I won't be talking about that here), with the ampersand (&) a substitute for the element that the class is being applied to. The nested brackets are attribute selectors, like with standard CSS selectors, as you correctly inferred in your Stacked Overflow question. Underscore is used instead of spaces in a CSS selector.
To give a few examples:
<div class="foo">
<div class="[.foo_&]:text-white"></div>
</div>
is conceptually like:
<div class="foo">
<div class="bar"></div>
</div>
<style>
/**
* .foo .bar
* ↓
* .foo &
* ↓
* .foo_&
*/
.foo .bar {
color: white;
}
</style>
With .bar now &, since .bar is the element we are applying the class/style to.
Another example:
<div class="foo"></div><div class="[.foo+&]:text-white"></div>
is conceptually like:
<div class="foo"></div><div class="bar"></div>
<style>
/**
* .foo + .bar
* ↓
* .foo + &
* ↓
* .foo+&
*/
.foo + .bar {
color: white;
}
</style>
The + grammar in CSS selectors does not strictly need spaces around it, so we can remove them for a more concise arbitrary variant syntax.
<div data-foo class="[&[data-foo]]:text-white"></div>
is conceptually like:
<div data-foo class="bar"></div>
<style>
/**
* .bar[data-foo]
* ↓
* &[data-foo]
*/
.bar[data-foo] {
color: white;
}
</style>
Hopefully this example makes the nested brackets clear.
How can I specify :first-of-type of the entire document?
I want to style the first <p> of the HTML, no mater where it is located (I don't want to write section p:first-of-type because it may be located elsewhere in a different HTML document).
p {
background:red;
}
p:first-of-type {
background:pink;
}
p:last-of-type {
background:yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
With CSS alone this unfortunately isn't possible. The documentation for the :first-of-type pseudo-class states:
The :first-of-type pseudo-class represents an element that is the first sibling of its type in the list of children of its parent element.
This means that :first-of-type is applied to the first element of its type relative to its parent and not the document's root (or the body element, in this case).
JavaScript solutions
:first-of-type
We can achieve this by introducing some JavaScript. All we need for this is JavaScript's querySelector() method, which pulls the first matching element from the selector specified.
In this example I've altered your :first-of-type pseudo-class to instead be a class of "first-of-type", then used JavaScript to add this class to the element returned when using querySelector('p'):
document.querySelector('p').className += ' first-of-type';
p {
background:red;
}
p.first-of-type {
background: pink;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
:nth-child and :last-of-type
As for :nth-child and :last-of-type, we can instead make use of a similar method JavaScript gives us: querySelectorAll(). This method pulls all matching elements into a NodeList (which is similar to an array), which we can then iterate through or select specific elements from within through the index:
var elems = document.querySelectorAll('p');
// nth-of-type = NodeList[n - 1]
// e.g. to select the 3rd p element ("333"):
if (elems.length >= 2)
elems[2].className += ' nth-of-type';
// last-of-type = NodeList length - 1
if (elems.length)
elems[elems.length - 1].className += ' last-of-type';
p {
background:red;
}
p.nth-of-type {
background: pink;
}
p.last-of-type {
background: yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
Note that I've included if statements around both selectors to ensure the elems NodeList has enough elements, otherwise an error will be thrown.
I know that the spec currently only allows compound selectors for ::slotted, i.e. ::slotted(my-first + my-second) is not allowed, but should something like this be working?
::slotted(x-first) + ::slotted(x-second) { /* css */ }
Is there any way to target slotted siblings (other than with global css)? And if not, where would I file such a request? Thanks.
Sure you can select siblings of slots / slotted.
The thing you can not do is select a element which has been slotted and is not a top-level node.
Select siblings:
slot[name=<slotname>] ~ <selector>
Select slotted top-level node
::slotted(<compound-selector>)
A compound-selector contains a tag/class/id/name etc. but must not have any combinators. Like <space> for example.
.myClass OK
<anyTag>[<anyAttribute>[=<anyValue>]] OK
.<myClass> > .<anotherClass> NO
Examples
var element = document.querySelector('.templateMe');
var shadow = element.attachShadow({mode: 'open'});
var template = document.querySelector('.myTemplate');
shadow.appendChild(template.content.cloneNode(true));
<template class="myTemplate">
<style type="text/css">
::slotted([slot=slot1]) { /* slot1 every slotted element - YES */
color: red;
}
slot[name=slot1] { /* slot1 itself - YES */
text-decoration: underline;
}
slot[name=slot1] + .siblingA { /* slot1 siblingA (direct sibling) - YES */
color: green;
}
slot[name=slot1] ~ .siblingB { /* slot1 siblingB (any sibling) - YES */
color: orange;
}
slot[name=slot2]::slotted(.selectMeA) { /* slot2 TOP-LEVEL CHILD (slotted) - YES */
color: purple;
}
slot[name=slot2]::slotted(.selectMeB) { /* slot2 NOT TOP-LEVEL CHILD - NO */
font-weight: bold;
}
slot[name=slot2]::slotted(.selectMeC[name=myName]) { /* slot2 TOP-LEVEL CHILD (slotted) - YES */
color: khaki;
}
slot[name=slot2] + .siblingC { /* slot2 sibling - YES */
color: blue;
}
</style>
<div>
<slot name="slot1"></slot>
<div class="siblingA">Sibling A of Slot 1</div>
<div class="siblingB">Sibling B of Slot 1</div>
</div>
<hr/>
<div>
<slot name="slot2"></slot>
<div class="siblingC">Sibling C of Slot 2</div>
</div>
</template>
<div class='templateMe'>
<span slot="slot1">Im in Solt 1</span>
<span slot="slot2" class="selectMeA">
Im in Solt 2, im selectable.
<div class='selectMeB'>
NOT selectable (because no top level node of slotted)!
</div>
</span>
<span slot="slot2" class="selectMeC" name="myName">Im in Solt 2 too and selectable!</span>
</div>
More here.
slotted elements (coming from light DOM), ::slotted(selector) allows to select slotted elements themselves, but not their children.
DOM that is placed into a slot is supposed to be controlled by the CSS that owns that DOM and not by the Custom Element.
The Web Component it allowed very minor CSS control over the DOM that is placed into your Slot. Pretty much just the top level elements (And things that are auto inherited by child nodes.)
This was a conscious decision and will probably never change.
How can I specify :first-of-type of the entire document?
I want to style the first <p> of the HTML, no mater where it is located (I don't want to write section p:first-of-type because it may be located elsewhere in a different HTML document).
p {
background:red;
}
p:first-of-type {
background:pink;
}
p:last-of-type {
background:yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
With CSS alone this unfortunately isn't possible. The documentation for the :first-of-type pseudo-class states:
The :first-of-type pseudo-class represents an element that is the first sibling of its type in the list of children of its parent element.
This means that :first-of-type is applied to the first element of its type relative to its parent and not the document's root (or the body element, in this case).
JavaScript solutions
:first-of-type
We can achieve this by introducing some JavaScript. All we need for this is JavaScript's querySelector() method, which pulls the first matching element from the selector specified.
In this example I've altered your :first-of-type pseudo-class to instead be a class of "first-of-type", then used JavaScript to add this class to the element returned when using querySelector('p'):
document.querySelector('p').className += ' first-of-type';
p {
background:red;
}
p.first-of-type {
background: pink;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
:nth-child and :last-of-type
As for :nth-child and :last-of-type, we can instead make use of a similar method JavaScript gives us: querySelectorAll(). This method pulls all matching elements into a NodeList (which is similar to an array), which we can then iterate through or select specific elements from within through the index:
var elems = document.querySelectorAll('p');
// nth-of-type = NodeList[n - 1]
// e.g. to select the 3rd p element ("333"):
if (elems.length >= 2)
elems[2].className += ' nth-of-type';
// last-of-type = NodeList length - 1
if (elems.length)
elems[elems.length - 1].className += ' last-of-type';
p {
background:red;
}
p.nth-of-type {
background: pink;
}
p.last-of-type {
background: yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
Note that I've included if statements around both selectors to ensure the elems NodeList has enough elements, otherwise an error will be thrown.
How can you redefine a class if its in another specific class?
div.cls {
color:blue;
}
div.tst > div.cls {
color:red;
}
<div class="cls">test</div> // text color = blue
<div class="tst">
<div class="cls">test</div> // text color = red
<div>
<div class="cls">test</div> // text color = blue
</div>
<div>
How to make the last one also red?
jsfiddle
http://jsfiddle.net/gpD7H/
I used this, it work for me:
.name-of-parent * { color: red; }
Use the descendant selector [W3C]: div.tst div.cls
> is the child selector [W3C] and will only match children of an element.
Exactly like that. However, your second division won't be red text because it's also contained within another division. The > selector only matches to the immediate children under the element matched before it, so it's looking inside div.tst at only one level. Try removing the > from the selector:
div.tst div.cls {
color:red;
}
Your updated jsFiddle