图片的底层原理
计算机中的颜色表示
计算机在表示颜色的时候,有两种形式,一种称作索引颜色(Index Color)
,一种称作直接颜色(Direct Color)
。
- 索引色
用一个数字来代表(索引)一种颜色,在存储图片的时候,存储一个数字的组合,同时存储数字到图片颜色的映射。这种方式只能存储有限种颜色,比如某计算机系统中,使用一个字节的数字来索引一种颜色,一个字节 2^8 表示一个颜色,也就是最多支持 256 种颜色。
- 直接色
使用四个数字来代表一种颜色,这四个数字分别代表这个颜色中红色、绿色、蓝色以及透明度
图片构成方式
- 位图(Bitmap)
又叫栅格图、点阵图,使用像素阵列来表示图像。位图就是由象素阵列的排列来实现其显示效果的,每个象素有自己的颜色信息,在对位图图像进行编辑操作的时候,可操作的对象是每个象素,我们可以改变图像的色相、饱和度、明度,从而改变图像的显示效果。位图根据位深度,有 1、4、8、16、24、32 位图像等。位图放大会失真变模糊。
- 矢量图
计算机图形学中用点、直线或者多边形等基于数学方程的几何图元表示图像。相比较位图,矢量图保存最少的信息,体积更小,缩放不会失真。
为什么SVG格式的图片放大不会失真模糊呢?
SVG(可缩放矢量图形)是一种基于XML的图形格式,与传统的位图图形(如JPEG、PNG)不同,SVG使用矢量图形描述图像。它描述图像的方式是基于数学公式和几何路径,SVG图像使用路径来定义图形,路径包含了一系列的命令和坐标点,用于绘制线条、曲线、形状等,当你放大SVG图像时,浏览器或图形软件会重新计算路径的坐标,并按比例进行缩放,而不会引入额外的像素或失真,SVG图像也可以包含文本信息,而这些文本信息同样是基于矢量的,因此也可以无损缩放。
图片格式
不同的图片格式在不同的应用场景下有各自的优缺点。以下是常见的图片格式(JPEG、PNG、GIF、WebP)的对比:
图片格式 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
JPEG | - 高压缩率 | - 有损压缩 | - 照片、复杂图像 |
- 广泛支持 | - 可能出现压缩失真 | ||
PNG | - 无损压缩 | - 文件大小相对较大 | - 透明背景、图标、简单图像 |
- 支持透明度 | - 不适用于照片 | ||
GIF | - 支持动画 | - 有限色彩 | - 简单动画、图标 |
- 支持透明度 | - 不适用于照片 | ||
WebP | - 高压缩率 | - 浏览器支持相对有限 | - 现代浏览器、要求高压缩率和透明度 |
- 支持透明度 | - 部分浏览器不支持 |
选择合适的图片格式取决于具体的应用场景和需求。JPEG适用于照片,PNG适用于需要保持图像质量和透明背景的场景,GIF适用于简单动画和图标,而WebP则是一种现代的、通常具有较高压缩率的格式,但需考虑浏览器兼容性。
图片跨域问题
图片(以及其他资源,如脚本、样式表等)存在跨域问题是由浏览器的同源策略(Same-Origin Policy)引起的。同源策略是一种安全机制,限制了来自不同源(域名、协议、端口)的页面对资源的访问,目的是防止恶意网站通过一些手段获取用户的敏感信息。
同源策略对于JavaScript访问其他域的资源有着严格的限制。解决图片跨域主要有以下方式:
-
CORS(跨域资源共享) 在提供图片的服务器上配置CORS头,允许特定域(你的网站域)的访问。
-
JSONP(仅适用于GET请求) 使用Script标签 JSONP利用了Script标签不受同源策略限制的特性,通过动态创建Script标签来加载跨域资源。
-
代理服务器:在你的域内设置一个代理服务器,该代理服务器可以访问其他域上的资源。前端通过访问代理服务器来获取资源,绕过了同源策略。
图片相关优化操作
-
图片懒加载。使用
intersectionObserve
或者使用getBoundingClientRect
结合视窗的高度来判断是否在可视区域内,如果在即将预设的data-src属性
赋值到img标签
的src属性
即可 -
图片预加载。动态创建img标签,提前加载图片,后续可从缓存中读取。
-
图片手动压缩。 使用压缩工具进行手动压缩
-
图片CDN加速。 静态资源放在CDN上,可以加速用户访问速度
-
图片加载失败处理
js
const imgOnError = (e) => {
e.currentTarget.onerror = null
e.currentTarget.src = '默认占位图片地址'
e.currentTarget.className = 'error'
}
// react
<img src={oss_url} onError={imgOnError}/>
- img标签在移动端如果src上没有一个有效的值,会产生一个白色的边框。有时候我们为了兜底隐藏该边框需要做一个处理。
css
img[src=""],
img:not([src]) {
opacity: 0;
}
- 图片裁剪。 图片裁剪大致流程如下:
详细流程推荐阅读👉:从零开始做一个图片裁剪组件
- 图片添加水印
推荐阅读👉:# 前端水印实现方案
图片资源优化
前端根据不同的设备的分辨率自动调整图片大小
1.使用srcset
和sizes
属性
srcset 属性用于指定一组备选的图片资源,以逗号分隔每个图片资源并指定对应的分辨率宽度,浏览器会根据当前设备的像素密度(DPR)和 CSS 像素比例(devicePixelRatio)来选择最佳匹配的图片资源进行加载;而 sizes 属性则用于设置媒体查询条件或者视口尺寸条件,用于判断图片显示在页面中的大小。
以下是一个示例代码:
js
<img src="small.jpg"
srcset="small.jpg 640w, medium.jpg 960w, large.jpg 1200w"
sizes="(max-width: 480px) 100vw, (max-width: 1024px) 50vw, 33.3vw">
在上述示例中,srcset 属性列出了三种不同大小的备选图片资源,并指定了相应的分辨率宽度。如果当前设备的窗口宽度为 800px,浏览器将会选择 medium.jpg 这个备选图片资源进行加载。而 sizes 属性则设置了两个条件,当窗口宽度小于等于 480px 时,图片将会占满整个窗口宽度;当窗口宽度大于 480px 且小于等于 1024px 时,图片将会占据窗口宽度的一半;当窗口宽度大于 1024px 时,图片将会占据窗口宽度的三分之一。
需要注意的是,srcset 和 sizes 属性并不兼容所有浏览器,使用前建议进行兼容性检查。
2.模拟scrset
和sizes
属性 首先,将 img 元素的 src 属性设置为最小分辨率的图片,然后在 JavaScript 中获取该元素并动态地更新其 src 属性,以便在设备像素密度变化时加载最合适的图片资源。
html
<img id="my-image" src="small.jpg">
js
function getBestImageSrcset() {
var windowWidth = window.innerWidth;
var images = [
{srcset: "small.jpg", width: 640},
{srcset: "medium.jpg", width: 960},
{srcset: "large.jpg", width: 1200}
];
var bestImage = images[0];
for (var i = 1; i < images.length; i++) {
if (windowWidth >= images[i].width && images[i].width > bestImage.width) {
bestImage = images[i];
}
}
return bestImage.srcset;
}
var myImage = document.getElementById("my-image");
myImage.src = getBestImageSrcset();
在上述示例中,getBestImageSrcset() 函数会根据当前设备分辨率的宽度和一组备选的图片资源(包括 srcset 和宽度)计算出最佳图片资源,并返回其相对路径。接下来,通过 JavaScript 获取 img 元素并动态更新其 src 属性为最佳图片资源的相对路径。这样可以确保在不同设备的分辨率下都可以加载最合适的图片资源。
实际开发中需要根据具体情况进行优化和调整。这种方式也可能存在一定的兼容问题。
3.使用成熟的第三方库
- Picturefill
- next/image
4.使用CSS媒体查询:可以通过CSS的媒体查询来根据设备的屏幕尺寸和像素密度,为不同的设备设置不同的背景图片。
css
.my-element {
background-image: url('low-res.jpg');
}
@media only screen and (min-width: 768px) {
.my-element {
background-image: url('medium-res.jpg');
}
}
@media only screen and (min-width: 1200px) {
.my-element {
background-image: url('high-res.jpg');
}
}
- 使用JavaScript动态加载:通过JavaScript可以根据设备的特性和屏幕信息动态选择加载不同分辨率的图片。可以通过
window.devicePixelRatio
获取设备的像素密度,并根据需要动态创建<img>
标签并设置对应的图片路径。
js
var image = new Image();
var pixelRatio = window.devicePixelRatio;
if (pixelRatio >= 2) {
image.src = 'high-res.jpg';
} else if (pixelRatio >= 1.5) {
image.src = 'medium-res.jpg';
} else {
image.src = 'low-res.jpg';
}
document.body.appendChild(image);
通过上述方式,可以根据不同设备的屏幕尺寸和像素密度,提供适合的图片分辨率,以优化用户在不同设备上的图片显示效果和加载性能。
webp格式图片
webp格式图片为什么高效
1.图片压缩算法:WebP采用了一种基于预测的压缩算法,可以识别和删除图片中的冗余信息,从而实现更好的压缩效果。这种算法比传统的JPEG和PNG压缩算法更高效。
2.支持有损和无损压缩:WebP可以同时支持有损和无损压缩,这意味着它可以在保持高质量的同时实现更小的文件大小。
3.支持alpha通道压缩:WebP支持alpha通道压缩,这意味着它可以在压缩过程中保留图像的透明度信息,并产生更小的文件大小。
4.支持动态图像:WebP还支持动态图像,这种格式可以在一个文件中包含多个帧,从而可以创建动画效果。
如何解决webp格式在浏览器中不兼容的问题
WebP 是一种高效的图片格式,它可以帮助减少图片文件的大小,从而提高网页的加载速度。然而,由于某些浏览器不支持 WebP 格式,使用 WebP 格式可能会导致一些兼容性问题。以下是几种解决 WebP 格式在浏览器中不兼容的方法:
1.使用图片格式检测:在服务器端检测浏览器是否支持 WebP 格式,如果支持,则使用 WebP 格式的图片,否则使用其他格式的图片。这可以通过服务器端的代码来实现。
2.使用 polyfill:Polyfill 是一种 JavaScript 库,可以让浏览器支持某些不支持的功能。有一些 polyfill 可以帮助浏览器在不支持 WebP 格式的情况下,使用 WebP 格式的图片。这些 polyfill 可以通过第三方库或者 CDN 来获取。
3.使用picture标签
html
<!-- WebP 格式图片 -->
<picture>
<source srcset="example.webp" type="image/webp">
<img src="example.jpg" alt="WebP Image">
</picture>
<picture>
标签用于提供WebP格式的备用,只有在浏览器支持WebP时才会加载
服务器端如何检测浏览器是否支持 WebP 格式
服务器端可以通过检测浏览器的 User-Agent 字符串来判断浏览器是否支持 WebP 格式。具体方法如下:
1.检查 User-Agent 是否包含关键字"Chrome"、"Opera"、"Edge"等支持 WebP 格式的浏览器名称和版本号。
2.如果浏览器名称和版本号匹配支持 WebP 格式的浏览器,则向客户端返回 WebP 格式的图片。
3.如果浏览器名称和版本号不匹配支持 WebP 格式的浏览器,则向客户端返回其他格式的图片。