I really like :focus-within
. It’s a super useful selector that allows you to essentially select a parent element when any of its children are in focus.
Say you wanted to reveal some extra stuff when a <div>
is hovered…
div:hover .extra-stuff {
/* reveal it */
}
That’s not particularly keyboard-friendly. But if something in .extra-stuff
is tab-able anyway (meaning it can be focused), that means you could write it like this to make it a bit more accessible:
div:hover .extra-stuff,
div:focus-within .extra-stuff {
/* reveal it */
}
That’s nice, but it causes a tricky problem.
Browsers ignore entire selectors if it doesn’t understand any part of them. So, if you’re dealing with a browser that doesn’t support :focus-within
then it would ignore the CSS example above, meaning you’ve also lost the :hover
state.
Instead:
div:hover .extra-stuff {
/* reveal it */
}
div:focus-within .extra-stuff {
/* reveal it */
}
That is safer. But it’s repetitive. If you have a preprocessor like Sass…
@mixin reveal {
.extra-stuff {
transform: translateY(0);
}
}
div:hover {
@include reveal;
}
div:focus-within {
@include reveal;
}
See the Pen
Mixing for :focus-within without comma-separating by Chris Coyier (@chriscoyier)
on CodePen.
I’d say it’s a pretty good use-case for having native CSS mixins.
Brilliant again Chris!
Just thought you’d like to know the reveal doesn’t work on the embedded CodePen, but works fine when viewing on CodePen.io!
No, it is a pretty good case for having browsers not ignore whole rulesets because it doesn’t understand one selector in the list of comma-separated selectors.
Do you have a strong understanding of what that would do to the web at large if that behavior was changed? I know browsers like to be really careful about that and my suspicion is the negative consequences would be fairly big (breaking browser hacks and such that are unfortunately already in the wild).
So dumb how they ignore whole ruleset like that
I have been using CSS for a year and didn’t know that browsers ignore entire selectors when they can’t understand parts of it. Thanks a lot.
Interesting, but can’t I get the same result just using :focus? Or did I miss something?
I always use :focus in my stylesheets for anything with a :hover property, and I’ve only just recently heard about :focus-within.
Yeah, I’ve been doing this for a few years and it’s an excellent technique. However, I prefer to “invert” how the mixin is used, so I can include it in my selector definition. This somewhat hides the implementation so other devs don’t need to remember to split up the selector into 2 blocks.
To answer the question as to why this selector: it applies when the children also have focus which can be useful or table rows, charts and many other complex actions. https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within
A small note on Sass mixins
You can nest mixins within selectors to avoid naming conflicts in the global scope
A major problem with this solution is you can’t nest mixins within mixins
To solve this we can create a helper mixin to ungroup (parent) selectors
Suggestions and comments are welcome :)