Add selector for previous element ("+" selector for previous child)


#1

It would be quite useful to have a previous element selector (equivalent of element + next element for previous child) and there are others who want this/have asked if it is available too. When an element that can’t easily be selected comes before an easily selected element, it needs a selection method, a previous selector. Sometimes this scenario can be reorganised to use next element selectors, but when it can’t there will be problems.

Syntax idea
Since parent element > child element is used to select child elements with a specified parent and preceding element(s) ~ element is used to select elements that are preceded by a specified element, using element < previous element would be a bad format as because of the > use it could be confused with referring to the parent element.
So I think a good format would be element - previous element as it doesn’t seem to be in use and relates to use of the + symbol for “next”.

Example
HTML:

<div>
  <div>The item with no easy selection method that comes before.</div>
  <div data-important-thing>Something important that can be selected.</div>
</div>

Pseudo-CSS (idea):

//div[data-important-thing] <some selector> div
div[data-important-thing] - div {color: red};

#2

FWIW, this has already been proposed (by me in particular) and discussed at the www-style@w3.org mailing list multiple times (e. g. 1, 2, 3, 4, 5). It has also been discussed at StackOverflow, and there is even a weird workaround based on the Flexbox order property used in conjunction with the next-sibling combinator (+).

But why not propose this again via WICG, especially given that it has features unavailable at mailing lists, such as unbreakable threading, proper formatting, and the magic “Like” button. :slight_smile:


#3

While the - character makes sense when explained, something else might be better. Hyphen-casing is used throughout CSS, so it would need different syntax rules than the other combinator symbols; you couldn’t collapse whitespace around it, for example. They’re also used in the upcoming Custom Selectors.


#4

The exact syntax doesn’t matter much. As mentioned in multiple previous www-style discussions, there is plenty of options:

  • we could just require whitespace around the hyphen to treat it as a combinator (and with CSS preprocessors, this could be supported regardless of the accepted formal syntax anyway);

  • another option is using P !+ UL instead of P - UL (negated + instead of -);

  • or we could use something universal / infinitely-extensible like a forward-slash-wrapped keyword, e. g. P /prev-sibling/ UL instead of P - UL;

  • or anything else — this almost doesn’t matter.


#5

Doesn’t has() cover this case?

In the example provided, I believe div:has(+ div[data-important-thing]) gives you what you want.


#6

:has() is currently not allowed in the static profile (CSS), only in the dynamic one (JS).


#7

If somebody would like to write a proposal (like an unofficial spec), the most important step should be to come up with some convincing use cases, I think. (Marketing is key :sunglasses:.)


#8

Nobody has unneeded time to waste. :slight_smile:

Substantially, usecases for previous-sibling combinator should apparently be similar to those (whatever they are) for next-sibling combinator that we already have.


#9

Someone mentioned needing a use case for a convincing argument.

Primary use case I have a form builder that I don’t have direct access to all the html.

In this case a form. There is one question on the form which needs three answers. The generated output is 3 groups each with a label and an input

<div class="form-group"> <label for="input-9971" data-toggle="collapse" class="control-label js-label-preview"> <span class="js-label-text">What are your top three business challenges?</span> <strong class="red bigger-110 js-required">*</strong> </label> <input type="text" id="input-9971" class="js-input width-100 form-control" name="fieldValue " data-id="9971" data-toggle="tooltip" data-placement="bottom" placeholder="Challenge #1" title=""> </div> <div class="form-group"> <label for="input-9972" data-toggle="collapse" class="control-label js-label-preview"> <span class="js-label-text" style="display: none;">Challenge #2</span> <strong class="red bigger-110 js-required">*</strong> </label> <input type="text" id="input-9972" class="js-input width-100 form-control no-star" name="fieldValue " data-id="9972" data-toggle="tooltip" data-placement="bottom" placeholder="Challenge #2" title=""> </div> I do have some control over hiding the label but it fails to hide the asterisks which is in an additional strong element separate from the span as part of the label. Through the form generators “Advanced” option you can add a class, however it’s only applied to input field. This is the point were a selector for previous element would come in handy because then I could add into my CSS something like input.no-star - label { display:none; }

Which would visually hide the undesired element while still enforcing the “required” behavior of the elements.

Undesired Output

Desired Output


#10

Are those input ID’s always the same? If so:

[for^="input-997" i]:not([for="input-9971"]) .js-required {
  display: none;
}

You can also give a list to the attribute selector to match by if they are specific IDs each time to make the initial target more accurate without the not addition. So what you want is doable, albeit a little more complex, without the addition of a parent selector.