前言
设置图片有两种方法,一种是只用<img /> 标签,另一种是给div或者其他元素设置背景background-image。
前者可以理解为前景图,后者理解为背景图。
下面我们来对两者进行分析。
一:background-image方式
列出background-image的几个属性帮助理解:
background-size: 设置整个背景图片的大小
background-size: 100px 100px;
是指把背景图片的大小设置为宽100px 高100px;
background-size: cover/contain
cover是指将图片按图片原本比例放大,让图片覆盖住div容器,多出来的部分裁剪。
contain是指在保持原比例的情况下,尽量撑满容器的情况下不超出容器,所以这种情况下,如果容器宽高比和图片宽高比不一致的话,图片不会填满容器,容器会留白。
background-position: 设置背景图片左上角相对于div左上角的位置
(1)background-position: -10px -10px;
是指以div左上角为(0,0)起始点,图片向左移动10px,向上移动10px。此时div的(0,0)就和背景图的(10,10)重合,所以在div内只能看到背景图(10,10)位置开始的图像
反之 background-position: 10px 10px;
是指以div左上角为(0,0)起始点,图片向右移动10px,向下移动10px。此时背景图的(0,0)就和div的(10,10)重合,所以背景图起始点在div的(10,10)位置,这时候div的(10,10)才出现背景图,(5,5),(0,0)等位置是没有背景图的
(2) background-position:50% 0%
positionX = (容器的宽度 - 背景图片宽度) * 百分比
positionY = (容器的高度 - 背景图片高度) * 百分比
(3) background-position:center top
与background-position:50% 0% 效果一致。
关键字:left或者top,bottom,center等值可以对应到百分比,和百分比的处理方式一致。
background-attachment:scroll/local/fixed
这个属性是在内容很多,出现滚动条的时候,用来确定背景图和内容之间的滚动关系的
可以参考这个来理解:https://codepen.io/Chokcoco/pen/xJJorg
scroll: 背景相对于元素本身固定,不随内容滚动。(默认值)
local: 背景相对于元素内容固定,内容很多时,背景岁随着内容滚动。
fixed: 背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。
二. <img> 和background-image区别
是否占位
img是html标签 ,占位;background-image是css样式,不占位;
但是使用img的时候如果我们希望宽度百分百,高度由图片宽高比例还确定的时候,就会出现高度不确定,导致图片在加载完之后,网页布局发生变化的情况。
使用background-image的时候我们一般会将容器大小确定,所以图片是否加载完成不会影响容器大小,所以网页布局不会 变化。
加载顺序
img是html元素,是网页结构的一部分,所以会在加载结构的过程中加载,而background-image是css样式,会等到结构加载完成(网页内容全部显示以后)才开始加载。所以img的图片会比background-image先加载。
三. 图片居中问题
第一种情况:图片本身比例不变(即不能让图片变形),让图片固定宽高比4:3的方式显示。
使用background-image很简单
设置容器宽高比为4:3,再给图片设置
1
2
3
4
5
6.bg-img {
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
}所以重点就在于怎么让容器比例为4:3。如果 容器宽度确定,那么直接写死宽度和高度就可以了。如果容器宽度不确定(根据屏幕宽度来决定),那么可以用这些方式来保证容器宽高比
里面的第3点讲到了如何保证容器宽高比。
使用img
1️⃣ 我们让img外层套一个容器div,这个容器是图片要显示的范围。首先比较容器宽高比boxRate和图片宽高比imgRate。(注意我使用的是宽高比,即宽/高)
如果picRate > boxRate ,说明图片偏宽,那么让图片高度设置为容器高度,用此高度和picRate相乘得出来图片的宽度。这样图片宽度 就会大于容器宽度,再将图片宽度 宽出来的部分裁剪,就达到 将图片等比例扩大之后盖住容器的效果了,也就是cover的效果。
反之,如果picRate < boxRate,说明图片偏高,那么让图片宽度等于容器宽度,用此宽度除以picRate来得到图片高度,这样得到的图片高度会比容器高度大,再将图片高出来的部分 裁剪 。
2️⃣ 设置好图片宽度和高度之后 ,第二步是将图片 挪动到容器中间,让图片 显示中间部分,将两边多出来的部分裁剪掉。
第一种方式:可以通过 计算图片宽度和高度来计算margin-left或者margin-top。
代码如下:
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<img @load="adaptImg"></img>
function adaptImg(event) {
const currentTarget = event.currentTarget;
// 使用jquery
const picWidth = currentTarget.naturalWidth;
const picHeigt = currentTarget.naturalHeight;
const picRate = picWidth / picHeigt;
const box = $(currentTarget).parent();
const boxHeight = $(box).height();
const boxWidth = $(box).width();
const boxRate = boxWidth / boxHeight;
// 不使用 jquery
// const picWidth = currentTarget.naturalWidth;
// const picHeigt = currentTarget.naturalHeight;
// const picRate = picWidth / picHeigt;
// const box = currentTarget.parentNode;
// const boxHeight = box.clientHeight;
// const boxWidth = box.clientWidth;
// const boxRate = boxWidth / boxHeight;
let finalWidth = 0;
let finalHeight = 0;
let marginLeft = 0;
let marginTop = 0;
if (picRate > boxRate) {
// asHeight
finalHeight = boxHeight;
finalWidth = picRate * boxHeight;
marginLeft = -(finalWidth - boxWidth) / 2;
currentTarget.style.height = '100%';
currentTarget.style.marginLeft = marginLeft + 'px';
} else {
// asWidth
finalWidth = boxWidth;
finalHeight = boxWidth / picRate;
marginTop = -(finalHeight - boxHeight) / 2;
currentTarget.style.width = '100%';
currentTarget.style.marginTop = marginTop + 'px';
}
}第二种方式:可以通过position:absolute配合margin: auto; 再设置left,top,right,bottom4个值来达到图片和 容器居中的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17.center-img-container {
position: relative;
overflow: hidden;
}
// 下面的是重点
.center-img-container img {
position: absolute;
left: -9999px;
right: -9999px;
top: -9999px;
bottom: -9999px;
margin: auto;
}
// 当设置left: -9999px;right: -9999px;right: -9999px;top: -9999px; bottom: -9999px;
// 四个数值要一样。记得margin要设置成auto
// 当四个值都设置成-9999px作用于图片比容器大的时候。
// 当四个值都设置成0作用于图片比容器小的时候。四. 图片模糊加载问题
思路: 一开始的时候,将img的src赋值为一个尺寸比较小的图片地址,并在img元素上添加一个data-src属性(清晰图片的地址),当元素处于视图中时,创建一个新的图片元素,将此新图片元素src赋值为之前img的data-src值,当新建的图片加载完成的时候,对之前img的src进行替换,这样就将模糊图片替换成了清晰图片
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
39export const lazyLoadImg = () => {
// 滚动加载出来的元素可以懒加载
$(window).on('scroll', function() {
clearTimeout(loadInterval);
var loadInterval = setTimeout(function() {
$('.lazy-image').each((index, item) => {
isElementInViewport(item) && loadImg(item);
});
}, 100);
});
$('.lazy-image').each((index, item) => {
loadImg(item);
});
};
function loadImg(item) {
const $item = $(item);
if ($item.data('status') === 'loading' || $item.data('status') === 'loaded') {
return;
}
$item.data('status', 'loading');
const img = new Image();
const dataSrc = $item.attr('data-src');
img.onload = () => {
$item
.attr('src', dataSrc)
.removeClass('lazy-image')
.data('status', 'loaded');
};
img.src = dataSrc;
}
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
var threshold_x = 0;
var threshold_y = 100;
return rect.top >= 0 - threshold_y && rect.left >= 0 - threshold_x && rect.top <= window.innerHeight + threshold_y && rect.left <= window.innerWidth + threshold_x;
}