15

I have problem with my css code.

As you see I have filter on li element, but it's overlays other elements. I need to make other two elements had no filter:

Is there any possibility to do so.

.main {
  width:300px;
  height:300px;
  background-color:blue;
  list-style:none;
}

.button {
    position: absolute;
    top: 35% ;
    height: 30px;
    width: 120px;
    display: none;
    z-index: 99;
    background-color:black;
    color:white;
}

.icon {
    width: 30px;
    position: absolute;
    z-index: 99;
    display: none;
    width:100px;
}

.main:hover > .button {
    display: block;
    filter: none;
}

.main:hover > .icon {
    display: block;
    filter: none;
}

.main:hover {
    filter: brightness(50%);
    transition: 0.5s;
}
<li class="main">
<img src="https://help.seesaw.me/hc/en-us/article_attachments/204081043/bear.png" class="icon" />
<a class="button" href="#">Button</a>
</li>

2
  • you cannot do it like this, it's like opacity, display,etc .. filter on parent apply on childs Commented Jul 3, 2018 at 12:05
  • Nope, you can't do that. The filter applies to all child elements because of how it's composited: think of something like opacity. You cannot "reverse" the opacity of a child element. If you want to isolate the filter, you will have to change how your markup is written.
    – Terry
    Commented Jul 3, 2018 at 12:05

3 Answers 3

8

The only way to do this is to revert the filter on the child.

For example, if the parent has:

filter: invert(100%);

then applying this filter to the child will reverse the effect:

filter: invert(100%);

Note that if you have multiple filters, the order of filters is important!

In this way the filter will be applied to all children EXCEPT the ones to which you apply the reversed filter.

.parent {
  filter: invert(100%);
}

.child, .no-parent-with-no-filters {
  width: 100px;
  height: 100px;
  border: 5px solid green;
  background-color: blue;
  float: left;
}

.child2 {
  filter: invert(100%);
}
<div class="parent">
  <div class="child child1">filter on parent</div>
  <div class="child child2">filter on parent but reverted</div>
  <div class="child child3">filter on parent</div>
</div>

<div class="no-parent-with-no-filters">no filters</div>

For more complex filter combinations reverting is more difficult. As a start, check out this question for more info:

0
5

You can't do it that way. Childs are affected by their parent style.
That's how Cascading Style Sheets works.

I suggest you to use a pseudo-element to make it work like you want, so that only the pseudo-element would be affected.

See comments in the snippet:

.main {
  position: relative;   /* Added */
  width: 300px;
  height: 300px;
  list-style: none;
}

.main::before {   /* Added */
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: blue;
  transition: 0.5s;
}

.button {
  position: absolute;
  top: 35%;
  height: 30px;
  width: 120px;
  display: none;
  z-index: 99;
  background-color: black;
  color: white;
}

.icon {
  width: 30px;
  position: absolute;
  z-index: 99;
  display: none;
  width: 100px;
}

.main:hover>.button {
  display: block;
  /* filter: none; Commented */
}

.main:hover>.icon {
  display: block;
  /* filter: none; Commented */
}

.main:hover::before {   /* Modified */
  filter: brightness(50%);
}
<li class="main">
  <img src="https://help.seesaw.me/hc/en-us/article_attachments/204081043/bear.png" class="icon" />
  <a class="button" href="#">Button</a>
</li>

Hope it helps.

1
  • 3
    Despite your (unwarranted) snark, that's not what cascading means in this context: children inherit the style because of the way filters are rendered visually by the parent element they're applied to, totally in spite of the CSS cascade (properties). If that were not the case, simply setting filter: revert on the children would solve the problem, but it does not because the CSS cascade has no part to play here since the filter property isn't inherited. Commented Dec 22, 2023 at 11:43
0

I'll suggest pseudo-element for this task. Your .main class retains the parent position with position:relative, While the image and button, becomes dependant with a position absolute. On hover on the element with .main class, add the pseudo-element ::before and apply the necessary styles as stated in code below.

.main {
  width:300px;
  height:300px;
  list-style:none;
  position:relative;
  background-color:blue;
}

.button {
    position: absolute;
    top: 35% ;
    height: 30px;
    width: 120px;
    display: none;
    z-index: 99;
    background-color:black;
    color:white;
}

.icon {
    width: 30px;
    position: absolute;
    z-index: 999999;
    display: none;
    width:100px;
}

.main:hover>.button {
  display: block;
}

.main:hover>.icon {
  display: block;
}

.main:hover::before {
  content: "";
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  position:absolute;
  background-color:blue;
  transition: 0.5s;
  filter: brightness(50%);
}
<li class="main">
<img src="https://help.seesaw.me/hc/en-us/article_attachments/204081043/bear.png" class="icon" />
<a class="button" href="#">Button</a>
</li>

Not the answer you're looking for? Browse other questions tagged or ask your own question.