问题描述
在缩略图状态下,图像将以固定的宽高比(例如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)时的初始状态。
解决方法
解决方案看起来很复杂,但不是很复杂,只是一堆数学...
-
首先,您需要弄清楚图像的比例与要放入图像的框的比例(div或整个屏幕)之间的差异。
-
然后,您需要确定尺寸是受比例差异的高度限制还是宽度限制(请参见步骤1),以及是否要覆盖(最大化最小尺寸)还是包含(最大化最大尺寸)
-
最后,您需要在不同的框(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-fit
和position: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