前端 性能优化 (图片与样式篇)

文章目录

  • 前端能够做哪些图片优化?
    • 1、减小图片体积
    • 2、图片缓存
      • 服务工作线程 (Service Workers)缓存
      • IndexDB缓存图片
      • LocalStorage缓存
    • 3、图片懒加载
      • 使用 loading="lazy" 属性
    • 4、不同分辨率下使用不同的图片
    • 5、使用webp格式的图片
    • 6、配置图片CDN
    • 7、减少图片和动图的使用
  • css样式如何优化?
    • 1、关键css优先,非关键css等页面加载完成再加载或引入
    • 2、使用 CSS 预处理器和后处理器
    • 3、利用 CSS 变量
    • 4、减少和优化选择器的复杂性
    • 5、删除无用的 CSS
    • 6、利用缓存
    • 7、编写代码时尽量减少重排和重绘

前端能够做哪些图片优化?

1、减小图片体积

压缩图片可以减小文件大小,提升页面加载速度。可以使用工具如 TinyPNG 或 ImageOptim 来优化图片。

2、图片缓存

浏览器缓存是最基础的前端缓存方式。通过设置HTTP响应头,指定缓存策略,可以控制浏览器对图片资源的缓存行为。

Cache-Control: 设置图片的缓存时长。例如,Cache-Control: max-age=31536000表示缓存一年。
Expires: 指定缓存过期日期,配合Cache-Control使用。
ETag 和 Last-Modified: 标记资源的版本号或最后修改时间,当浏览器再次请求该资源时,通过对比判断是否需要重新下载。

这些头信息可以在服务器端配置,常用于CDN或静态资源服务器。

服务工作线程 (Service Workers)缓存

Service Workers是一种更高级的缓存方式,通过注册Service Worker脚本,可以拦截图片请求并从缓存中返回内容。可以在应用初始化时加载图片资源并存储在Service Worker的缓存中,后续请求可以直接读取缓存内容。

// 安装阶段(Install Event),当 Service Worker 安装时触发
self.addEventListener('install', event => {// 使用 event.waitUntil 确保安装过程完成后才继续执行后续的步骤event.waitUntil(// 打开一个名为 'image-cache' 的缓存存储caches.open('image-cache').then(cache => {// 将图片资源添加到缓存中return cache.addAll(['/images/photo1.jpg', // 图片1'/images/photo2.jpg', // 图片2// 更多图片资源可以添加在这里...]);}));
});// 激活阶段,拦截网络请求并返回缓存数据(Fetch Event)
self.addEventListener('fetch', event => {// 判断请求是否是图片资源if (event.request.destination === 'image') {// event.respondWith 接受一个 Promise,返回响应数据event.respondWith(// 尝试从缓存中匹配请求caches.match(event.request).then(response => {// 如果缓存中存在图片,直接返回缓存的响应return response || // 如果缓存中没有对应的图片,则执行网络请求fetch(event.request).then(fetchResponse => {// 一旦网络请求返回图片数据,就将其缓存return caches.open('image-cache').then(cache => {// 将网络获取的图片存入缓存cache.put(event.request, fetchResponse.clone());// 返回从网络获取的图片响应return fetchResponse;});});}));}
});

IndexDB缓存图片

IndexedDB一个适合存储较大数据(如图片二进制数据)的浏览器数据库。要存储图片,我们通常将图片文件转换为 Blob(二进制大对象),并存入 IndexedDB。这样,在后续需要加载缓存图片时,可以从 IndexedDB 中检索 Blob,然后将其转化为 URL 以加载到页面中。

初始化 IndexedDB 数据库和对象存储

// 初始化 IndexedDB
function openDatabase() {return new Promise((resolve, reject) => {const request = indexedDB.open('imageCacheDB', 1);// 创建或更新数据库时触发request.onupgradeneeded = function(event) {const db = event.target.result;if (!db.objectStoreNames.contains('images')) {db.createObjectStore('images'); // 创建名为 "images" 的对象存储}};request.onsuccess = function(event) {resolve(event.target.result); // 成功打开数据库};request.onerror = function(event) {reject(event.target.error); // 打开数据库失败};});
}

将图片存储到 IndexedDB 中

// 将图片 Blob 存入 IndexedDB
function cacheImage(url, blob) {openDatabase().then(db => {const transaction = db.transaction('images', 'readwrite');const store = transaction.objectStore('images');store.put(blob, url); // 使用图片 URL 作为键transaction.oncomplete = () => {console.log('Image cached in IndexedDB');};}).catch(error => {console.error('Failed to cache image:', error);});
}// 获取图片并缓存
function fetchAndCacheImage(url) {fetch(url).then(response => response.blob()).then(blob => {cacheImage(url, blob); // 缓存图片}).catch(error => {console.error('Failed to fetch image:', error);});
}

从 IndexedDB 中读取图片并显示
当需要显示图片时,可以从 IndexedDB 读取 Blob 数据并生成一个 URL 给 标签使用

// 从 IndexedDB 中获取图片 Blob
function getCachedImage(url) {return new Promise((resolve, reject) => {openDatabase().then(db => {const transaction = db.transaction('images', 'readonly');const store = transaction.objectStore('images');const request = store.get(url);request.onsuccess = function(event) {if (event.target.result) {resolve(event.target.result); // 返回图片 Blob} else {reject('Image not found in cache');}};request.onerror = function() {reject('Failed to retrieve image from IndexedDB');};});});
}// 使用缓存图片显示到页面
function displayImageFromCache(url, imgElementId) {getCachedImage(url).then(blob => {const imgURL = URL.createObjectURL(blob);document.getElementById(imgElementId).src = imgURL;}).catch(error => {console.error('Error displaying cached image:', error);});
}// 示例调用
const imageUrl = 'https://example.com/image.jpg';
fetchAndCacheImage(imageUrl); // 首次获取并缓存
displayImageFromCache(imageUrl, 'myImage'); // 从缓存中显示图片

LocalStorage缓存

// 保存图片到 localStorage
function cacheImage(url) {fetch(url).then(response => response.blob()).then(blob => {const reader = new FileReader();reader.onload = function () {localStorage.setItem('cachedImage', reader.result); // 将Base64数据存入localStorage};reader.readAsDataURL(blob);});
}

3、图片懒加载

懒加载和占位图也是提升前端图片加载性能的技巧,虽然不算是严格意义的缓存。懒加载会等到图片在视窗中出现时才开始加载,减少初始页面加载的资源量,占位图则在图片未加载完成前提供一个小尺寸、模糊的占位图,让页面看起来更平滑。

假设你有多个图片,添加 data-src 属性存储图片的实际 URL,src 属性设置为占位符(比如一张模糊的小图或空白图片),这样只有当图片进入视口时,才会加载实际的图片。

<img class="lazy" data-src="https://example.com/photo1.jpg" src="placeholder.jpg" alt="Image 1" />
<img class="lazy" data-src="https://example.com/photo2.jpg" src="placeholder.jpg" alt="Image 2" />
<img class="lazy" data-src="https://example.com/photo3.jpg" src="placeholder.jpg" alt="Image 3" />
<!-- 更多图片 -->

使用 IntersectionObserver 来监视图片是否进入视口,如果进入视口,就把 data-src 的值赋给 src,从而触发图片加载。

// 创建一个 IntersectionObserver 实例,监视图片是否进入视口
const lazyLoadImages = document.querySelectorAll('img.lazy');const imageObserver = new IntersectionObserver((entries, observer) => {entries.forEach(entry => {// 如果图片进入视口if (entry.isIntersecting) {const image = entry.target;// 将 data-src 的真实图片 URL 赋值给 src 属性image.src = image.dataset.src;// 一旦图片加载完毕,停止观察该图片image.onload = () => {image.classList.remove('lazy'); // 可选:移除懒加载样式};observer.unobserve(image); // 停止观察已加载的图片}});
}, {rootMargin: '0px', // 可选:在视口边缘触发加载(当图片接近视口时开始加载)threshold: 0.1  // 可选:当图片至少 10% 显示时开始加载
});// 观察所有懒加载图片
lazyLoadImages.forEach(image => {imageObserver.observe(image);
});

代码解释
IntersectionObserver:
创建 IntersectionObserver 实例来观察图片元素是否进入视口。IntersectionObserver 会异步监测指定元素与视口的交集变化。
entries 是一个包含所有监测元素的数组,entry.target 是当前进入视口的图片元素。
isIntersecting 属性表示图片是否已经进入视口(或者与视口重叠)。当该属性为 true 时,图片就进入了视口。
rootMargin:

rootMargin 是视口的扩展区域。当图片距离视口边缘一定距离时就触发加载。可以使用类似 CSS 的值(如 10px 0px)。
threshold:

threshold 定义了当多少比例的图片进入视口时触发懒加载,0.1 表示图片至少 10% 进入视口时触发加载。
image.onload:

一旦图片加载完毕,可以执行一些操作,比如移除懒加载样式(如 lazy 类),表示图片已成功加载。
observer.unobserve(image):

加载完图片后,停止观察该图片,优化性能。

使用 loading=“lazy” 属性

使用 loading=“lazy” 属性可以非常简单地实现图片的懒加载。浏览器就会在图片进入视口时自动加载它。这是原生浏览器对懒加载的支持,无需额外的 JavaScript 代码。这个属性已经被大多数现代浏览器支持。

<img src="image1.jpg" alt="Image 1" loading="lazy" />
<img src="image2.jpg" alt="Image 2" loading="lazy" />
<img src="image3.jpg" alt="Image 3" loading="lazy" />

4、不同分辨率下使用不同的图片

<picture><source media="(max-width: 600px)" srcset="image-small.jpg"><source media="(max-width: 1200px)" srcset="image-medium.jpg"><img src="image-large.jpg" alt="Responsive Image">
</picture>

或者

<img src="image-small.jpg" srcset="image-small.jpg 500w, image-medium.jpg 1000w, image-large.jpg 2000w" sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33vw" alt="Responsive Image">

5、使用webp格式的图片

使用 WebP 格式(如果浏览器支持)可以显著减小图片文件大小,从而提高加载速度。
可以通过 元素来根据浏览器支持选择图片格式。

<picture><source srcset="image.webp" type="image/webp"><img src="image.jpg" alt="Responsive Image">
</picture>

6、配置图片CDN

  1. 选择和设置 CDN 服务提供商
    首先,选择一个合适的 CDN 服务提供商。常见的 CDN 提供商包括:

Cloudflare
AWS CloudFront
Fastly
KeyCDN
Alibaba Cloud CDN
Tencent Cloud CDN

  1. 上传图片到 CDN
    选择图片存储方式:

存储在对象存储服务中:你可以使用云服务提供商的对象存储(如 Amazon S3、Alibaba OSS、腾讯云 COS)来存储图片文件,并通过 CDN 进行分发。通过这种方式,你可以确保文件安全,并允许 CDN 节点从这些存储服务获取资源。

直接通过 CDN 上传:有些 CDN 服务商允许直接将图片资源上传到其 CDN 网络。

上传图片:将图片上传到选定的存储服务(如 S3),并记录图片的 URL。

  1. 配置 CDN
    创建 CDN 加速域名:

登录你的 CDN 提供商控制台,创建一个加速域名(例如 cdn.yoursite.com)。
配置源站点(通常是你存储图片的服务器或对象存储服务)。源站点是 CDN 获取图片资源的地方。
设置缓存策略:

配置缓存时间(TTL,生存时间),指示 CDN 节点在没有更新时缓存图片的时间。一般情况下,静态资源(如图片)可以设置较长的缓存时间,如一周或一月。
启用 图片优化 功能(如果支持),以便根据设备类型和网络状况自动调整图片的大小和质量。
4. 修改图片 URL
在网页中引用 CDN 提供的图片 URL。假设你的 CDN 域名是 cdn.yoursite.com,你可以像这样引用图片:

<img src="https://cdn.yoursite.com/images/photo1.jpg" alt="Image 1" />
<img src="https://cdn.yoursite.com/images/photo2.jpg" alt="Image 2" />

将原本直接指向服务器的图片 URL 替换为指向 CDN 的图片 URL。

7、减少图片和动图的使用

这可能需要有较强的canvas功底,和较多的开发时间。但的确是能大幅度优化图片的方案。
能用css实现的简单动画,就别用动态图片。能用css实现的样式,就别用图片。

css样式如何优化?

1、关键css优先,非关键css等页面加载完成再加载或引入

在优化 CSS 加载时,遵循“先加载关键 CSS,再懒加载非关键 CSS”的策略,可以显著提升页面加载速度。

1、提取关键css
这就要分析一个页面的功能样式,是否可以分离为进入页面就要展示的css和等用户操作后才展示的css

<style>/* 关键 CSS */body { margin: 0; font-family: Arial, sans-serif; }header { background-color: #333; color: white; padding: 10px; }/* 添加更多关键样式 */
</style>

2、 懒加载非关键 CSS
如果页面有复杂特效(如动画、hover 状态、特定 JavaScript 动画等),可以将这些 CSS 动效代码延迟到页面加载完成后再应用,从而加快页面初始渲染速度。通过在 标签中添加 media=“print” 和 onload 事件来实现非阻塞加载。

<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">

3、使用 rel=“preload” 优化 CSS 加载
对于需要优先加载的非关键 CSS,可以用 preload 指令提前加载,提高资源加载效率。

<link rel="preload" href="important.css" as="style" onload="this.οnlοad=null; this.rel='stylesheet'">

除了上述处理非关键css,还可以使用js直接引入

window.addEventListener('load', function() {let link = document.createElement('link');link.rel = 'stylesheet';link.href = 'additional-styles.css';document.head.appendChild(link);
});

2、使用 CSS 预处理器和后处理器

预处理器如 SCSS、LESS 可以更简洁地编写和管理 CSS。
后处理器如 PostCSS 可以根据浏览器的兼容性要求,自动添加前缀、压缩代码、处理变量等。

3、利用 CSS 变量

使用 CSS 变量可以减少重复代码,便于动态调整样式。比如色彩、尺寸等样式都可以用 CSS 变量来定义,从而减少代码量并优化可维护性。

:root {--main-color: #4CAF50;--padding: 10px;
}body {color: var(--main-color);padding: var(--padding);
}

4、减少和优化选择器的复杂性

尽量使用简单的选择器,避免使用深层嵌套或复杂选择器。深层嵌套和通配符(如 *)会增加浏览器的解析成本。

5、删除无用的 CSS

使用工具如 PurgeCSS 或 UnCSS 来移除未使用的 CSS 代码。这样可以极大地减少 CSS 文件体积,提高加载速度。

6、利用缓存

为 CSS 文件设置长缓存时间。通过配置缓存策略,浏览器可以在多次访问时直接加载缓存中的 CSS 文件,避免重新请求 (前端的缓存策略,无非就是 Localstorage,service work)

7、编写代码时尽量减少重排和重绘

尽量避免频繁修改布局属性(如 width、height、padding),减少重绘和重排。可以使用 transform、opacity 等性能友好的属性,进行页面更新。
transform 调用的GPU来实现渲染 ,减少使用translate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/59952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot实现多数据源连接和切换

文章目录 前言一、多数据源配置与切换方案二、实现步骤1. 创建多个 DataSource 配置类2. 创建 DataSource 配置类3. 创建动态数据源路由类4. 实现 DynamicDataSource 类5. 创建 DataSourceContextHolder 来存储当前的数据源标识6. AOP 方式切换数据源7. 自定义注解来指定数据源…

【023】基于51单片机数字电压表

☆、设计硬件组成&#xff1a;51单片机最小系统ADC0832模数转换LCD1602液晶显示。 1、本设计采用STC89C51/52、AT89C51/52、AT89S51/52单片机作为主控芯片&#xff1b; 2、采用LCD1602液晶显示屏实时更新显示所测量的电压值&#xff1b; 3、采用ADC0832进行采集电压信号&…

ElasticSearch从环境搭建到如何使用的全过程

ES是什么? ES是一款非常强大的开源的高扩展的分布式全文检索引擎,可以帮助我们从海量数据中快速找到需要的内容,它可以近乎实时的存储、检索数据。还可以实现日志统计、分析、系统监控等功能。 例如京东、淘宝、头条等站内搜索功能 在大数据环境下&#xff0c;Elasticsearc…

SpringCloud框架学习(第一部分:初始项目搭建)

目录 一、SpringBoot和SpringCloud版本选型 1.Springcloud版本选择 2.Springcloud版本选择 3.Springcloud Alibaba版本选择 4.SpringCloud VS SpringBoot VS SpringCloud Alibaba版本三者制约对应关系 二、SpringCloud介绍 1.单体架构 2.微服务架构 3.springcloud 4.S…

uni-app打包后报错云服务空间未关联

使用uni-app打包到h5 项目里面用到了uni-app的云端一体城市选择组件&#xff0c;这个组件数据用到了uniCloud云服务空间&#xff0c;在本地运行没问题&#xff0c;打包之后测试环境报错&#xff1a; 一顿查&#xff0c;查到了官网是这样说的&#xff1a; cli publish --platfo…

解决Mac M芯片 Wireshark 运行rvictl -s 后,出现Starting device failed

前言 mac os big sur 之后&#xff0c;苹果系统的安全性能提升&#xff0c;导致 rvictl -s 创建虚拟网卡失败。 $ rvictl -s 000348120-001621w21184C01E bootstrap_look_up(): 1102Starting device 000348120-001621w21184C01E [FAILED] 这是由于 rvictl 需要开启系统扩展才能…

公共命名空间:内置名

使用方言[Perl] 使用[哇哇小可爱的方言] 第一句明确指出了使用什么&#xff0c;使用方言&#xff1b; 第二句也是使用方言的意思。 如果中括号里的内容&#xff0c;完全当做参数来处理&#xff0c;那么&#xff0c;第二句就难以确定使用什么。这里需要使用叫做“内置名”的技术…

浙江酒店WIFI广告路由实现——酒店经营

像这样的链接WIFI&#xff0c;后自动弹出连接认证&#xff0c;或者广告&#xff0c;可以展示酒店介绍&#xff0c;住房信息 智能wifi优点&#xff1a; 对于酒店体验而言&#xff1a; 1. 便捷性&#xff1a;客人无需繁琐的认证步骤就能自动连接 WiFi&#xff0c;提升了入住的便…

音视频入门基础:H.264专题(22)——通过FFprobe显示H.264裸流每个packet的信息

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…

JavaScript中执行上下文和执行栈是什么?

一、执行上下文 简单的来说&#xff0c;执行上下文是一种对Javascript代码执行环境的抽象概念&#xff0c;也就是说只要有Javascript代码运行&#xff0c;那么它就一定是运行在执行上下文中 执行上下文的类型分为三种&#xff1a; 全局执行上下文&#xff1a;只有一个&#…

达梦8-达梦数据实时同步软件(DMHS)配置-Oracle-DM8

1、安装环境 源端目的端IP地址192.168.6.111192.168.6.110系统版本Red Hat 6.4Kylin v10数据库版本Oracle11g达梦 v8系统用户Oracledmdba字符集MERICAN_AMERICA.AL32UTF8UTF-8端口15215236实例名PRODDMSERVER数据库软件目录/u01/app/oracle/opt/dmdbmsDMHS安装目录/u01/dmhs/o…

GEE代码学习 day18

13.4 计算图像集合的多个百分位图像 在此上下文中&#xff0c;您可以想象访问给定像素的给定 ImageCollection 中给定波段的所有值&#xff0c;并对它们进行排序。例如&#xff0c;第 30 个百分位数是列表中从最小到最大的 30% 的值。这提供了一种简单的方法&#xff0c;通过计…

【优选算法 — 滑动窗口】滑动窗口小专题(一)

长度最小的子数组 长度最小的子数组 题目解析&#xff1a; 对于示例一 对于剩下两种示例&#xff1a; 解法一&#xff1a;暴力枚举 把所有的子数组全部枚举出来&#xff0c;并且枚举出的每一个子数组求和判断&#xff0c;返回长度最小的子数组&#xff1b; 时间复杂度 &…

【数据集】【YOLO】【目标检测】安全帽识别数据集 22789 张,YOLO安全帽佩戴目标检测实战训练教程!

数据集介绍 【数据集】安全帽识别数据集 22789 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含2种分类&#xff1a;{0: head, 1: helmet}&#xff0c;分别是无安全帽和佩戴安全帽。数据集来自国内外图片网站和视频截图。检测场景为施工地工人安全帽佩…

【Pytorch】model.eval()与model.train()

model.train()&#xff1a; 作用是启用Batch Normalization 和 Dropout 如果模型中有BN层(Batch Normalization&#xff09;和Dropout&#xff0c;需要在训练时添加model.train()。model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropout&#x…

Linux 系统结构

Linux系统一般有4个主要部分&#xff1a;内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构&#xff0c;它们使得用户可以运行程序、管理文件并使用系统。 1. linux内核 内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;它…

飞书 富文本(Markdown)

飞书机器人webhook支持Markdown格式&#xff0c;包括表格 表格 |Syntax | Description |\n|-------- | -------- |\n|Header | Title |\n|Paragraph | Text |参考 富文本&#xff08;Markdown&#xff09;

深入理解 Vue 3 中的 Props

深入理解 Vue 3 中的 Props Vue 3 引入了 Composition API 等新特性&#xff0c;组件的定义和使用也变得更为灵活。而在组件通信中&#xff0c;Props&#xff08;属性&#xff09;扮演了重要角色&#xff0c;帮助父组件向子组件传递数据&#xff0c;形成单向的数据流动&#x…

R语言实战——一些批量对地理数据进行操作的方法

各位朋友在进行数据处理时&#xff0c;当有多张栅格影像时&#xff0c;如果我们都要进行同一操作时&#xff0c;一张一张做很繁琐&#xff0c;用ArcGIS模型构建器是一种比较好的方法。当然&#xff0c;今天小编新学了R语言上面进行批量裁剪&#xff0c;一起来学习一下吧&#x…

【时间之外】IT人求职和创业应知【31】

目录 新闻一&#xff1a;2024年“秦创原沣东杯”陕西省科技工作者创新创业大赛颁奖仪式暨沣东新城机器人产业发展大会盛大启幕 新闻二&#xff1a;声网CEO赵斌&#xff1a;RTE将成为生成式AI时代AI Infra的关键部分 新闻三&#xff1a;“5G工业互联网”融合应用试点城市名单…