The Future Generation of CSS Selectors: Level 4

By Louis Lazaris

Back in January 2014 I wrote the article The Current Generation of CSS3 Selectors. The goal of that article was to introduce the new generation of selectors that often fell under the “CSS3” umbrella. Thabet group of selectors has been well documented in a lot of places, and browser support for those features is quite strong (all browsers including IE9+).

The future of CSS selectors is also looking bright, with the Selectors Level 4 specification currently in Working Draft status, and an Editor’s Draft of the same spec still in progress (the editor’s draft is generally viewed as more authoritative).

This article will focus on the new selectors not discussed in my previous article. Browser support for many of these is pretty poor, so I don’t recommend using many of these in production. View this post as a peek into what’s to come when the spec is further along and browsers start their implementations. I’ve included demos for those that have support.

:read-only and :read-write

These selectors are pretty straightforward. Any element that’s editable by the user is in the “read-write” state. Otherwise, the element is in the “read-only” state.

Take the following HTML:

<input type="text" readonly>
<input type="text" disabled>
<input type="text">
<div contenteditable></div>

Now consider this CSS:

:read-only {
  outline: solid 1px blue;

:read-write {
  outline: solid 1px red;

Here’s a breakdown of what this CSS does in relation to the HTML:

  • The first two elements will have a blue outline because they are set to “readonly” and “disabled” in the HTML, respectively.
  • The third element will have a red outline because it’s naturally editable (“read-write”), as are all inputs by default. A textarea would be the same.
  • The last element (the div) will have a red outline because of the contenteditable attribute.

In the CSS I’m using these selectors universally (i.e. without applying them to any elements). This means the red outline would be applied to all divs, spans, and other naturally uneditable elements. It’s more likely that this would be used on specific form elements or elements with a class applied, to be more specific.

The :read-write pseudo-class is listed as “at-risk” in the Editor’s Draft, so it may be removed.

Browser Support for :read-only and :read-write
Chrome, Opera, Firefox, Safari.

Note: As shown in the demo below, the browsers that support these selectors identify the “disabled” input as “read-write”, which is not correct, according to the spec.

See the Pen Demo for :read-only and :read-write by SitePoint (@SitePoint) on CodePen.

The Default-option Pseudo-class: :default

The :default pseudo-class matches elements that qualify as “default” in relation to a set that they are part of. For example, a button element that’s the default submit button for a form or the default selected item in a set of radio buttons.

You can also have multiple defaults for a single group, as shown in this HTML snippet:

<input type="checkbox" value ="f" name="group" checked> Fruits
<input type="checkbox" value ="v" name="group"> Vegetables
<input type="checkbox" value ="m" name="group" checked> Meats
<input type="checkbox" value ="p" name="group" checked> Poultry
<input type="checkbox" value ="n" name="group"> Nuts
<input type="checkbox" value ="b" name="group"> Breads

Now let’s pair the HTML above with the following CSS:

input[type=checkbox]:default {
  outline: solid 1px hotpink;

In this case, all the elements with the checked attribute present will be styled with the outline.

Browser Support for :default
Chrome, Opera, Firefox, Safari.

As shown in the demo, WebKit/Blink browsers do not apply the outline to the “default” checkboxes, even though they should. This seems to be a bug. Firefox has the correct behavior.

See the Pen Demo for :default by SitePoint (@SitePoint) on CodePen.

Validity Pseudo-classes: :valid and :invalid

These pseudo-classes are useful in HTML forms for giving visual clues as to the validity of the data entered by the user, something that would normally be done with JavaScript.

As an example, if your form has the following field:

Email: <input type="email" required>

Notice the field expects the data entered to be a valid email address. You can then do the following:

input[type=email]:invalid {
  outline: red solid 1px;

input[type=email]:valid {
  outline: lightgreen solid 1px;

With the above CSS, the email field will be styled with a red outline even before the user enters anything. Once the user types in a valid email address, the outline will turn green.

With these pseudo-classes you could easily add a pseudo-element in the form of a green checkmark (or something similar), to indicate valid field data.

Some notes on these selectors:

  • Interestingly, the validity can also apply to the form element itself, indicating if all the fields are valid.
  • These don’t work on common elements like div or p because those elements don’t have any way to specify expected data formats.
  • A regular “text” input type, which doesn’t require a specific format, is “valid” by default, but would be “invalid” without data if it has the required attribute set.

Browser Support for :valid and :invalid
All browsers including IE10+.

See the Pen Demo for :valid and :invalid by SitePoint (@SitePoint) on CodePen.

Range Pseudo-classes: :in-range and :out-of-range

These two pseudo-classes are useful for form elements that allow data that falls between a specified range. You can style the specified input based on whether or not the element is within the allowed range.

So your HTML would be something like this:

<input type="date" 
       min="1994-01-01" max="2015-03-01"

Notice the default value of “1993-01-01”, which is outside the allowed date range. You can then style the input dynamically, based on the default data or any entered data, something like this:

input[type=date]:in-range {
  outline: lightgreen solid 1px;

input[type=date]:out-of-range {
  outline: red solid 1px;

Some notes on these selectors:

  • These can be used for number, datetime, datetime-local, month, week, and any other input types that allow ranges.
  • Technically these also work with the range input type, but I don’t think there is a way to make such an element be “out of range” so the usefulness in this case seems limited.
  • As with other pseudo-classes, these will work only on elements that have the capability to define accepted ranges.

Browser Support for :in-range and out-of-range
Opera, Chrome, Firefox, Safari.

See the Pen Demo for :in-range and :out-of-range by SitePoint (@SitePoint) on CodePen.

Optionality Pseudo-classes: :required and :optional

These pseudo-classes let you style form elements based on whether they are required to be filled out or not. Take the following HTML:

  <label for="name">name:</label>
  <input type="text" id="name" required>
  <span class="msg"></span>
  <label for="email">Email:</label>
  <input type="email" id="email" required>
  <span class="msg"></span>
  <label for="address">Address:</label>
  <input type="text" id="address">
  <span class="msg"></span>

Notice the empty span elements added next to each input. Also notice that the first two fields are required but the third is not. With this HTML in place, you can do the following in your CSS:

input:required ~ .msg:after {
  content: '*';
  color: red;

input:optional ~ .msg:after {
  content: '(optional)';

Here I’m using the general sibling combinator to add a red asterisk next to each required field and I’m adding the word “optional” in parentheses beside each non-required field.

This uses the extra elements that I added. If you prefer not to use extra elements, you can either add them dynamically with JavaScript or apply styling directly to the input itself. But note that you can’t use pseudo-elements with form inputs, so you’d have to apply a different kind of styling in that case.

Browser Support for :required and :optional
All browsers.

See the Pen Demo for :required and :optional by SitePoint (@SitePoint) on CodePen.

Case-insensitive Attribute Selectors: i

By default in CSS, attribute selectors are case sensitive. So, for example, if you select all elements with href values that end with “pdf”, it will not select href values that end with “PDF” (uppercase).

There’s a useful new flag that can be added to an attribute selector that overrides this behavior.

a[href$="pdf" i] {
  color: red;

Now the attribute selector will select all href links pointing to PDF files, regardless of whether the .pdf extension is written in lowercase, uppercase, or even mixed case.

Browser Support for case-insensitive attribute selectors:
Opera (only available behind a flag; thanks to Šime Vidas for pointing this out).

See the Pen Demo for case-insensitive attribute selectors by SitePoint (@SitePoint) on CodePen.

:blank Pseudo-class

The :blank pseudo-class is kind of like the prettier cousin of :empty, which I discussed in the previous article. With :empty you can select an element based on there being no children in it, whether that be elements, text nodes, or even white space nodes. So with :empty, even if the element contains a single space and nothing else, it will not be considered “empty”.

The :blank pseudo-class, however, will select an element as long as it has no text and no other child elements, regardless of white space. So it could contain white space, line breaks, etc., and it would still qualify.

Here’s some example HTML:


<p> </p>

Note that the first paragraph element is completely empty, but the second one has a single space character in it. Here’s the CSS:

p:blank {
  outline: solid 1px red;

p:empty {
  border: solid 1px green;

In this case, I’m applying a red outline on “blank” elements and a green border on “empty” elements. The :empty pseudo-class will select only the first element, because it’s completely empty. But the :blank pseudo-class will apply to both, because they are both “blank” with respects to text and elements.

It might be hard to remember the difference, because the names sound too similar and this is something that is noted in an issue in the spec. So it’s possible that this selector will change names. As the spec also notes, there is an equivalent Mozilla-only version of this selector.

Browser Support for :blank

Matches-any Pseudo-class: :matches()

The :matches() pseudo-class is a way to make selector grouping more succinct, and should be a useful addition to the spec when browser support improves.

In an example taken from MDN, you might have the following overly-verbose CSS, which attempts to deal with styling for main headings that are nested in various contexts:

section section h1, section article h1,
section aside h1, section nav h1,
article section h1, article article h1, 
article aside h1, article nav h1,
aside section h1, aside article h1,
aside aside h1, aside nav h1,
nav section h1, nav article h1, 
nav aside h1, nav nav h1, {
  font-size: 20px;

With :matches(), this can be simplified to:

:matches(section, article, aside, nav)
:matches(section, article, aside, nav) h1 {
  font-size: 20px;

The simplified version can be interpreted as: “If the h1 is inside any of these four elements, which in turn is inside any of the same four elements, do the following.”

Notes on :matches():

  • It used to be :any in the spec, supported with -moz- and -webkit- prefixes.
  • As CSS-Tricks points out, the principle here is similar to selector nesting in preprocessors.
  • The selector argument must be a “simple selector” (i.e. it cannot be a pseudo-element and it can’t use a combinator other than descendant).

Browser Support for :matches()
None, however, WebKit/Blink and Mozilla have their own vendor-based equivalents.

Relational Pseudo-class: :has()

The :has pseudo-class is similar to jQuery’s .has() but with some broader abilities. Examples will make clear what’s possible. Note the comments in the code, which explain what each example selects:

/* Section elements that contain a footer */
section:has(footer) {
  background: #ccc;

/* Any element containing a p element with a class of "alert" */
:has(p.alert) {
  background-color: red;

/* img element with paragraph immediately following. */
img:has(+p) {
  color: red;

/* list item with ul as a direct child */
li:has(> ul) {
  color: red;

As you can see, the name “has” isn’t just another word for “contains” (which is how jQuery’s method works); it can also mean “has as immediate child”, “has specified element following it”, etc.

Note: The :has pseudo-class is in the Editor’s Draft but not in the Working Draft. Also, as pointed out by Ralph in the comments, this selector may only be available in JavaScript (kind of like querySelectorAll), and not in CSS. See Dynamic vs Static Selector Profiles in the spec.

Browser Support for :has()

This selector works as a shortcut for styling any element that can take an href attribute. This includes a, area, and link elements. It can also be used as a general shortcut for the following:

:link, :visited {
  color: #555;

So instead of the above, you would write:

:any-link {
  color: #555;

But, as mentioned, this would also cover other elements, not just anchors (a), so this selector’s usefulness might be tough to discern.

It should be noted that the Working Draft had a selector called :local-link, which has been removed in Editor’s.

Browser Support for :any-link
Chrome, Opera, and Firefox (with vendor prefixes; thanks to Selen in the comments for pointing this out).

Generalized Input Focus Pseudo-class: :focus-within

This is an interesting one that I can definitely see being useful. The :focus-within pseudo-class will select not only the element to which :focus would normally apply, but also the parent element.

Here’s some example HTML:

<div class="outer">
  <label for="email">Email:</label>
  <input type="email" id="email">

With that, you can write the following CSS:

:focus-within {
  outline: yellow solid 1px;

This will cause the yellow outline to apply not only to the focused input, but also to the parent div element, because they both match the focus-within state. The spec also points out that this would work the same way inside “shadow tree” elements, applying the styles to the “host element”.

Browser Support for :focus-within

Drag-and-Drop Pseudo-class: :drop and :drop()

Now that drag-and-drop functionality is so common in apps, these selectors could prove valuable for improving the user experience.

The :drop selector lets you style the drop zone (the place where the element is supposed to be dropped), during the time when the user is dragging (or carrying) the element to be dropped.

.spot {
  background: #ccc;

.spot:drop {
  background: hotpink;

The above CSS will apply a neutral gray background color to the .spot element when the user is not dragging. But when the user starts dragging to the .spot element, the background color will change and stay that way until the item is dropped.

The alternate :drop() syntax takes one or more of the following keyword values:

  • active: Indicates the current drop target for the item dragged.
  • valid: Indicates if the drop target is valid in relation to the item being dragged (e.g. if the target only accepts files, other items wouldn’t be valid)
  • invalid: Opposite of previous, lets you style the drop target if it’s invalid in relation to the item dragged.

Multiple keywords can be used to make things more specific and if an argument is not given then it will just act like :drop, so there’s really no point in using the parentheses unless you plan to specify an argument.

Important notes:

  • The Working Draft version of the spec had a completely different set of pseudo-classes for this, so these are still in flux.
  • The drop() syntax is “at-risk”, so it may be removed.

Browser Support for :drop and :drop()

Honorable Mentions

In addition to the ones discussed above, there are some other new features that I won’t go into detail on but are worth a brief mention:

  • The column combinator (||), for defining relationships between cells and columns in tables and grids.
  • The :nth-column() and :nth-last-column() pseudo-classes for targeting specific columns of tables and grids.
  • The attribute node selector attr(), which is the first non-element selector.
  • The alternate version of the descendant combinator, represented by >> (instead of just a space character)
  • The :user-error pseudo-class for styling inputs that have incorrect user-entered data.
  • Namespaces defined with the @namespace at-rule.
  • The :dir() pseudo-class, which lets you select elements based on their directionality (e.g. ltr).
  • The :scope pseudo-class, which provides a scope, or reference point, for selecting elements.
  • The time-dimensional :current, :past, and :future pseudo-classes for targeting elements during a timeline progression such as subtitles in a video.
  • The :placeholder-shown pseudo-class for styling placeholder text in form elements.

Final Remarks and Further Info

As already mentioned, these features are very new and as shown by the browser support info and the demos, aren’t very well supported. Many of them are therefore not ready for prime time.

To keep up with the progress, here are some resources on Level 4 selectors:

If you notice any errors or bugs, mention them in the comments.

  • Ralph Mason

    Great summary, Louis. The :has() pseudo-class is effectively the holy grail “parent selector” we’ve all been waiting for, but it still appears that it won’t be available via CSS alone, but instead will only be usable from within JavaScript:

    I keep hoping that will change, but all that ever changes is the profile names!

    • LouisLazaris

      Ah, interesting. I suppose that’s due to the complex nature of selecting stuff like that, similar to querySelector or querySelector all, etc. I’ll have to add a note about that. Thanks!

    • pydsigner

      *Sigh*… that was the feature that really jumped out at me. CSS *needs* this selector.

    • Tyler Hibbard

      If you subscribe to the vendor mailing lists on the relevant subjects, you’ll see there’s a *lot* of talk about enabling :has() for CSS in the fast profile, if only for certain selector parameters. All is not lost, yet.

    • Spudley

      Yep, it’s not going to be available in pure CSS, only from Javascript. They’ve been pretty consistent in saying that, so one can only assume they’re serious. They’re restricting it in the name of performance; apparently using it in CSS will slow down the browser. It’s a bit crazy though because all that will happen is that people will start using it via Javascript instead to get their desired layout, which will be even slower.

      I can see how it would be slow if the browser were to parse it by looking at the main selector and then filtering it by the :has() section. But if you parse the :has() bit first and then search for the main selector based on the results of that, I don’t see why that should be particularly slow. Certainly no slower than some of the other selectors we use on a day-to-day basis.

      And frankly, while I agree that performance is important, it shouldn’t be the first priority. “Get it right, then make it fast”. In any case it should surely be up to the site owner to decide what kind of performance hit is acceptable to them – I don’t want to be prevented from using it because someone else thinks it might slow my site down; the performance of my site is my responsibility, not theirs. Just give me the tools and let me use them.

      • LouisLazaris

        It’s a bit crazy though because all that will happen is that people will start using it via Javascript instead to get their desired layout,

        That’s not going to happen. Today, people have the option to use pretty much any means to style an element with JavaScript or jQuery, but they generally don’t do it. I don’t know why this selector would change their mind on that. I think most developers understand that CSS should stay in CSS.

        And regarding what you said about performance, I don’t think it’s just a small matter. If the spec authors and vendors are rejecting a CSS selector due to performance, then it’s likely a major performance issue, not just a minor thing that can be tweaked or optimized.

  • So many useful toys! I mean rules!

    Thanks for sharing this, Louis. I know I shouldn’t get my hopes up but this looks like a very bright future for CSS and separating presentation from behaviour. I especially like the :has, :matches, :blank and the case insensitive selector. If they get implemented in the way you’re describing then we should start to see much improved interfaces and be able to reduce file sizes massively.

  • M S i N Lund

    default doesn’t seem to work in FF or IE or Chrome.

    • LouisLazaris

      You don’t see a pink outline around the first button in that demo?

      It’s not supported in IE, so that’s expected, but it should work partially in Chrome and fully in FF. For example, as explained in the article, I see a pink outline around the “default” checkboxes and the first button in FF, but Chrome doesn’t recognize the default checkboxes.

      What OS and browser versions are you testing on?

  • SelenIT

    :any-link are supported by Gecko and WebKit/Blink browsers, with -moz- and -webkit-prefixes, respectively:

  • Dennis Tafel

    and still now way to travel the dom up…

    • DC

      Well we have the parent selector already (&) and if you’re doing much more than that you’re likely doing something REALLY wrong.

      • LouisLazaris

        I’m not sure why you say the & character is a parent selector…? What selector are you referring to exactly? There used to be a parent selector in the spec, as explained in this 2013 Smashing Magazine article but it was removed from the spec some time ago. And it was not with the & character, it was with “!”.

        • Lukyvj

          First of all, really good article, loved it and cannot wait to use those precious new pseudo selectors.

          I think he meant that you can “define” who the parent is by writing some different context classes.

          .selector .parent_context-1 .selector .parent_context-2

          • Dennis Tafel

            i am locking for something like this (& is her for travel up):
            .checkbox:checked & .container{ background: red;}

            with this i would need less JS or none =)

          • LouisLazaris

            That’s not CSS, that’s Sass. I didn’t realize that’s what he was referring to). That’s actually a totally different topic, nothing really to do with this post, which is about native CSS selectors.

          • Lukyvj

            Well, i’m not saying that. I’m just here to help you the comment you didn’t get.

          • LouisLazaris

            Yes, thanks. Sorry, I didn’t mean to be rude, was just pointing out that Sass is a totally different thing which the 2nd comment in this thread didn’t seem to realize.

  • 1. :in-range/:out-of-range – could you confirm that this is supported in Firefox? The demo uses a “date” input which Firefox doesn’t support.

    2. Case-insensitive attribute selectors – no longer supported in Opera (I’m assuming it was suppored in Presto).

    3. “attr()” should be “::attr()”. The attr() function is something different (it’s defined in CSS 2.1 and CSS Values).

    • LouisLazaris

      1. I’m going to have to check on that tomorrow or on the weekend. But yeah, I don’t see it working in Firefox for that input. I was going by other sources on some of the support.

      2. I just tested in Opera, version 30 on Windows 7 and it works from what I can tell. All three links are red in Opera, all other browsers only the first link is red. The “about” option in Opera tells me this is the most up to date version.

      3. Fixed.

      Thanks, I’ll get back to you on the Firefox range thing.

      • 2. I think you have the “Enable experimental Web Platform features” flag turned on in Opera. I just noticed that this feature is available behind flag for me.

        • LouisLazaris

          Oh wow… that’s really strange. Looks like you’re right. I don’t know why I have that enabled…? I never enable those flags for any browser. I must have done it temporarily and forgot about it. OK, thanks for the detective work, I’ll update the article.

          Just as a side point here, I did find it strange that Opera supported it and Chrome didn’t, so that certainly explains it.

          • Happens to me, too. Chrome/Opera need a better UI for flags.

    • LouisLazaris

      Update on #1:

      Yes, it works in Firefox. I’ve changed the example to use a “number” input type instead, which demonstrates it correctly in all supporting browsers. Thanks!

  • LouisLazaris

    Oh thanks, I thought I had added a note about that. Was thinking of another selector. I’ll update it, thank you!

  • There is no such thing as CSS4

  • Some really interesting info here, maybe not as exciting as CSS animation but still good to be made aware of thanks!

  • saeidrnb

    thank you Louis Lazaris , this is useful

  • Corey Bruyere

    Pretty sure this is related.. I just realized Blink/Chrome browsers also don’t show focus styles on the select and button elements while tabbing through them. I asked a question on Stack Oveflow ( going into more detail. This may be related to the :default pseudo class bug, so if anyone has any insight or a issue ticket to follow that’d be great.

  • Awesome@LouisLazaris:disqus , again this morning you made me fall in love with CSS!

  • Ralph Mason

    The various CSS modules have levels, though, and these ones are from Selectors Level 4, as the article’s title notes.

    • Totally understood and good article btw! But I still think it can lead to some confusion.

  • :read-write seems redundant when we could simply do :not(:read-only):not(:disabled)

    • Qbe Root

      Still shorter and more straightforward, like :any-link for :link, :visited.

  • Lucas Medina

    :has is everything that CSS needs. That’s awesome!

  • Vitor Canova

    Have you tried any of them in Microsoft Edge?

    • LouisLazaris

      Nope. If anyone wants to do such a test, I’d be glad to update the post.

  • Tyler Hibbard

    Edge is still a Work in Progress, not to mention that none of these are out of Draft version yet, anyway. There’s absolutely no need to worry about browser support yet.

    • Vitor Canova

      Yes I know. I’ve just thought it would be s draw at least. Because in ES2015 it’s way beyond everyone else.

  • Daniel Tan

    Great article. In fact, much better than the last SitePoint article about Selectors 4, which was so poorly researched and written that I dare not link it here. Unfortunately I don’t know how much of this stuff will change during implementation, but it’s always nice to have a glimpse into what might be possible in the future.

    A few things I’d like to add/clarify:

    1. Many of the UI pseudo-classes here were originally defined in css3-ui. For some reason, they were punted to Selectors 4. I do not recall why. However, their existence in css3-ui may explain why they already enjoy a good amount of implementation today.

    2. Case-insensitive attribute selectors are available in all Blink browsers, not just Blink Opera. @simevidas:disqus I wasn’t aware that they were supported in Presto Opera… that’s pretty cool.

    3. In the 2013 WD, :matches() can take a list of compound selectors in the fast profile, that is, simple selector chains without any combinators. In the latest ED, there are no confirmed restrictions on :matches(). I suppose it’s yet to be tested.

    4. The 2013 WD version of :has() is actually the subject indicator. It was voted out in favor of :has() through a CSSWG poll.

    5. Namespace prefixes first appeared in Selectors 3. I don’t blame you for including them here though — I don’t know anyone personally who’s ever used them in production sites, mostly because HTML has little to no use for it.

    • LouisLazaris

      Thanks for the extra info!

  • Prays to the CSS deities to implement the :has selector, I cannot count the number of times I’ve needed this in my life! (It’s totally never going to happen. Sniff.)

  • Antonella

    Fantastic info! I’d be all for :has() and all that pertains to form validation has my vote.

  • Great post Louis, thank you – some of these are going to be so useful!

  • input:focus-within {
    outline: yellow solid 1px;

    This will cause the yellow outline to apply not only to the focused input, but also to the parent div element.

    Are you sure that is how the selector works? The W3 spec doesn’t seem very clear, but I would have expected input:focus-within to behave exactly like input:focus, but that if applied to the parent div:focus-within it would show an outline, whereas div:focus would not.

  • LouisLazaris

    Hi @donmccurdy:disqus, I’m not 100% sure what you mean, but to me the spec seems fairly clear. It says:

    The :focus-within pseudo-class applies to elements for which the :focus pseudo class applies. Additionally, the parent of an element that matches :focus-within also matches :focus-within.

    Notice the last sentence. It refers to “the parent” of the matched element being affected by the styles (i.e. it too is also matched, but doesn’t require that you apply any pseudo-class to it).

    • I would consider it very unclear, if that’s what is meant. And more importantly, pretty inconsistent with the meaning of “pseudo-class,” which should strictly be a subset/subclass of the element type.

      For example input:focus, input:active,, and input#my-id are all expected to be a subset of the inputs on the page, but input:focus-within could be a div?

      My interpretation of “the parent of an element that matches:focus-within also matches :focus-within” is that if a parent element contains an input matching :focus, that parent element could be matched with “.parent-class:focus-within”. And for consistency I suppose, input:focus-within would select the input, but you might as well write input:focus.

      By extension, if a parent matches :focus-within, shouldn’t its parent also match :focus-within? If that’s the case then it makes sense that you’d need to explicitly specify which parent, unless you want to apply borders to all parents, as shown in this javascript shim:

      • LouisLazaris

        @donmccurdy:disqus Thanks again for following up. Tab is right, I should have recognized that a parent element can’t be selected (hence why we don’t have a parent selector). But still, the way it’s explained in the spec is just mud. They need to give examples of use and be more explicit in what they mean. Unfortunately, the people who write the specs don’t actually build websites, so there’s nothing we can do about how they choose to explain things.

      • LouisLazaris

        @donmccurdy:disqus FYI – I’ve updated the post to reflect the corrected understanding. I believe it should be clearer now. Let me know if you think it’s still in need of more detail. Thanks again!

    • Followed up with one of the W3C contributors, here. It does sound like the article is slightly incorrect, in that adding a border to the input and the parent would require:

      input:focus-within {
      outline: yellow solid 1px;

  • LouisLazaris

    @morkro:disqus I know, the article never says anything about “CSS4”, it simply refers to “Selectors Level 4”. The links at the end do use the term “CSS4” but I didn’t write those, so I can’t control what others write. :)

Get the latest in Front-end, once a week, for free.