Search code examples
cssclip-pathcss-filters

Drop shadow in the wrong place when hovering translated clip-path polygons


I have a list of 3 triangles, to which one I want to apply a drop-shadow when hovering over it. The last 2 triangles are translated so that they stand side-by-side. When I hover over the box of the 1st triangle (the green one in the snippet), the drop-shadow appears under the last triangle. Why does that happen, what could I do to avoid this? And why is the 1st triangle registering the hover event on the whole box and not just on the triangle?

li {
  list-style: none;
  position: absolute;
  width: 100px;
  height: 100px;
}

div {
  width: 100%;
  height: 100%;  
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.one {
  background-color: green;
}

.two {
  background-color: blue;
  transform: translateX(100%);
}

.three {
  background-color: red;
  transform: translateX(200%);
}

li:hover {
  cursor: pointer;
  filter: drop-shadow(10px 10px 5px rgba(0,0,0,0.5))
}
<ul>
  <li>
    <div class="one"></div>
  </li>
  <li>
    <div class="two"></div>
  </li>
  <li>
    <div class="three"></div>
  </li>
</ul>


Solution

  • it's because you are applying the drop-shadow to the li and you are translating the div inside. So when hovering the first li you will be hovering over the last li since this one comes later in the DOM tree.

    Add some border to better see the issue. You can clearly see that all the li are stacked above each other. So hovering all of them will trigger the hover on the last one.

    li {
      list-style: none;
      position: absolute;
      width: 100px;
      height: 100px;
      border:2px solid; 
    }
    
    div {
      width: 100%;
      height: 100%;
      clip-path: polygon(50% 0, 100% 100%, 0 100%);
    }
    
    .one {
      background-color: green;
    }
    
    .two {
      background-color: blue;
      transform: translateX(100%);
    }
    
    .three {
      background-color: red;
      transform: translateX(200%);
    }
    
    li:hover {
      cursor: pointer;
      filter: drop-shadow(10px 10px 5px rgba(0, 0, 0, 0.5));
      border:2px solid green; 
    }
    <ul>
      <li>
        <div class="one"></div>
      </li>
      <li>
        <div class="two"></div>
      </li>
      <li>
        <div class="three"></div>
      </li>
    </ul>

    You can translate the li instead and avoid this issue:

    li {
      list-style: none;
      position: absolute;
      width: 100px;
      height: 100px;
    }
    
    div {
      width: 100%;
      height: 100%;
      clip-path: polygon(50% 0, 100% 100%, 0 100%);
    }
    
    .one {
      background-color: green;
    }
    
    .two {
      background-color: blue;
    }
    
    .three {
      background-color: red;
    }
    
    li:nth-child(2) {
      transform: translateX(100%);
    }
    
    li:nth-child(3) {
      transform: translateX(200%);
    }
    
    li:hover {
      cursor: pointer;
      filter: drop-shadow(10px 10px 5px rgba(0, 0, 0, 0.5))
    }
    <ul>
      <li>
        <div class="one"></div>
      </li>
      <li>
        <div class="two"></div>
      </li>
      <li>
        <div class="three"></div>
      </li>
    </ul>

    If you want to hover only the triangle, simply make the height of the li to be 0 thus only the child element will trigger the hover which is your triangle element:

    li {
      list-style: none;
      position: absolute;
      width:100px;
      height:0;
    }
    
    div {
      width: 100%;
      height: 100px;
      clip-path: polygon(50% 0, 100% 100%, 0 100%);
    }
    
    .one {
      background-color: green;
    }
    
    .two {
      background-color: blue;
    }
    
    .three {
      background-color: red;
    }
    
    li:nth-child(2) {
      transform: translateX(100%);
    }
    
    li:nth-child(3) {
      transform: translateX(200%);
    }
    
    li:hover {
      cursor: pointer;
      filter: drop-shadow(10px 10px 5px rgba(0, 0, 0, 0.5))
    }
    <ul>
      <li>
        <div class="one"></div>
      </li>
      <li>
        <div class="two"></div>
      </li>
      <li>
        <div class="three"></div>
      </li>
    </ul>