Как установить точку привязки для обложки CSS img - PullRequest
0 голосов
/ 03 июня 2019

Мне бы хотелось иметь поведение обложки CSS-изображения, где оно заполняет элемент контейнера, но не меняет пропорции изображения; все, что не помещается в область просмотра элемента контейнера, выходит за пределы контейнера и скрыто.

Тем не менее, способ, которым это работает в CSS (из того, как я его использовал до сих пор), заключается в том, что он размещает его вокруг центра изображения.

Я хотел бы сказать, что «установите опорную точку обложки на x = 150 и y = 375 для изображения». Хотите знать, как это сделать. Таким образом, я мог бы выбрать точку на изображении, и она была бы центральной точкой обложки.

Ответы [ 2 ]

2 голосов
/ 03 июня 2019

Вам необходимо использовать 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>
0 голосов
/ 04 июня 2019

Использование 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...