Home > Enterprise >  Prevent shadow bleeding with position absolute element?
Prevent shadow bleeding with position absolute element?

Time:03-22

I'm developing a dropdown and I'm having an issue because I want to have an absolutely positioned container of items to appear when you hover over it, but the issue is that the shadow from this bleeds onto the actual dropdown itself. Here's a reproduction:

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

.dropdown {
  position: relative;
  width: 200px;
  height: 40px;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #efefef;
}

.items {
  display: none;
  position: absolute;
  overflow: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100px;
  top: 100%;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #f7f7f7;
}

.dropdown:hover .items {
  display: block;
}

.item {
  padding: 5px 10px;
}
<div >
  <div >
    <div >a</div>
    <div >b</div>
    <div >c</div>
    <div >d</div>
  </div>
</div>
<div>hello</div>

As you can see, the top portion of the shadow from the .items container is visible when you mouse over the dropdown. Here's a picture of what I'm referring to:

enter image description here

The obvious solution is to just make the box shadow apply to only the dropdown, but then the issue is that since the items container is position absolute, it doesn't receive the box shadow.

Is there any way around this?

CodePudding user response:

I think Jackson has the right idea with using a pseudo element.

Although my approach would be the following:

.dropdown:hover::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: #efefef;
}

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

.dropdown {
  position: relative;
  width: 200px;
  height: 40px;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #efefef;
}

.items {
  display: none;
  position: absolute;
  overflow: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100px;
  top: 100%;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #f7f7f7;
}

.dropdown:hover .items {
  display: block;
}
.dropdown:hover::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: #efefef;
}

.item {
  padding: 5px 10px;
}
<div >
  <div >
    <div >a</div>
    <div >b</div>
    <div >c</div>
    <div >d</div>
  </div>
</div>
<div>hello</div>

A second approach could be to grow the height of .dropdown on hover, and set the items list to a position not relative to .dropdown's height:

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

.dropdown {
  position: relative;
  width: 200px;
  height: 40px;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #efefef;
}

.items {
  display: none;
  position: absolute;
  overflow: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100px;
  top: 40px;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  background-color: #f7f7f7;
}

.dropdown:hover .items {
  display: block;
}
.dropdown:hover {
  height: 140px;
}

.item {
  padding: 5px 10px;
}
<div >
  <div >
    <div >a</div>
    <div >b</div>
    <div >c</div>
    <div >d</div>
  </div>
</div>
<div>hello</div>

CodePudding user response:

You could add a :before element on the .dropdown with a smaller height than he items. Like this:

.dropdown:hover:before {
    position: absolute;
    content: "";
    width: 100%;
    height: 98px;
    box-shadow: rgb(0 0 0 / 24%) 0px 6px 8px;
    background: red;
    bottom: -100px;
    z-index: 0;
}

Also, remove the shadow from the .items element.

  • Related