0

CSS has the + selector which selects a sibling immediately following an element. As discussed in this question, there is no similar - selector for selecting the sibling that immediately precedes an element.

What are the reasons for not having a - selector that selects the preceding sibling? More specifically, what are the technical limitations, if any, with having a browser do this?

Let's suppose for the sake of argument that I'd like to be able to write code like this:

<style>
    p:hover, img:hover + p {
        background-color: yellow
    }
    img:hover, p:hover - img {
        outline: solid 2px yellow
    }
</style>
...

<img src="image.png"/>
<p>Description of image 1</p>

<img src="image1.png"/>
<p>Description of image 2</p>

Ideally, I wouldn't have to write any Javascript and I wouldn't have to restructure my HTML by (for example) wrapping the pairs in common divs. Can anyone indicate a technical reason why I can't select preceding siblings in CSS?

Community
  • 1
  • 1
aebabis
  • 3,657
  • 3
  • 22
  • 40
  • 5
    Does it matter? It doesn't exist! – Diodeus - James MacFarlane Jan 21 '14 at 22:37
  • @Diodeus Well maybe it can get added to the W3 spec some day :) – aebabis Jan 21 '14 at 22:38
  • The dichotomy between them is negligible. Why would you need both, I can't think of a scenario were it'd be needed because if a sibling exists after an element, why would you need to select it in reverse, seems redundant to me. – Jack Jan 21 '14 at 22:57
  • @JackWilliams Take a look at my example code. When you hover the paragraph, the image should be outlined. – aebabis Jan 21 '14 at 23:03
  • 2
    For a justification as to why browser selector engines don't support a preceding sibling selector, see [here](http://lists.w3.org/Archives/Public/www-style/2009Jul/0041.html) – avik Jan 21 '14 at 23:07
  • @avik Thanks, that was very informative. – aebabis Jan 21 '14 at 23:13
  • @avik So far, your link has the most thorough answer to the question. Maybe you should post an answer summarizing it. – aebabis Jan 23 '14 at 22:58
  • @acbabis I wrote up an answer, unfortunately the question was put on hold literally seconds before I tried to post it. Stupid optimistic locking :p. – avik Jan 24 '14 at 15:18
  • @avik Its a shame, too. I think this question has generated thoughtful, objective answers. Is there any way to appeal a lock? – aebabis Jan 24 '14 at 17:05

3 Answers3

1

CSS is designed to only be able to select following siblings and children of other selectors. This is simply how CSS is designed, and even though I think it's restricting in a couple of situations too and I hope this changes some time soon, you just have to live with it for now (and probably for a lot longer, since there are currently no plans on adding parent or previous-sibling selectors).

In this particular example, you should group both the <img> and <p> tags in a single container element, such as a <div>, and apply the :hover pseudo-class to that div. For example:

<style>
    div:hover p {
        background-color: yellow
    }
    div:hover img {
        outline: solid 2px yellow
    }
</style>
...
<div>
    <img src="image.png"/>
    <p>Description of image 1</p>
</div>
<div>
    <img src="image1.png"/>
    <p>Description of image 2</p>
</div>

That will have the exact same effect as what you're trying to do, but you will have to modify your HTML layout for that too.

This article might be interesting to read. It analyzes the way CSS works a bit further.

Joeytje50
  • 18,636
  • 15
  • 63
  • 95
  • This is a very tautological answer - CSS doesn't have it because CSS doesn't have it isn't an answer. –  Jan 21 '14 at 23:03
  • The answer is that it's just "designed to [not work that way]" and "This is simply how CSS is designed". There's nothing tautological about that. I never said "it is this way because it is this way". – Joeytje50 Jan 21 '14 at 23:21
1

Simpler explanation: the character - is valid as part of a CSS identifier for compatibility with HTML/XML identifiers. If - was an operator, it would need to be disambiguated with whitespace or something, and that would make the grammar more complicated to parse and minify. Too easy to screw up for the little use we would get out of it.

sqykly
  • 1,586
  • 10
  • 16
  • It wouldn't have to be a minus sign, and if it was, I suspect the increase in parse time would be negligible. Very insightful though. – aebabis Jan 21 '14 at 23:06
  • It wouldn't necessarily take longer to parse, it would just take longer to get the formal grammar written so that it isn't a hack job with forward assertions all over the place. Also consider matching a tag in an XML document whose tag name is `-foo`. `-foo` is a perfectly good identifier, but when you get promoted and your underling has to maintain that CSS, he/she always must wonder whether you meant an element `-foo` or the previous sibling `foo`. – sqykly Jan 22 '14 at 00:53
  • I see, but if having "-" as a part of CSS was the way things were, people would probably decide that using -foo is not recommended, wouldn't they? – aebabis Jan 22 '14 at 01:28
  • I think most of us have come to that conclusion anyway =D. But that's not how W3 thinks or works. If someone was to propose `-` or *any* operator that would break *any* old selector as part of a selector for the next CSS spec, they will be laughed out immediately. New features that break old code that was written in their absence simply don't happen in standards. – sqykly Jan 22 '14 at 02:53
1

There isn't a "-" symbol, but something similar may be on its way.

The w3c is working on a proposed way to determine the subject of a selector. It could act as a parent selector to accomplish what you are wanting.

Here is info on w3.org

Here's an article offering a sneak peak from Smashing Magazine

Here is an example of how it would work:

body! header a.styleSwitcher:hover {
   background: red;
}

As you can see, by hovering over the link with the class "styleSwitcher", the attributes of the body itself - which is of course a containing element - could be manipulated.

(Here is a polyfill so that you can play around with it now: https://github.com/Idered/cssParentSelector)

PhillipKregg
  • 9,358
  • 8
  • 49
  • 63