Fork me on GitHub

object-fit各种拉伸算法

需求来源

object-fit 可以很方便的对 img 标签做拉伸适配,但它一是兼容性不太好,二是只能在可替换元素中使用,如果我们想对一个 div 做类似调整,它就无能为力了,所以这种场景下就需要我们对 object-fit 的各种算法有一定了解才能手动实现。

算法实现

object-fit 一共有 fill | contain | cover | none | scale-down 五种拉伸方式,以下是针对每种方式的算法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Cover
// 被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。 整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边”。
function cover(containerSize, elementSize) {
const containerRatio = containerSize.width / containerSize.height
const elementRatio = elementSize.width / elementSize.height

let width, height

if (containerRatio > elementRatio) {
width = containerSize.width
height = containerSize.width / elementRatio
} else {
width = containerSize.height * elementRatio
height = containerSize.height
}

return { width, height }
}

// Contain
// 被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。
function contain(containerSize, elementSize) {
const containerRatio = containerSize.width / containerSize.height
const elementRatio = elementSize.width / elementSize.height

let width, height

if (containerRatio < elementRatio) {
width = containerSize.width
height = containerSize.width / elementRatio
} else {
width = containerSize.height * elementRatio
height = containerSize.height
}

return { width, height }
}

// Fill
// 被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。
function fill(containerSize) {
return containerSize
}

// None
// 被替换的内容将保持其原有的尺寸。
function none(elementSize) {
return elementSize
}

// ScaleDown
// 内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。
function scaleDown(containerSize, elementSize) {
if (elementSize.width > containerSize.width || elementSize.height > containerSize.height) {
return contain(containerSize, elementSize)
} else {
return none(containerSize)
}
}

示例

具体示例可以参考 https://codesandbox.io/s/object-fit-gechonglashensuanfa-23uhd