Let us suppose that I have a theme where I am designing among others form
s. 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 function
s. 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:
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?
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.
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:
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.