如何为CSS img封面设置锚点

时间:2019-06-03 09:08:17

标签: html css flexbox

我想拥有CSS图像封面的功能,它可以填充容器元素,但不改变图像的比例;容器元素的视口中无法容纳的所有内容都将超出容器并被隐藏。

但是,这在CSS中的工作方式(根据我到目前为止的使用方式)是将其定位在图像的中心。

我想说“将覆盖锚点设置为图像的x = 150和y = 375”。想知道如何做到这一点。这样,我可以在图像上选择一个点,并将其作为封面的中心点。

2 个答案:

答案 0 :(得分:2)

您需要将background-position用于背景图像,或将object-position用于具有objec-fit的图像

您需要通过将坐标除以图像尺寸并乘以100%来计算正确的值

background-position: calc(131 / 200 * 100%) calc(66 / 200 * 100%);
/*                        ^^^   ^^^              ^^   ^^^ 
                          |||   |||              ||   |||
                          |||   |||              ||   image height
                          |||   |||          y coordinate
                          |||   image width
                      x coordinate
*/

单击按钮,您将触发动画,这些动画表明焦点位于这些图像中的鸟上

document.addEventListener('click', e => {
  if (e.target.nodeName.toLowerCase() == 'button') {
    document.getElementById(e.target.dataset.id).classList.toggle('animate')
  }
})
.container {
  display: inline-block;
  background-image: url(https://picsum.photos/id/990/200/200);
  background-size: cover;
  background-position: calc(131 / 200 * 100%) calc(66 / 200 * 100%);
  transition: all 1s ease-in-out;
}

img {
  -o-object-fit: cover;
     object-fit: cover;
  -o-object-position: calc(131 / 200 * 100%) calc(66 / 200 * 100%);
     object-position: calc(131 / 200 * 100%) calc(66 / 200 * 100%);
  transition: all 1s ease-in-out;
}

.animate[data-property=width] {
  width: 5px !important;
}
.animate[data-property=height] {
  height: 5px !important;
}
<span id="container-1" data-property="width" class="container" style="width:200px; height:100px"></span>
<span id="container-2" data-property="height" class="container" style="width:100px; height:200px"></span>

<img id="image-1" data-property="width" src="https://picsum.photos/id/990/200/200" alt="" style="width:200px; height:100px">
<img id="image-2" data-property="height" src="https://picsum.photos/id/990/200/200" alt="" style="width:100px; height:200px">
<br>
<button data-id="container-1">Animate</button>
<button data-id="container-2">Animate</button>
<button data-id="image-1">Animate</button>
<button data-id="image-2">Animate</button>

答案 1 :(得分:0)

由于background-size: cover本身的工作方式,使用cover极大地限制了可以居中的坐标数量。

background-size: cover放大(或缩小)图像,以便始终显示尽可能多的图像,同时仍能覆盖整个容器。

让我们直观地看一些示例:

Visual Breakdown

案例1中,需要放大图像,以使图像的width与容器的width相匹配。

第2种情况下,需要放大图像,以使图像的height与容器的height相匹配。

情况3中,需要缩小图像,以使图像的height与容器的height相匹配。

Visual Breakdown

Visual Breakdown

您可能已经注意到,图像将始终始终在一个轴上居中。这意味着您只能使图像在其余轴上居中。此外,只能将落在两个红点之间或红色线(实际上只有1px宽)上的坐标居中,否则图像将无法覆盖整个容器。

background: cover是不够的。您需要使用JS。




JavaScript方法

要设计解决方案,您需要了解...

  1. 图像的固有尺寸,以保持其比例。
  2. 在任何给定时间的容器尺寸
  3. 我们要居中的坐标,它也是一个变量。

在花了数小时试图弄清楚这一点之后,我才真正意识到做您想做的事是完全不切实际的,因为所需的中心坐标离原始图像的边缘越近,输出图像将变得无限大。 。找出公式以产生适当比例的输出图像真的很棘手,因为比例也是一个变量。唯一可行的解​​决方法是通过例如在图像的外部边缘(如边框)​​周围应用禁区来限制坐标的中心,即该区域中的任何内容都不能或不应该居中。 。所谓边框的宽度将完全取决于图像的分辨率。

Self-Imposed Practical Limitations

这就是我正在从事的工作。我们不欢迎您继续我离开的地方,尽管我必须警告您代码现在很乱。我正在全神贯注于如何在保持封面状态的同时正确缩放和定位图像。数学背景会帮助您节省大量时间。祝你好运。

const
  srcImg = document.querySelector('#source-image'),
  output = document.querySelector('#output')
let
  srcImgWidth, srcImgHeight

const
test = document.querySelector('#test')

window.onload = ()=>{
  srcImgWidth = srcImg.width
  srcImgHeight = srcImg.height
}

srcImg.onclick = function(e){
  const
	  ctrWidth = output.offsetWidth,
 	 	ctrHeight = output.offsetHeight,
    compAxisX = ctrWidth / srcImgWidth,
    compAxisY = ctrHeight / srcImgHeight,
    rect = srcImg.getBoundingClientRect(),
  	x = e.clientX - rect.left,
  	y = e.clientY - rect.top
  
  // create cover
  if (compAxisX > compAxisY){
    //console.log('width grow/shrink to match width')
    output.style.backgroundSize = `${ctrWidth}px ${ctrWidth / srcImgWidth * srcImgHeight}px`
  } else if (compAxisY > compAxisX) {
    //console.log('height grow/shrink to match height')
    output.style.backgroundSize = `${ctrHeight / srcImgHeight * srcImgWidth}px ${ctrHeight}px`
  } else {
    // square in square ???
    output.style.backgroundSize = `${ctrWidth}px ${ctrHeight}px`
  }
  
  // determine scale of image
  const
    compAxisX1 = ctrWidth / 2 / x,
    compAxisY1 = ctrHeight / 2 / y
  let
    qtrImplicitViewportX,
    qtrImplicitViewportY,
    scale
  
  // cover container with implicit viewport
  if (compAxisX1 > compAxisY1){
    //console.log('width grow/shrink to match width')
    qtrImplicitViewportX = ctrWidth / 2
    qtrImplicitViewportY = ctrWidth / 2 / x * y
    
    //srcImgWidth / x * scale * srcImgWidth + 'px'
    //srcImgHeight / y * scale * srcImgHeight + 'px'
    
    // x / srcImgWidth === qtrImplicitViewportY
    newWidth = qtrImplicitViewportX / (x / srcImgWidth)
    newHeight = qtrImplicitViewportY / (y / srcImgHeight)

    console.log(newWidth, newHeight)
    output.style.backgroundSize = `${newWidth}px ${newHeight}px`
    output.style.backgroundPosition = '0% 100%'
    
  } else if (compAxisY1 > compAxisX1){
    //console.log('height grow/shrink to match height')
    //qtrImplicitViewportX = ctrHeight / 2 / y * x
    qtrImplicitViewportY = ctrHeight / 2
    
    //srcImgWidth / x * scale * srcImgWidth + 'px'
    //srcImgHeight / y * scale * srcImgHeight + 'px'
    
    // x / srcImgWidth === qtrImplicitViewportY
    newWidth = qtrImplicitViewportX / (x / srcImgWidth)
    newHeight = qtrImplicitViewportY / (y / srcImgHeight)

    console.log(newWidth, newHeight)
    output.style.backgroundSize = `${newWidth}px ${newHeight}px`
    output.style.backgroundPosition = '0% 100%'
    
  } else {
    
  }

  test.style.width = newWidth + 'px'
  test.style.height = newHeight + 'px'
  test.style.bottom = output.getBoundingClientRect().bottom
  test.style.left = output.getBoundingClientRect().left
  
}
#input-container {
  padding: 10px;
  display: inline-block;
  background: grey;
}

#output {
  width: 256px;
  height: 377px;
  resize: both;
  position: relative;
  overflow: auto;
  box-sizing: border-box;
  border: solid red 3px;
  background-image: url('https://i.postimg.cc/s2PnSDmR/test0.png');
  background-size: cover;
  background-repeat: no-repeat;
}

#test {
  z-index: -1;
  width: 256px;
  height: 377px;
  position: absolute;
  transform: translateY(-100%);
  background: orange;
  background-image: url('https://i.postimg.cc/s2PnSDmR/test0.png');
  background-size: cover;
  background-repeat: no-repeat;
}
<div id='input-container'>  
  <div>Click the Image to Center on Click Point</div>
  <img id='source-image' src='https://i.postimg.cc/s2PnSDmR/test0.png' />
</div>

<div id='output'></div>
<div id='test'></div>