手把手讲解使用纯css实现item - background-hover随鼠标丝滑移动~

线上效果预览

www.js-bridge.com/

前提

基于css方案,每个item的高度必须是固定的,这确实是一个局限的点,当然文章主要分享一下新的思路。

常规hover效果

css 复制代码
.item:hover {
  background-color: #eee;
}

可以想象一下,效果很生硬,你看到的区块是hover时突然出现,并不会有丝滑的移动效果。

css实现步骤

创建html,创建items

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <title>hover</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    .container {
      overflow-x: hidden;
      overflow-y: auto;
      position: relative;
      height: 100vh;
    }

    .item {
      --y: 0;
      --height: 151px;
      --surface-2: #767676;
      --surface-0: #181818;

      cursor: pointer;
      padding: 30px 16px;
      border-bottom: 1px #ddd solid;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <div class="container"></div>
</body>
<script>
  const itemCount = 15;

  for (var i = 0; i < itemCount; i++) {
    var item = document.createElement('div');
    item.className = 'item';
    item.innerHTML = '<p>testtesttesttesttest</p><p>testtesttesttesttesttest</p>';
    document.querySelector('.container').appendChild(item);
  }
</script>
</html>

在每一项hover时,通过伪类获取最后一个item

css 复制代码
.item:hover~.item:last-child {
  // do something
}

这是打开核心思路的钥匙。

介此,我们可以通过.item:last-child::before去创建一个等同大小absolute定位的浅灰色区块,在hover时候去移动它来达到我们想要的交互效果~

浅灰色区块默认opacity: 0,可以通过top来移动浅灰色区块。

css 复制代码
.item {
  --y: 0;
  --height: 151px;
  --surface-2: #767676;
  --surface-0: #181818;

  // ...
}

.item:last-child::before {
  content: '';
  display: block;
  position: absolute;
  background: var(--surface-2);
  opacity: 0;
  width: 100%;
  top: var(--y);
  left: 0;
  height: var(--height);
  border-radius: .4rem;
  pointer-events: none;
  transition: all .5s cubic-bezier(.2,1,.2,1);
}

接下来的关键就是如何在hover每一项时改变y变量的值,上面我们提到过"在每一项hover时,通过伪类获取最后一个item的before",并将其透明度调高

  • 透明度调高
css 复制代码
.item:hover~.item:last-child::before {
  opacity: .06;
}

此时预览,发现并没有任何效果,浅灰色区块始终在最上方,那是因为我们还没有初始化y的值。

初始化思路也是通过伪类实现即可,如下:

css 复制代码
.item:nth-child(1):hover~.item:last-child::before {
  --y: calc(var(--height) * 0);
}

.item:nth-child(2):hover~.item:last-child::before {
  --y: calc(var(--height) * 1);
}

.item:nth-child(3):hover~.item:last-child::before {
  --y: calc(var(--height) * 2);
}

// ...
// ...

但是,这样写死未免有些不方便,而且显得笨拙~

我们改造一下,通过js去生成样式,并在items dom生成后初始化插入head即可。

js 复制代码
const initHoverClasses = () => {
    let styleStr = '';

    for (let i = 0, len = itemCount; i < len - 1; i++) {
      styleStr += `
        .item:nth-child(${i + 1}):hover~.item:last-child::before {
          --y: calc(var(--height) * ${i});
        }
      `;
    }

    styleStr += `.item:nth-child(${itemCount}):hover::before {
      --y: calc(var(--height) * ${itemCount - 1});
      opacity: .06;
    }`;

    // create style tag, inject styleStr
    const styleTag = document.getElementById('hover-classes');
    if (styleTag) styleTag.remove();

    const style = document.createElement('style');
    style.id = 'hover-classes';
    style.innerHTML = styleStr;
    document.head.appendChild(style);
};

完整代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <title>hover</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    .container {
      overflow-x: hidden;
      overflow-y: auto;
      position: relative;
      height: 100vh;
    }

    .item {
      --y: 0;
      --height: 151px;
      --surface-2: #767676;
      --surface-0: #181818;

      cursor: pointer;
      padding: 30px 16px;
      border-bottom: 1px #ddd solid;
      box-sizing: border-box;
    }

    .item:last-child::before {
      content: "";
      display: block;
      position: absolute;
      background: var(--surface-2);
      opacity: 0;
      width: 100%;
      top: var(--y);
      left: 0;
      height: var(--height);
      border-radius: .4rem;
      pointer-events: none;
      transition: all .5s cubic-bezier(.2,1,.2,1);
    }

    .item:hover~.item:last-child:before {
      opacity: .06;
    }
  </style>
</head>
<body>
  <div class="container"></div>
</body>
<script>
  const itemCount = 15;

  const initHoverClasses = () => {
    let styleStr = '';

    for (let i = 0, len = itemCount; i < len - 1; i++) {
      styleStr += `
        .item:nth-child(${i + 1}):hover~.item:last-child::before {
          --y: calc(var(--height) * ${i});
        }
      `;
    }

    styleStr += `.item:nth-child(${itemCount}):hover::before {
      --y: calc(var(--height) * ${itemCount - 1});
      opacity: .06;
    }`;

    // create style tag, inject styleStr
    const styleTag = document.getElementById('hover-classes');
    if (styleTag) styleTag.remove();

    const style = document.createElement('style');
    style.id = 'hover-classes';
    style.innerHTML = styleStr;
    document.head.appendChild(style);
  };

  for (var i = 0; i < itemCount; i++) {
    var item = document.createElement('div');
    item.className = 'item';
    item.innerHTML = '<p>testtesttesttesttest</p><p>testtesttesttesttesttest</p>';
    document.querySelector('.container').appendChild(item);

    setTimeout(() => {
      initHoverClasses();
    });
  }
</script>
</html>

好了文章到此结束,如果对您有帮助,请点个小红心,谢谢~

相关推荐
DK七七4 分钟前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客15 分钟前
QSS 设置bug
前端·bug·音视频
Chikaoya16 分钟前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季16 分钟前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie17 分钟前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
NoloveisGod42 分钟前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing44 分钟前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚1 小时前
实现3D热力图
前端·javascript·3d
杨过姑父1 小时前
org.springframework.context.support.ApplicationListenerDetector 详细介绍
java·前端·spring
理想不理想v1 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试