0

After seeing the different selectors available (as of CSS3), the difference between the + and ~ seem to be nearly the same. And it also appears there is no selector with opposite functionality to ~.

Taken from www.w3schools.com:

  • div + p: Selects all <p> elements that are placed immediately after <div> elements.
  • p ~ ul: Selects every <ul> element that are preceded by a <p> element.

The effect of p ~ ul can be rewritten as:

Selects all <ul> elements that are placed after a <p> element.

Because preceded by a <p> means the <p> is before the <ul>.

This leaves the only difference between these operators being that + only select elements immediately after (I assume all consecutive occurrences), whereas ~ selects elements anywhere after (but still with the same parent).

  1. Is my understanding of the difference correct?

Originally I thought the two operators were opposites due to the somewhat confusing english. So, my follow-up questions is this:

  1. How can I select every element placed before (or immediately before) another element?


I'm working with this case scenario:

I have 2 div's side-by-side in the same parent div.

<div id="container">
    <div id="column_left">
    </div>
    <div id="column_right">
    </div>
</div>

When I hover either div, both should gradually become more opaque using CSS transitions. When I'm not hovering either, they should become more transparent.

So, to select the right column when the left is hovered I would using the selector:

#column_left:hover+column_right {
    opacity: 0.9;
    transition: opacity 300ms;
    -webkit-transition: opacity 300ms;
}

Now, how can I select the left column when the right is hovered?

Here is my CSS so-far:

div {
  border: 1px solid black;
  background: #262626;
}

#left {
  float: left;
  width: 200px;
  height: 200px;
  margin: 0;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}

#right {
  display: inline-block;
  width: 200px;
  height: 200px;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}

#left:hover,#left:hover~#right {
  background: #909090;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}
<div id=left>
</div>
<div id=right>
</div>
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62
  • For 2): [Is there a previous sibling selector?](http://stackoverflow.com/q/1817792/11683) – GSerg Aug 20 '15 at 19:18
  • 1
    css can only refer "forward" or "down". you can't go backward or up. – Marc B Aug 20 '15 at 19:19
  • What about using the attribute selector? Could I define my own custom attribute and refer to it. Suppose I added the attribute selector or one of its variants to both of the div's. (see the W3Schools page for a reference to the `[attribute]` selector). – Nicholas Miller Aug 20 '15 at 19:22
  • The Selectors spec is more verbose, but also more consistent with its wording than W3Schools. – BoltClock Aug 21 '15 at 04:50

2 Answers2

2

Is my understanding of the difference correct?

Yes. Selectors L3 defines those two types of sibling combinators (emphasis mine):

  • Adjacent sibling combinator

    The adjacent sibling combinator is made of the "plus sign" (U+002B, +) character that separates two sequences of simple selectors. The elements represented by the two sequences share the same parent in the document tree and the element represented by the first sequence immediately precedes the element represented by the second one.

  • General sibling combinator

    The general sibling combinator is made of the "tilde" (U+007E, ~) character that separates two sequences of simple selectors. The elements represented by the two sequences share the same parent in the document tree and the element represented by the first sequence precedes (not necessarily immediately) the element represented by the second one.

How can I select every element placed before (or immediately before) another element?

As explained in Is there a previous sibling selector?, it's not possible to do that with Selectors L3. Selectors L4 may introduce some way to do it, but probably it will only be available in JS (e.g. through querySelector) but not in CSS stylesheets because of performance reasons.

Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
1

A solution for your specific use case

When I hover either div, both should gradually become more opaque using CSS transitions. When I'm not hovering either, they should become more transparent.

.wrap {
  float:left;
  overflow:hidden
}
div {
  border: 1px solid black;
}
#left {
  float: left;
  width: 200px;
  height: 200px;
  margin: 0;
  background-color: red;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}
#right {
  float:left;
  width: 200px;
  height: 200px;
  background-color: blue;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}
.wrap:hover > #right,
.wrap:hover > #left {
  background: #909090;
  transition: background 300ms;
  -webkit-transition: background 300ms;
}
<div class="wrap">
  <div id=left>
  </div>
  <div id=right>
  </div>
</div>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • Unfortunately, I should have been a bit more specific with the case. A wrapper is close but still will not work since the divs will end up being different sizes. So there is some 'empty space' considered part of the wrapper which would trigger the transition. Thanks for the snippet though, it is still useful. – Nicholas Miller Aug 20 '15 at 20:04
  • Fair enough...then you'll needjavascript unfortunately. – Paulie_D Aug 20 '15 at 20:07