2

Let us suppose that I have a theme where I am designing among others forms. Let us suppose further that the form might have a submit button of class .submit. There are cases when the button is disabled (the form is not ready for submission) and when the button is not disabled. I can design the button like this:

.submit {
    /*Some Rules*/
}

.submit:disabled {
    /*Some Rules*/
}

However, if I know that the button will be inside a div and I want to style its parent based on the disabled property, then I need to implement a disable and an enable function and to style parentElement in those functions. Instead of that I would like to be able to define rules like this:

.submit < div { /*where < would mean parent*/
    /*Some rules*/
}

.submit:disabled < div {
    /*Some rules*/
}

Currently this is not supported.

Let us suppose further that I want to style the form based on the button's disabled attribute, to visually show whether the form is ready for submission. In this case I need to find the ancestor form tag (if exists) and style it whenever disable or enable is called. Instead of that, I would like to be able to do something like this:

.submit << form { /*Where << means ancestor*/
    /*Some rules*/
}

.submit:disabled << form {
    /*Some rules*/
}

Instead of this simple and straightforward way, currently we need to do something like this:

function disable(element) {
    element.disabled = true; //Disabling the button
    var p = element.parentElement; //Here we need to style p with Javascript
    //Find the form element
    var formExists = true;
    while (formExists && (p.tagName !== "form")) {
        if (p.tagName === "html") {
            formExists = false;
        } else {
            p = p.parentElement;
        }
    }
    if (formExists) {
        /*Do something with p*/
    }
}

function enable(element) {
    element.disabled = false; //Disabling the button
    var p = element.parentElement; //Here we need to style p with Javascript
    //Find the form element
    var formExists = true;
    while (formExists && (p.tagName !== "form")) {
        if (p.tagName === "html") {
            formExists = false;
        } else {
            p = p.parentElement;
        }
    }
    if (formExists) {
        /*Do something with p*/
    }
}

Despite appearance, disable and enable is not code-duplication, since we intend to add different styles. Off course, this code can be refactored somewhat, but it is ugly, difficult to maintain, hacky, not to mention the fact that it assumes that one calls disable or enable whenever the state of the disabled attribute needs to be changed. While all the problems shown above is solvable even without parent/ancestor selector, I would prefer to be able to implement the theme inside a .css file, without Javascript hacks, without assuming that whenever a button gets disabled disable is called and whenever a button gets enabled enable is called. Also, if this kind of thing could be triggered by CSS, then we could use automatically browser-level juices which could benefit performance.

An alternative is to have a class defined for a form, but then that class needs to be maintained programmatically along with the disabled attribute and things are not much better.

I believe I have proved in my question that such CSS rules would be superior compared to Javascript ui hacks from several points of view:

  • parents and ancestors could be designed inside a single .css file
  • developers would not have to worry about calling helper functions, nor about telling new team members those policies or documenting the usage of the theme
  • there would be no need to write difficult-to-maintain Javascript functions to handle ui changes
  • we could override the rules as we like with other CSS rules if needed instead of escalating the hacks to even bigger hacks

I know parent and ancestor selectors are not among the CSS features we can use, so I wonder whether the situation will improve. Are there known plans for this kind of feature? Are these scheduled for a future date?

Lajos Arpad
  • 45,912
  • 26
  • 82
  • 148
  • [W3C: CSS current work & how to participate](https://www.w3.org/Style/CSS/current-work.en.html) – Andreas Jul 29 '16 at 10:37
  • 4
    Appreciate the effort you've put in but am not sure SO is the right place for this question. The only one who could answer that is the W3C. – Harry Jul 29 '16 at 10:37
  • _“An alternative is to have a class defined for a form, but then that class needs to be maintained programmatically along with the disabled attribute and things are not much better”_ – I’d consider that to be _a lot_ better. Setting/removing the disabled attribute and the class together is a no-brainer. You’ve just complicated your example code much more than necessary with that loop to find the parent form of the button – every input element has a `form` property. – CBroe Jul 29 '16 at 10:54
  • 1
    @CBroe I can't agree with *every input element has a `form` property.* First, I think you wish said *has a `form` element*. Second, you know that it's not true, because I see tons of proyects without `
    ` element in the forms.
    – Marcos Pérez Gude Jul 29 '16 at 10:58
  • 1
    This question is more general than the one of which is considered to be a duplicate, as here I am asking about ancestor selector as well. – Lajos Arpad Jul 29 '16 at 11:12
  • @CBroe, what about ? – Lajos Arpad Jul 29 '16 at 11:15
  • Duplicate of http://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector – Salman A Jul 29 '16 at 11:42
  • @MarcosPérezGude: He asked specifically about elements that _are_ inside a from. And no, I wish not I had said something else (but perhaps rather that people understood what I actually said correctly.) And _every input element has a `form` property_ is still true. (Make that _every `HTMLInputElement` object_, if you wanna nitpick.) For elements that are not part of a form, it will contain null then of course. – CBroe Jul 29 '16 at 11:44
  • @LajosArpad: What about it? You specifically asked about elements that _are_ inside a form, and about styling that form. – CBroe Jul 29 '16 at 11:48
  • So _all_ of your code in both functions, apart from the first line, can be reduced to `if (element.form) { … }` – CBroe Jul 29 '16 at 11:58
  • 1
    @CBroe you're right. The `form` property exists. I knew it but I forget it when you comment that. Sorry :( – Marcos Pérez Gude Jul 29 '16 at 12:27
  • No problem, it happens :) And sorry for the tone above. Should probably have used the term HTMLInputElement object in the first place, to make it clearer that I was talking about the DOM object, and not an input element and its attributes in HTML. – CBroe Jul 29 '16 at 12:56
  • @CBroe, I have asked about parent and ancestor selectors, not about inputs inside a form. inputs inside a form were merely an illustration of my more general question. – Lajos Arpad Jul 29 '16 at 17:35

1 Answers1

3

Yes. In CSSv4 will be the :has() pseudoselector. The problem with parent elements is old, and your suggestion is wide known:

 element < parent {} 

Will have a serious problem. Browser reads the CSS from right to left, so this kind of selectors will be low performance.

Related link (suggestion in year 2008):

To achieve that, in CSS4 we can do:

 element:has(.parent) {}

And this will be perfect! It can select an element that is contained by the .parent selector. We can do more things like:

 element:not(:has(.parent)) {}
 element:has(#myId > .myClass) {}

This is currently not supported by any browser. It's a working draft and will came with CSS level 4.

Related links:

While this awesome selectors are not available to general use, you must to do it with Javascript or thinking about another HTML structure to avoid the needed of parent selector.

EDITION:

I've found right now a polyfill that allows you to target parent elements with CSS. It's written in jQuery but it translates the CSS content,so you don't need to make anything to make it works (apart of plugin inclusion)

Quick Info extracted from the plugin page:

! - determines subject of selector according to CSS4 reference

E > F - selects an F element, child of E

E! > F - selects an E element, parent of F

CSS4 reference

In the past, this syntax was used to develop the parent element selector, but due performance reasons it was discarded. Here you are one link explaining it:

Alternative technique

It's a technique that allows you to think different in pure CSS to achieve the same functionality (stylize parent elements). You can see in this link:

It explains how to select parent elements without weird things, plugins, or polyfills. It's only pure CSS but with a expensive thinking behind.

Marcos Pérez Gude
  • 20,206
  • 4
  • 34
  • 65
  • Further info: https://developer.mozilla.org/en-US/docs/Web/CSS/:has. I look forward to when browsers support this standard, some time next decade :) – Rory McCrossan Jul 29 '16 at 10:40
  • Oh I know - it wasn't a remark against your answer at all. Just about how slow users upgrade their browsers :) – Rory McCrossan Jul 29 '16 at 10:42
  • Yeah, it's the way that users behaves. Remember how we suffer with IE6-7-8 along the years ! – Marcos Pérez Gude Jul 29 '16 at 10:43
  • Thanks for this very nice answer. Your criticism to the < notation seems to be plausible. I wonder whether :has is an ancestor selector. It seems to be. In that case, will there be a parent selector as well? – Lajos Arpad Jul 29 '16 at 10:46
  • 1
    No, in the future there is no plans to make a parent selector. This is because the browser can't go down through a DOM node and then came back up searching a parent. This is the opposite as CSS works (rendered by browsers), and there's no way to implement that. – Marcos Pérez Gude Jul 29 '16 at 10:47
  • @LajosArpad see the edition. You can use a polyfill! – Marcos Pérez Gude Jul 29 '16 at 10:52
  • You might be right, we will see. As a conclusion, we can say that we will have an ancestor selector in CSS4 and parent will be a particular case of that. Parent per se is not (yet) on the agenda, but I do not exclude the future appearance of that feature along the lines of tags being aware of their parents or a range for :has. If this is impossible under current circumstances due to the way CSS works, then the way CSS works might be changed in the future. – Lajos Arpad Jul 29 '16 at 11:04
  • Anyway, I appreciate the high-level of your answer which clarified things and I thank you very much for that. – Lajos Arpad Jul 29 '16 at 11:06
  • The parent selector was discarded due performance and implementation issues. I update the answer with that, here you are the related link: http://red-team-design.com/css-parent-selector/ – Marcos Pérez Gude Jul 29 '16 at 11:06
  • 1
    @LajosArpad you are welcome ;) Good luck achieving the functionality! – Marcos Pérez Gude Jul 29 '16 at 11:06
  • @MarcosPérezGude, there is a question of which this one is considered to be a duplicate. There, in the answer we can see a very nice, juicy selector using the :has pseudo-selector: li:has(> a.active) – Lajos Arpad Jul 29 '16 at 11:14
  • Can you share the link? However, is the same that I said, the posibilities of `:has()` are close to infinity – Marcos Pérez Gude Jul 29 '16 at 11:25
  • Off course, my friend: http://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector – Lajos Arpad Jul 29 '16 at 17:36