:root :empty :blank :nth-child() :nth-last-child() :first-child* :last-child :only-child :nth-of-type() :nth-last-of-type() :first-of-type :last-of-type :only-of-type
Estelle Weyl | @estellevw | Github | Press → key to advance.
:root :empty :blank :nth-child() :nth-last-child() :first-child* :last-child :only-child :nth-of-type() :nth-last-of-type() :first-of-type :last-of-type :only-of-type
:first-child :last-child :first-of-type :last-of-type :only-child :only-of-type
Easier to explain by example
:nth-
pseudo-classes:nth-child(3n) :nth-last-child(odd) :nth-of-type(5) :nth-last-of-type(3n+1)
starting from the top or bottom
:nth-
pseudo-classesTarget element or elements based on argument passed to the selector
:nth-of-type(even) :nth-of-type(odd) :nth-of-type(An+B) :nth-last-child(An+B [of S])
li:only-of-type{width: 100%;} li:nth-of-type(1):nth-last-of-type(2), li:nth-of-type(2):nth-last-of-type(1){width: 50%;} li:nth-of-type(1):nth-last-of-type(3), li:nth-of-type(3):nth-last-of-type(1), li:nth-of-type(2):nth-last-of-type(2){width: 33.33%;} li:nth-of-type(1):nth-last-of-type(4), li:nth-of-type(2):nth-last-of-type(3), li:nth-of-type(3):nth-last-of-type(2), li:nth-of-type(4):nth-last-of-type(1){width: 25%;}
:nth-child(An+B [of S]) :nth-last-child(An+B [of S])
li:nth-child(2n of .foo) li:nth-child(3n+1 of .bar)
Specificity is 0-1-0
for :nth-child(An+B)
, plus specificity of the most specific complex selector in S
select the 3rd li with the class of foo
:nth-child(3 of li.foo) /* matches #8 */
Select the 3rd li if it has the class foo
li.foo:nth-child(3) /* no match */
Match every even row of the visible rows
tr:nth-child(even of :not([hidden]))
:root
Selects the document root, which is <html>
:not
- Negation pseudo-classE:not(s1)
div:not(.excludeMe)
Specificity: weight of (s1)
, not the :not
.
*:not(h1) /* 0 - 0 - 1 */ *:not(.class) /* 0 - 1 - 0 */ *:not(#myId) /* 1 - 0 - 0 */
Supported everywhere since IE9
E:not(s1, s2)
div:not(.excludeMe, .excuseYou)
Reminder: if a browser doesn't recognize a pseudo-class, the entire selector block fails
"RESOLVED: Drop individual invalid selectors from selector lists in *all* selector functions that take such lists, *except* for :not()."
Most specific of (s1, .s2, #s3)
, in this case 1-0-0
.
:is(s1, s2) :matches(s1, s2)
RESOLVED: Rename :matches() to :is() and deprecate :matches()
E:is(s1, s2)
li:is([title], [role]) a {}
li[title] a, li[role] a {}
:is()
doesn't get invalidated if a parameter is invalid.
:matches(s1, s2)
:matches(#home, #contact) aside :matches(a:active, a:focus){}
#home aside a:active, #contact aside a:active, #home aside a:focus, #contact aside a:focus {}
Safari only, :-moz-any & :-webkit-any for FF & Chrome
:-webkit-any(article, aside) :-webkit-any(article, aside) h1 {} :-moz-any(article, aside) :-moz-any(article, aside) h1 {} :matches(article, aside) :matches(article, aside) h1 {} :is(article, aside) :is(article, aside) h1 {}
article article h1, article aside h1, aside article h1, aside aside h1 { }
article, aside { article, aside { h1 { /* sass nesting*/ } } }
a:-webkit-any(.foo, .bar, .bam) span {} a:-moz-any(.foo, .bar, .bam) span {} a:matches(.foo, .bar, .bam) span {} a:is(.foo, .bar, .bam) span {}
nav a:not(:matches(.foo, .bar, .bam)), nav a:not(:-webkit-any(.foo, .bar, .bam)), nav a:not(:-moz-any(.foo, .bar, .bam)), nav a:not(:is(.foo, .bar, .bam)), nav a:not(.foo, .bar, .bam), nav a:not(.foo):not(.bar).not(.bam) { }
:-webkit-any(header, aside, footer) [contenteditable]:hover { color: blue; cursor: pointer; } :-moz-any(header, aside, footer) [contenteditable]:hover { color: blue; cursor: pointer; } :matches(header, aside, footer) [contenteditable]:hover { color: blue; cursor: pointer; } :is(header, aside, footer) [contenteditable]:hover { color: blue; cursor: pointer; }
:is(header, aside, footer) [contenteditable]:hover { /* CSS Selectors level 4 */ color: blue; cursor: pointer; }
header, aside, footer { /* sass */ [contenteditable]:hover { color: blue; cursor: pointer; } }
header [contenteditable]:hover { /* CSS Selectors level 2 */ color: blue; cursor: pointer; } aside [contenteditable]:hover { color: blue; cursor: pointer; } footer [contenteditable]:hover { color: blue; cursor: pointer; }
The specificity is the specificity of its most specific argument:
:is(ul, ol, .list) > [hidden] { ... /* 0-2-0 */
ul > [hidden], ol > [hidden], /* 0-1-1 */ .list > [hidden] { /* 0-2-0 */
<ol> <li hidden>This matches</li> <li>This doesn't</li> </ol>
:where()
Same as :is(s1, s2)
, but with no specificity
Specificity sometimes makes life hard:
a:not(:hover) { text-decoration: none; } nav a { /* has lower specificity */ text-decoration: underline; }
:where()
adds no specificity weight
a:where(:not(:hover)) { text-decoration: none; } nav a { /* has greater specificity */ text-decoration: underline; }
:has(s1, s2)
Parent SelectorParent selector
document.querySelectorAll(':has(s1, s2)');
Contains a header
document.querySelectorAll('header:has(h1, h2, h3, h4, h5, h6)');
Contains no headers
document.querySelectorAll('header:not(:has(h1, h2, h3, h4, h5, h6))');
Contains something that is not a header
document.querySelectorAll('header:has(:not(h1, h2, h3, h4, h5, h6))');CanIUse.com
Matches if the element has the lang
attribute
html[lang|="en"]
Matches if the element is in the language, as determined by document language, headers, and lang attribute on ancestors.
p:lang(en)
:lang(l1, l2)
- Matches and language common to the country. Accepts comma separated values.
:lang(\*-ch, \*-be)
:dir()
- Matches content that is left to right (ltr
) or right to left (rtl
) based on language, dir
attribute, or surrounding text.
:dir(rtl)
Any element with an href
attribute
a:link /* unvisited links */ a:visited /* visited links */
CSS Selectors Level 4
a:any-link /* a:link, a:visited */ :local-link /* target absolute URL == document URL */ /* :not(:local-link) == external link */
:any-link
Any element with an href
attribute:
<a> <area> <link>
:any-link
is the same as :is(:link, :visited)
:local-link
:local-link { text-decoration: none; color: inherit; }
a:local-link { /* match links on this page or section of page (#fragment) */ }
a:not(:local-link) { /* on a different document or site */ }
:hover :active :focus
Note: always style :focus when you style :hover
:focus-visible :focus-within
:-moz-focusring
You can toggle :hover
, :active
, :focus
, and :focus-within
in DevTools
:hover :active :focus
a:visited:hover button:active:focus
Never, ever, ever do....
*:focus { outline: none; }
Improving accessibility:
:focus-visible
matches active elements:focus-visible
when focused, even if interaction doesn’t affect :focus
.:focus-visible
spot, the newly focused element should match :focus-visible
.:focus-visible
spot, the newly focused element should NOT match :focus-visible
either.:focus-visible
is applied to :focus
as well. :focus-visible
:target
:target
myPage.html#anchor <div id="anchor">ipsum lorem.... div:target::first-line { font-weight: bold; }
:target
presentation:target-within
:target :target-within
The :target-within
pseudo-class applies to elements for which the :target
pseudo class applies as well as to an element whose descendant in the flat tree (including non-element nodes, such as text nodes) matches the conditions for matching :target-within
.
:scope
:scope
Matches elements that are a reference point for selectors to match against.
/* Selects a scoped element */ :scope { background-color: blue; }
In CSS, :scope is the :root, since we don't have scoped CSS yet.
In JS, :scope
matches the element returned by querySelector(), querySelectorAll(), matches()
, or el.closest()
E || F
col.selected || td { /* matches all cells within the column's scope*/ }
:nth-col(An+B) :nth-last-col(An+B)
:current :current(s) :future :past
:playing :paused
There are lots of Developer Tool featues related to selectors, including pseudo classes.
:hover
, :active
, :visited
, :focus
, and :focus-within
.Add this HTML to the page you created in the intro
<figure> <div data-type="H"> <div></div> <div data-value="A">♥</div> </div> <div data-type="C"> <div></div> <div data-value="A">♣</div> </div> <div data-type="D"> <div></div> <div data-value="A">♦</div> </div> </figure>
There are three playing cards, each with a face side and a back, all inside a <figure>
container. For right now every card is an ace.
Create the following selector blocks in your css file:
The figure
figure {}
all the cards
[data-type] {}
backs of the cards
[data-type] > :first-child
card faces
[data-value]
first, second, and last card
[data-type]:first-of-type {} [data-type]:nth-of-type(2) {} [data-type]:last-of-type {}
faces of first, second and last cards
[data-type]:first-of-type [data-value]{} [data-type]:nth-of-type(2) [data-value] {} [data-type]:last-of-type [data-value] {}
red cards
[data-type="H" i], [data-type="D" i] {}
black cards
[data-type="C" i], [data-type="S" i] {}
hovered card
[data-type]:hover {}
Now that we know how to target cards without classes, let's add some classes to make our code easier to discuss. You can now add the card
, back
, and face
classes to your HTML.
<figure> <div class="card" data-type="H"> <div class="back"></div> <div class="face" data-value="A">♥</div> </div> <div class="card" data-type="C"> <div class="back"></div> <div class="face" data-value="A">♣</div> </div> <div class="card" data-type="D"> <div class="back"></div> <div class="face" data-value="A">♦</div> </div> </figure>
Your original selectors still all work.