Skip to content Skip to sidebar Skip to footer

Faking The :has() "parent Selector" Using Only Css

It's long been hailed as the answer to many selector problems, even disputed by some as entirely unnecessary, but the Selectors Level 4 pseudo-class :has(), better known as the par

Solution 1:

In Gecko and WebKit, certain selectors can “jump” using <label for> and an associated <input> element positioned anywhere. This works unreliably, but is still kind of fun.

#before {
    left: -9999px;
    position: absolute;
}
#parent {
    padding: 0.5em;
}
#before:hover + #parent {
    background-color: #123;
    color: white;
}
#label {
    border: 0.1em solid #678;
    border-radius: 0.2em;
    display: inline-block;
    padding: 0.5em;
}
<inputtype="checkbox"id="before"><divid="parent"><labelfor="before"id="label">Hover over me!</label></div>

(You might have to click once if using Chrome.)

Solution 2:

JSFiddle Example

For this method, I created a fixed-position container element of static size, with a single child element inside of it, taking up 200px by 200px.

Then, I added two absolutely-positioned elements (.glass1 and .glass2) to simulate glass panes ("You can look, but you can't touch"), and I used z-index on them so that they would cover the remaining space of the container element.

The addition of these glass panes is to simulate the effect of nothing happening unless you hover over the child. Otherwise this method wouldn't imitate parent selector behavior; it would just be a normal :hover implementation.

At this point, it was just a matter of adding a :hover property to the container that did not affect the area covered by the child element.

.container {
    background: lavender;
    top: 0;
    left: 0;
    position: absolute;
    width: 600px;
    height: 400px;
    z-index: 0;
    border: 1px solid black;
}
.glass1 {
    width: 400px;
    height: 200px;
    position: absolute;
    left: 200px;
    top: 0;
    z-index: 2;
}
.glass2 {
    width: 600px;
    height: 200px;
    position: absolute;
    z-index: 3;
    top: 200px;
    left: 0;
}
.hover {
    background: lightblue;
    width: 200px;
    height: 200px;
    margin: 0;
    position: absolute;
}
.container:hover:not(.hover) {
    background: seagreen;
}
<divclass="container"><divclass="hover">Hover over me. Change my parent.</div></div><divclass="glass1"></div><divclass="glass2"></div>

The obvious problem with this implementation is its static nature and its lack of responsiveness. A more-practiced hand might allow for some measure of responsiveness.

Edit: More efficient version by ZachSaucier

Solution 3:

This is an example of what I mentioned in comments – instead of the element that gets hovered over actually being a child element, it is a mere sibling that comes right before the element that should be affected – and the adjacent sibling combinator is used to affect the second element on hover of the first one,

.hover:hover ~ .container {
    background: red;
}

http://jsfiddle.net/95HKP/5/embedded/result/

Since it has no need for additional positioned elements “covering up” the second element, it does not suffer from the mentioned drawbacks, such as actual content in the second element not being accessible via mouse cursor for selection or other forms of interaction. Only the “triggering” element itself is positioned absolutely over the other one – instead of using absolute positioning, other methods to achieve that are possible as well, f.e. a negative margin-bottom. (And I have introduced a “spacer” element to keep the content from being overlapped by the absolutely positioned element – that does not necessarily need an additional element, for example a pseudo element created using ::before would do as well.)

So again, this is also not a “parent selector” – just something that achieves a certain effect by using some positioning and other, broadly available selectors.

Post a Comment for "Faking The :has() "parent Selector" Using Only Css"