You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用object-fit: contain时如何让图片悬停动画仅作用于图片周边区域

解决object-fit:contain下悬停动画仅作用于图片周边的问题

这个问题我碰到过!核心原因是:当你给<img>加上object-fit: contain后,元素本身的盒子是占满了父容器的高度和84%宽度,但实际图片内容是在这个盒子里居中缩放的——而你的动画span是基于<img>的盒子尺寸来定位的,自然就覆盖了整个区域,而不是只围绕图片转。

要解决这个问题,关键是让动画元素的容器尺寸匹配实际显示的图片内容的尺寸,而不是<img>元素的盒子尺寸。下面给你两种实用方案:

方案一:已知图片宽高比时用纯CSS实现

如果你的图片都是固定宽高比(比如示例里的图片接近4:3),可以用aspect-ratio属性创建一个和图片比例一致的容器,把图片和动画元素都放在这个容器里,动画就能精准匹配图片的显示区域:

修改后的CSS代码

body { height: 100%; margin: 0; }
.container { 
  max-width: 600px; 
  position: relative; 
  text-align: center; 
  width: 100%; 
  height: 100%; 
  min-height: 700px;
  /* 让容器内部元素垂直居中 */
  display: flex;
  align-items: center;
  justify-content: center;
}
.product { 
  /* 设置和图片一致的宽高比,示例用4/3 */
  aspect-ratio: 4/3;
  width: 84%;
  position: relative;
}
.content { 
  background: white; 
  width: 100%; 
  height: 100%; 
  object-fit: contain; 
  z-index: 5000;
}
.product:hover .effect-1, .product:hover .effect-2 { display: block; }
.effect-1, .effect-2 { 
  border-radius: 30%; 
  display: none; 
  mix-blend-mode: multiply; 
  height: 100%; 
  opacity: 1; 
  position: absolute; 
  width: 100%; 
  z-index: 3000;
}
.effect-1 { 
  animation: rotate 1.8s linear infinite; 
  background: cyan; 
}
.effect-2 { 
  animation: rotate 1.2s linear reverse infinite; 
  background: #e7a9ff; 
}
@keyframes rotate {
  0% { top: 0; left: 0; }
  25% { top: 8%; left: -8%; }
  50% { top: 16%; left: 0; }
  75% { top: 8%; left: 8%; }
  100% { top: 0; left: 0; }
}

修改后的HTML代码

<body>
<div class="container">
  <div class="product">
    <img class="content" src="http://www.petsworld.in/blog/wp-content/uploads/2014/09/Golden-Retriever-Puppies-in-basket.jpg">
    <span class="effect-1"></span>
    <span class="effect-2"></span>
  </div>
</div>
</body>

说明

  • .product容器的aspect-ratio和图片一致,刚好匹配图片显示区域
  • 图片在容器内用object-fit: contain居中,动画元素基于这个容器定位,完美贴合图片周边

方案二:未知图片宽高比时用JS动态计算

如果你的图片比例不固定,就需要用JS动态计算图片实际显示的尺寸,再调整动画元素的大小和位置:

修改后的CSS代码

body { height: 100%; margin: 0; }
.container { 
  max-width: 600px; 
  position: relative; 
  text-align: center; 
  width: 100%; 
  height: 100%; 
  min-height: 700px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.product { 
  width: 84%;
  position: relative;
}
.content { 
  background: white; 
  width: 100%; 
  height: 100%; 
  object-fit: contain; 
  z-index: 5000;
}
.effect-1, .effect-2 { 
  border-radius: 30%; 
  display: none; 
  mix-blend-mode: multiply; 
  opacity: 1; 
  position: absolute; 
  z-index: 3000;
}
.product:hover .effect-1, .product:hover .effect-2 { display: block; }
.effect-1 { 
  animation: rotate 1.8s linear infinite; 
  background: cyan; 
}
.effect-2 { 
  animation: rotate 1.2s linear reverse infinite; 
  background: #e7a9ff; 
}
@keyframes rotate {
  0% { top: 0; left: 0; }
  25% { top: 8%; left: -8%; }
  50% { top: 16%; left: 0; }
  75% { top: 8%; left: 8%; }
  100% { top: 0; left: 0; }
}

修改后的HTML代码(含JS)

<body>
<div class="container">
  <div class="product">
    <img class="content" src="http://www.petsworld.in/blog/wp-content/uploads/2014/09/Golden-Retriever-Puppies-in-basket.jpg" onload="adjustEffects(this)">
    <span class="effect-1"></span>
    <span class="effect-2"></span>
  </div>
</div>
<script>
function adjustEffects(img) {
  const product = img.parentElement;
  const effects = product.querySelectorAll('.effect-1, .effect-2');
  
  // 计算图片原始比例和容器比例
  const imgRatio = img.naturalWidth / img.naturalHeight;
  const containerRatio = product.clientWidth / product.clientHeight;
  
  let imgDisplayWidth, imgDisplayHeight, offsetTop, offsetLeft;
  
  if (imgRatio > containerRatio) {
    // 图片更宽,按容器宽度适配
    imgDisplayWidth = product.clientWidth;
    imgDisplayHeight = product.clientWidth / imgRatio;
    offsetTop = (product.clientHeight - imgDisplayHeight) / 2;
    offsetLeft = 0;
  } else {
    // 图片更高,按容器高度适配
    imgDisplayHeight = product.clientHeight;
    imgDisplayWidth = product.clientHeight * imgRatio;
    offsetLeft = (product.clientWidth - imgDisplayWidth) / 2;
    offsetTop = 0;
  }
  
  // 同步动画元素的尺寸和位置
  effects.forEach(effect => {
    effect.style.width = `${imgDisplayWidth}px`;
    effect.style.height = `${imgDisplayHeight}px`;
    effect.style.top = `${offsetTop}px`;
    effect.style.left = `${offsetLeft}px`;
  });
}

// 窗口大小变化时重新计算
window.addEventListener('resize', () => {
  const imgs = document.querySelectorAll('.content');
  imgs.forEach(img => adjustEffects(img));
});
</script>
</body>

说明

  • 图片加载完成后,通过naturalWidth/naturalHeight获取原始比例,对比容器比例计算出图片实际显示的尺寸和偏移量
  • 动画元素的尺寸和位置会匹配图片的实际显示区域,窗口大小变化时也会自动更新

这样两种方案都能保证图片用object-fit: contain垂直居中的同时,悬停动画只作用在图片的周边区域啦。

内容的提问来源于stack exchange,提问作者Mitchell Andrew Abbott

火山引擎 最新活动