使用 object-fit: cover 将绝对定位的元素保持在背景图像的相同部分,无论宽高比如何

问题描述 投票:0回答:1

我想将“固定”元素绝对定位在背景图像上方。无论宽高比如何,它们都必须位于图像内容的完全相同部分之上。该图像具有适合对象:封面和 16:9 的固有纵横比,因此对于较低的纵横比,例如4:3,图像的左右两侧将被裁剪掉。因此,位于左侧:30% 的图钉现在将位于图像的不同部分上方。

这是当前设置的简化版本:

我有一个包含图像的 div:

  <body>
    <div class="pin-container">
      <img src="./test.jpg" class="main-image"/>
    </div>
  </body>

在我的 JS 中,引脚被添加到“引脚容器”div 中:

const pins = [
    {
      xPercent: 30,
      yPercent: 50,
      text: 'Pin A',
    },
    {
      xPercent: 80,
      yPercent: 20,
      text: 'Pin B',
    },
    {
      xPercent: 50,
      yPercent: 50,
      text: 'Pin C',
    },
  ];

  const pinContainer = document.querySelector('.pin-container');

  pins.forEach((pinDetails) => {
    const pin = document.createElement('div');
    pin.className = 'pin';

    const pinText = document.createElement('p');
    pinText.className = 'pin-text';
    pinText.innerText = pinDetails.text;

    pin.appendChild(pinText);

    pin.style.left =
      pinDetails.xPercent *
        (window.innerWidth / window.innerHeight / (16 / 9)) +
      '%';
    pin.style.top = pinDetails.yPercent + '%';

    pinContainer.appendChild(pin);
  });

CSS 规定 img 元素和 pin-container div 都应该占据整个屏幕,pin 元素绝对位于顶部:

.pin-container {
  height: 100vh;
  width: 100vw;
  position: relative;
}

.main-image {
  position: absolute;
  height: 100%;
  width: 100%;
  object-fit: cover;
  object-position: 75%;
}

.pin {
  position: absolute;
  z-index: 1;
  background-color: white;
  padding: 10px;
  border-radius: 50%;
}

问题在于我尝试在 JS 中使用的公式 - 仅获取纵横比的差异并将 xPercent 值乘以该差异是不够的。这样做会同等地影响所有引脚 - 如果屏幕纵横比为 4:3,则对于 xPercent 为 30:

的引脚,公式的工作原理如下

pinDetails.xPercent * (window.innerWidth / window.innerHeight / (16 / 9)) 30 * (4/3 / (16/9)) 30 * (1.33.../1.77...) 30*0.75 = 22.5%

正如应该的那样,“left”属性的值会减小,将图钉进一步推向屏幕左侧,并正确考虑到被裁剪的图像的左侧。

但是,这同样适用于所有引脚,无论其位置如何。因此,xPercent 为 80 的图钉的左侧属性也会减少,从而将其进一步推向左侧。但在这种情况下,因为图像具有 object-position: center,所以图像的右侧也会被裁剪掉,事实上 left: 80% 的 pin 应该增加其 left 属性,将其进一步推向正确地解释了被剪掉的图像的右侧。

据我所知,这需要在一条曲线上 - 50% 的引脚应该保持其左侧值不变,因为图像的中心将始终位于同一位置,并且接近 50% 的引脚应该他们留下的财产变化很小。当引脚接近 0% 时,纵横比的差异应越来越降低其左值,而当引脚接近 100% 时,其左值应越来越高。

我无法弄清楚的是,究竟需要如何改变公式才能实现这一点,或者我是否只是错误地处理了整个问题,并且有一种更简单的方法来实现我想要的效果。

为了加分 - 图像的重要内容实际上聚集在右侧,所以我理想情况下希望设置 .main-image object-position: 75%。但这似乎给问题增加了一层额外的复杂性,因此最好先处理居中图像!

任何帮助将不胜感激!!

javascript html css image responsive-design
1个回答
0
投票

不确定这是否是您所需要的,但我想出了一个更简单的解决方案:我将缩放和居中应用于包含地图和标记的父元素。这样标记将始终保持在正确的位置。

在此示例中,图像中的字母 O 和字母 D 上应该有一个标记。如果您调整窗口大小,标记将保持在原位。

一个问题是标记也会随着图像缩放,我通过在放置标记时“反向缩放”标记来解决这个问题。

https://jsfiddle.net/xgLp48n0/8/

const container = document.querySelector("#container")
const map = document.querySelector("#map")
const img = document.querySelector("img")
let scale

function cover() {
  let viewW = container.getBoundingClientRect().width
  let viewH = container.getBoundingClientRect().height
  let imgW = img.naturalWidth
  let imgH = img.naturalHeight
  scale = Math.max((viewW / imgW), (viewH / imgH))
  let xdiff = (viewW / 2) - (imgW / 2)
  let ydiff = (viewH / 2) - ( imgH / 2)
  let offsetX = ((imgW - viewW) * scale) / 2
  let offsetY = ((imgH * scale) - viewH) / 2
  map.style.transform = `translate(-${offsetX}px, -${offsetY}px) scale(${scale})`
}

function placePin(x, y) {
  const pin = document.createElement("div")
  pin.classList.add("pin")
  map.appendChild(pin)
  pin.style.transform = `translate(${x}px, ${y}px) scale(${1/scale})`
}

cover()
placePin(840, 1020)
placePin(1430, 940)

window.addEventListener("resize", (event) => cover());
#container {
  width: 80vw;
  height: 60vh;
  outline: 2px solid blue;
  overflow: hidden;
}

.pin {
  position: absolute;
  border-radius: 50%;
  background-color: red;
  width: 16px;
  height: 16px;
}

#img {
  position: absolute;
  opacity:0.8;
}

#map {
  transform-origin: center;
  position: relative;
}
<div id="container">
  <div id="map">
    <div id="img">
      <img src="https://images.unsplash.com/photo-1455849318743-b2233052fcff?q=80&w=2669&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" >
    </div>
  </div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.