Reputation: 16815
How do I add arbitrary selectors in CSS rules?
For instance, say I want to make every item of the .effect
class turn red if the user hovers over#target
. How would I implement this? Is there a robust approach to this? I know about things like nesting .effect
inside #target
or using the sibling selectors ~
and +
, but all of these rely on a certain way of structuring the HTML.
Is this possible at all? It seems like something relatively straight forward. If it's not possible, is there any reason it isn't?
I do not want to use Javascript.
Upvotes: 1
Views: 1032
Reputation: 3789
Don't expect it for the forseeable future either. Let's take a look why!
From the point of view of someone who works on a CSS engine, selectors are actually evaluated backwards. This is certainly a rather interesting and less known aspect of CSS; Whilst the CSS selector specification does not directly define the implementation behaviour, all selectors are defined with this in mind. No hierarchial/ 'structural' selector has been created which can arbitrarily jump around the DOM as that would cause major performance issues in comparison to what we have today.
So, for example, let's take the following selector:
#target:hover .effect
This requires that an element with a class of effect
is a child (at any depth) of an element with an ID of target
because the selector engine starts by matching elements with a class of effect
first, then proceeds to work backwards, stepping up the DOM looking for a parent element with an ID of target
next.
Jumping to the parent node is extremely fast. Evaluating this in the forward direction would involve testing all children of any element with an ID of target
which is considerably more performance intensive.
This characteristic of CSS evaluation is naturally important for performance; at the worst case, the above selector will only bubble up to the root of the DOM, testing only a handful of elements along the way. The direct child selector, a > b
, only tests the direct parent and then stops, for example.
For even further performance, the structure of a selector is 'baked' into the DOM. There certainly isn't consensus on this, i.e. every CSS engine does it differently, but roughly when the DOM structure of a selector matches (i.e. we have found an element with a class of effect
and any parent with an id of target
) the selector is recorded as having matched in the DOM, regardless of the hover state on #target
. When the hover state on #target
changes, it then simply bumps all the selectors that are baked at the element - this may then trigger the whole selector to activate or deactivate. This way we're not constantly testing masses of elements when the mouse moves around, for example.
In short, none of this works either if it could arbritarily jump around the DOM. Elements entering/ leaving the DOM could affect selectors in entirely separate parts of the DOM, so the style engine would potentially be checking the entire DOM to keep this index up to date.
Also consider that we can test for elements before something, but not after (when evaluated backwards):
h1 + h2
h1 - h2 /* ..? Doesn't exist! */
This is because when we test this particular selector starting against a 'h2' element, the DOM following it might not actually be loaded yet. As soon as an element enters the DOM, either because it's just been parsed from the incoming HTML or it has been added via scripting, we begin checking for which selectors it matches. That means we can't depend on anything being available after the element in the raw HTML, so again this would also be a block for any arbritary DOM hopping.
It's currently not possible and it's unlikely to be added any time soon because it invalidates multiple performance characteristics of CSS implementations. That's not to say that it won't be added however; the W3C does appreciate that hardware is getting ever more powerful, so there is always a point at which author convenience will win over implementation performance considerations.
So, putting this a little further into context of the question, take a look at this fiddle created by @Marvin to see what's currently possible with selectors today.
Upvotes: 3