使用可设置动画的属性模拟对象拟合

问题描述

我正在尝试制作一个需要从缩略图到全屏图像的动画的灯箱。

缩略图状态下,图像将以固定的宽高比(例如3:2)保存在容器内。画廊中的每张图片都必须适合这个分配的空间,并覆盖其整个表面(通常为ThemeResource)。

在全屏状态下,容器将扩展为100vw:100vh,并且图像可以扩展(甚至收缩,对于某些异常高的图像来说也是如此)以适合(object-fit: cover)。

object-fit: contain必须始终保持其纵横比不变(在两种状态下以及在动画过程中)。

我可以为容器的<img>width(它们具有绝对值)制作动画。

但是height动画是离散的。

这是一支书写状态和容器动画的钢笔:https://codepen.io/rslemos/pen/PoNMymR(要观看动画,应从object-fit元素中删除expanded类)。

是否有任何CSS技巧可以使用线性属性来模拟container

编辑

在动画过程中,图像本身-我的意思是,由位图覆盖的表面(而不是object-fit元素,该表面在任何方向上都可能比<img>更大或更小)应从其初始变形到最终尺寸。

我还编辑了笔,以显示容器的宽高比(宽度:高度) 1)时的初始状态。

解决方法

解决方案看起来很复杂,但不是很复杂,只是一堆数学...

  1. 首先,您需要弄清楚图像的比例与要放入图像的框的比例(div或整个屏幕)之间的差异。

  2. 然后,您需要确定尺寸是受比例差异的高度限制还是宽度限制(请参见步骤1),以及是否要覆盖(最大化最小尺寸)还是包含(最大化最大尺寸)

  3. 最后,您需要在不同的框(div或整个屏幕)之间切换。在这里,我不考虑div的位置(总是在左上角),因为我希望本演示中的数学保持简单。

lst1 <- structure(list("null","gclid=ertyyhglkdl-kjkY","utm_source=google&utm_medium=cpc&utm_campaign=1234556&utm_term=brand%20shirts&utm_content=Brand&gclid=jhajsgjdgd_ajs","utm_source=google&utm_medium=cpc&utm_campaign=1674814043&utm_term=brand%20shirts&utm_content=Brand&gclid=KvgMsEAAYASAAEgLq6vD_BwE","null","utm_source=fb&utm_medium=ctw&utm_campaign=Shirt_rem&utm_content=CasciaShirt"),class = c("extracted","list"))
const img = document.querySelector('img')
const div = document.querySelector('.box')

// initialize some stuff
const {offsetHeight: boxHeight,offsetWidth: boxWidth} = div
let naturalHeight,naturalWidth
img.addEventListener('load',() => {
  naturalHeight = img.naturalHeight
  naturalWidth = img.naturalWidth  
  scaleToBox()
  requestAnimationFrame(
    () => img.classList.remove('initial')
  )
})

function scaleToBox() {
  let scale
  let x = 0,y = 0
  // is image ratio wider than container ratio
  if (boxWidth / boxHeight < naturalWidth / naturalHeight) {
    // width is the largest dimension,maximize height to cover
    scale = boxHeight / naturalHeight
    // center along x axis
    x = -(naturalWidth * scale - boxWidth) / 2 / scale
  } else {
    // height is the largest dimension,maximize width to cover
    scale = boxWidth / naturalWidth
    // center along y axis
    y = -(naturalHeight * scale - boxHeight) / 2 / scale
  }
  img.style.setProperty('transform',`scale(${scale}) translate(${x}px,${y}px)`)
}

function scaleToScreen() {
  let scale
  let x = 0,y = 0
  // is image ratio wider than container ratio
  if (innerWidth / innerHeight < naturalWidth / naturalHeight) {
    // width is the largest dimension,maximize width to contain
    scale = innerWidth / naturalWidth
    // center along y axis
    y = -(naturalHeight * scale - innerHeight) / 2 / scale
  } else {
    // height is the largest dimension,maximize height to contain
    scale = innerHeight / naturalHeight
    // center along x axis
    x = -(naturalWidth * scale - innerWidth) / 2 / scale
  }
  img.style.setProperty('transform',${y}px)`)
}


let state
div.addEventListener('click',() => {
  if (!naturalHeight || !naturalWidth) {
    return
  }
  
  div.classList.toggle('full')  
  if (!state) {
    scaleToScreen()
  } else {
    scaleToBox()
  }

  state = !state
})
body {
  margin: 0;
}

.box {
  position: relative;
  height: 200px;
  width: 300px;
  transition: clip-path 1s;
  clip-path: polygon(0 0,100% 0,100% 100%,0% 100%);
}

.box.full {
  clip-path: polygon(0 0,100vw 0,100vw 100vh,0 100vh);
}

img {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  transition: transform 1s;
}

img.initial {
  height: 100%;
  width: 100%;
  object-fit: cover;
  transition-duration: 0s;
}

即使父div不在左上角(我不想混淆此演示的工作原理),也可以通过对图像进行动画处理以改善工作效果,以改进此演示。

,

如果我正确理解了您的请求,则可以尝试使用object-fitposition:absolute;来代替transform: translate()

.container > img  {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%,-50%); 
   width: auto;
   height: auto;
   max-width: 100%;
}

这是经过修改的笔: https://codepen.io/gsarig/pen/KKzOrJW

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...