Home > Back-end >  Why CSS hover with pseudo element failed?
Why CSS hover with pseudo element failed?

Time:01-19

I wrote a list item hover effect today, but the result behavior is quite strange:

When hover from Item6 to Item2, everything's ok, but when hover from Item2 to Item6 & hover the blank area (inside<li>, outside of <p>), it seems something is blocking the hovering.

Feels like something's wrong with the pseudo element.

Can anyone help me with it? Thanks!

Here is my code:

var li = document.querySelectorAll('li')
li.forEach((e) => {
  e.addEventListener('click', (event) => {
    li.forEach((l) => {
      l.classList.remove('active')
    })
    e.classList.add('active')
  })
})
:root {
  --el-color-primary: #409eff;
  --el-color-info: #909399;
  --el-color-primary-rgb: 64, 158, 255;
}

.categories {
  width: 200px;
}

li {
  list-style-type: none;
  box-sizing: border-box;
  height: 2.2rem;
  cursor: pointer;
  color: var(--el-color-info);
  z-index: 0;
  border-radius: .5rem;
}

li {
  margin: .3rem;
}

li p {
  font-size: 1rem;
  line-height: 1rem;
  padding: .6rem 0 .6rem .8rem;
  margin: 0;
  color: var(--el-color-info);
}

li.active p {
  font-weight: 600;
  color: var(--el-color-primary);
}

li.active {
  background-color: rgba(var(--el-color-primary-rgb), .2);
}

li:not(.active)::after {
  content: "";
  display: inline-block;
  width: 0;
  height: 2.2rem;
  position: relative;
  top: -2.2rem;
  left: 0;
  border-radius: .5rem;
  background-color: rgba(var(--el-color-primary-rgb), .1);
  z-index: -99;
  transition: width .4s ease-out;
}

li:not(.active):hover p {
  color: var(--el-color-primary);
}

li:not(.active):hover::after {
  width: 100%;
}
<ul >
  <li >
    <p>Item 1</p>
  </li>
  <li>
    <p>Item 2</p>
  </li>
  <li>
    <p>Item 3</p>
  </li>
  <li>
    <p>Item 4</p>
  </li>
  <li>
    <p>Item 5</p>
  </li>
  <li>
    <p>Item 6</p>
  </li>
</ul>

CodePudding user response:

The problem is solved by modifying putting a display: block at li:not(.active)::after instead of an inline-block

var li = document.querySelectorAll('li')
li.forEach((e) => {
  e.addEventListener('click', (event) => {
    li.forEach((l) => {
      l.classList.remove('active')
    })
    e.classList.add('active')
  })
})
:root {
  --el-color-primary: #409eff;
  --el-color-info: #909399;
  --el-color-primary-rgb: 64, 158, 255;
}

.categories {
  width: 200px;
}

li {
  list-style-type: none;
  box-sizing: border-box;
  height: 2.2rem;
  cursor: pointer;
  color: var(--el-color-info);
  z-index: 0;
  border-radius: .5rem;
}

li {
  margin: .3rem;
}

li p {
  font-size: 1rem;
  line-height: 1rem;
  padding: .6rem 0 .6rem .8rem;
  margin: 0;
  color: var(--el-color-info);
}

li.active p {
  font-weight: 600;
  color: var(--el-color-primary);
}

li.active {
  background-color: rgba(var(--el-color-primary-rgb), .2);
}

li:not(.active)::after {
  content: "";
  display: block;
  width: 0;
  height: 2.2rem;
  position: relative;
  top: -2.2rem;
  left: 0;
  border-radius: .5rem;
  background-color: rgba(var(--el-color-primary-rgb), .1);
  z-index: -99;
  transition: width .4s ease-out;
}

li:not(.active):hover p {
  color: var(--el-color-primary);
}

li:not(.active):hover::after {
  width: 100%;
}
<ul >
  <li >
    <p>Item 1</p>
  </li>
  <li>
    <p>Item 2</p>
  </li>
  <li>
    <p>Item 3</p>
  </li>
  <li>
    <p>Item 4</p>
  </li>
  <li>
    <p>Item 5</p>
  </li>
  <li>
    <p>Item 6</p>
  </li>
</ul>

CodePudding user response:

The problem is in top: -2.2rem because it is relative and relative position doesn't remove the element from the normal document flow (enter image description here The whole selected area shows "item 2" li element and the light-blue box is actually a part of that element and we bring it up by negative top value. That's why when we enter mouse from item 2 to 3, we think we would be on item 3 but in fact we are still hovering item 2.

I guess the better way to do this is using absolute:

var li = document.querySelectorAll('li')
li.forEach((e) => {
  e.addEventListener('click', (event) => {
    li.forEach((l) => {
      l.classList.remove('active')
    })
    e.classList.add('active')
  })
})
:root {
  --el-color-primary: #409eff;
  --el-color-info: #909399;
  --el-color-primary-rgb: 64, 158, 255;
}

.categories {
  width: 200px;
}

li {
  list-style-type: none;
  box-sizing: border-box;
  height: 2.2rem;
  cursor: pointer;
  color: var(--el-color-info);
  z-index: 0;
  border-radius: .5rem;
  position: relative; /* <----- new */
}

li {
  margin: .3rem;
}

li p {
  font-size: 1rem;
  line-height: 1rem;
  padding: .6rem 0 .6rem .8rem;
  margin: 0;
  color: var(--el-color-info);
}

li.active p {
  font-weight: 600;
  color: var(--el-color-primary);
}

li.active {
  background-color: rgba(var(--el-color-primary-rgb), .2);
}

li:not(.active)::after {
  content: "";
  display: block;
  width: 0;
  height: 2.2rem;
  position: absolute; /* <----- new */
  top: 0; /* <----- new */
  left: 0;
  border-radius: .5rem;
  background-color: rgba(var(--el-color-primary-rgb), .1);
  z-index: -99;
  transition: width .4s ease-out;
}

li:not(.active):hover p {
  color: var(--el-color-primary);
}

li:not(.active):hover::after {
  width: 100%;
}
<ul >
  <li >
    <p>Item 1</p>
  </li>
  <li>
    <p>Item 2</p>
  </li>
  <li>
    <p>Item 3</p>
  </li>
  <li>
    <p>Item 4</p>
  </li>
  <li>
    <p>Item 5</p>
  </li>
  <li>
    <p>Item 6</p>
  </li>
</ul>

  • Related