如何利用 JavaScript 中的 WebP/AVIF 等现代图片格式和 CSS will-change 属性进一步优化页面性能?

各位靓仔靓女,早上好!今天咱们来聊聊怎么让你的网页跑得更快,更丝滑,就像德芙巧克力一样!主题就是利用 JavaScript 中的 WebP/AVIF 等现代图片格式和 CSS will-change 属性来优化页面性能。

开场白:你的网页,卡了吗?

想象一下,你辛辛苦苦搭建的网站,内容丰富,设计精美,结果用户打开一看,加载半天,图片刷不出来,动画卡顿掉帧,用户体验直接拉胯,用户内心OS一定是: “什么垃圾网站,拜拜了您嘞!”

所以,性能优化是前端开发永恒的主题。今天咱们就来啃啃两块硬骨头:图片格式优化和 will-change 属性。

第一部分:现代图片格式:WebP/AVIF,让你的图片瘦身!

传统的 JPEG 和 PNG 格式虽然应用广泛,但它们在压缩率上已经达到了瓶颈。WebP 和 AVIF 这些现代图片格式,就像健身房里的私教,能帮你把图片“瘦身”,在保证画质的前提下,大幅减小文件体积,从而加快加载速度。

  • WebP:Google 出品的良心之作

    WebP 是一种由 Google 开发的图片格式,它同时支持有损压缩和无损压缩,并且在压缩率上优于 JPEG 和 PNG。通常情况下,WebP 图片比 JPEG 图片小 25%-34%,比 PNG 图片小 26%。

    • WebP 的优势:

      • 更小的文件体积:相同的画质,更小的体积。
      • 支持有损和无损压缩:灵活应对各种场景。
      • 支持动画:可以替代 GIF 动画,体积更小。
      • 浏览器兼容性良好:主流浏览器都支持。
    • WebP 的劣势:

      • 老版本浏览器不支持:需要做兼容性处理。
      • 编码/解码需要消耗 CPU 资源:但现在的设备性能都足够强悍,这点可以忽略不计。
    • 如何使用 WebP?

      1. 图片转换: 可以使用各种工具将 JPEG 或 PNG 图片转换为 WebP 格式。例如:

        • 在线转换工具:搜索 “JPEG to WebP” 或 “PNG to WebP” 可以找到很多在线转换工具。
        • 命令行工具:cwebp (WebP 官方提供的命令行工具)。

          cwebp input.jpg -o output.webp
      2. HTML 中的使用:

        <picture>
          <source srcset="image.webp" type="image/webp">
          <img src="image.jpg" alt="描述文字">
        </picture>

        这段代码使用了 <picture> 元素,它允许你为不同的浏览器提供不同的图片格式。如果浏览器支持 WebP 格式,它会加载 image.webp,否则会加载 image.jpg

      3. JavaScript 检测支持:

        function supportsWebp() {
          return new Promise(resolve => {
            const img = new Image();
            img.onload = () => resolve(img.width > 0 && img.height > 0);
            img.onerror = () => resolve(false);
            img.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEAWkAA/veff/0PP8bReAAAA';
          });
        }
        
        supportsWebp().then(supported => {
          if (supported) {
            console.log("浏览器支持 WebP");
            // 使用 WebP 图片
          } else {
            console.log("浏览器不支持 WebP");
            // 使用 JPEG/PNG 图片
          }
        });

        这个函数创建一个 Image 对象,并尝试加载一个小的 WebP 图片。如果加载成功,说明浏览器支持 WebP 格式。

  • AVIF:下一代图片格式的希望之星

    AVIF (AV1 Image File Format) 是一种基于 AV1 视频编码器的图片格式。它在压缩率上比 WebP 更胜一筹,尤其是在高压缩比的情况下,画质损失更小。

    • AVIF 的优势:

      • 更高的压缩率:相同的画质,更小的体积。
      • 更好的画质:在高压缩比下,画质损失更小。
      • 支持 HDR:可以更好地呈现高动态范围的图像。
    • AVIF 的劣势:

      • 浏览器兼容性不如 WebP:目前只有部分主流浏览器支持。
      • 编码/解码需要消耗更多 CPU 资源:对设备性能要求更高。
      • 编码速度较慢:转换 AVIF 图片需要更长的时间。
    • 如何使用 AVIF?

      1. 图片转换: 可以使用各种工具将 JPEG 或 PNG 图片转换为 AVIF 格式。例如:

        • 命令行工具:avifenc (libavif 提供的命令行工具)。

          avifenc input.jpg output.avif
      2. HTML 中的使用:

        <picture>
          <source srcset="image.avif" type="image/avif">
          <source srcset="image.webp" type="image/webp">
          <img src="image.jpg" alt="描述文字">
        </picture>

        这段代码使用了 <picture> 元素,它会按照顺序尝试加载 image.avifimage.webpimage.jpg,直到找到浏览器支持的格式。

      3. JavaScript 检测支持:

        function supportsAvif() {
          return new Promise(resolve => {
            const img = new Image();
            img.onload = () => resolve(img.width > 0 && img.height > 0);
            img.onerror = () => resolve(false);
            img.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxAAIAAAAAbWlhZgEAAAAAAW1tZGF0EgAKCBgAN1dpZAAAAFGZmQ=='
          });
        }
        
        supportsAvif().then(supported => {
          if (supported) {
            console.log("浏览器支持 AVIF");
            // 使用 AVIF 图片
          } else {
            console.log("浏览器不支持 AVIF");
            // 使用 WebP/JPEG/PNG 图片
          }
        });

        类似于WebP,检测逻辑相同。

  • 选择哪个?WebP vs AVIF

    特性 WebP AVIF
    压缩率 较高 更高
    画质 良好 更好
    兼容性 良好,主流浏览器都支持 较差,部分主流浏览器支持
    编码速度
    适用场景 对兼容性要求高,对体积要求适中的场景 对体积和画质要求极高,且不惧兼容性问题的场景

    我的建议:

    • 如果你的网站对兼容性要求很高,并且需要快速的编码速度,那么 WebP 是一个不错的选择。
    • 如果你的网站对体积和画质要求极高,并且可以接受兼容性问题,那么 AVIF 是更好的选择。
    • 可以同时使用 WebP 和 AVIF,并使用 <picture> 元素来提供兼容性支持。

第二部分:CSS will-change 属性:提前告诉浏览器,我要变身了!

CSS will-change 属性允许你提前通知浏览器,某个元素将会发生哪些变化,例如 transformopacityscroll-position 等。这样浏览器就可以提前做好优化准备,避免在动画或过渡开始时出现卡顿。

  • will-change 的原理:

    will-change 就像一个剧透,提前告诉浏览器:“注意了,这个元素一会儿要动了,你提前准备好!” 浏览器收到这个信号后,会:

    • 为该元素创建一个新的渲染层。
    • 分配更多的内存和 GPU 资源。

    这样,当元素发生变化时,浏览器就可以更快地进行渲染,从而提高性能。

  • will-change 的用法:

    .element {
      will-change: transform; /* 告诉浏览器,这个元素将会发生 transform 变化 */
    }
    
    .another-element {
      will-change: opacity, transform; /* 告诉浏览器,这个元素将会发生 opacity 和 transform 变化 */
    }
    
    .scrollable-element {
      will-change: scroll-position; /* 告诉浏览器,这个元素将会发生滚动 */
    }
    • will-change 的取值:

      • auto:默认值,浏览器自行决定是否优化。
      • scroll-position:表示元素的内容可能会发生滚动。
      • contents:表示元素的内容可能会发生变化。
      • transform:表示元素可能会发生 transform 变化(例如:translaterotatescale)。
      • opacity:表示元素可能会发生 opacity 变化。
      • topleftbottomright:表示元素的位置可能会发生变化。
      • custom-ident:自定义属性名。
  • will-change 的注意事项:

    • 不要滥用 will-change 滥用 will-change 会导致浏览器分配过多的资源,反而会降低性能。只在需要的时候才使用 will-change
    • 使用后及时移除 will-change 当元素不再需要优化时,应该及时移除 will-change 属性,释放资源。可以通过 JavaScript 来动态控制 will-change 属性。
    • will-change 不是万能的: will-change 只能优化一些特定的场景,例如动画和过渡。对于其他类型的性能问题,需要使用其他优化手段。
    • 注意层叠上下文: will-change会创建新的层叠上下文。这可能会影响元素的z-index表现。
  • will-change 的最佳实践:

    1. 在动画或过渡开始前添加 will-change

      const element = document.querySelector('.element');
      
      element.addEventListener('mouseover', () => {
        element.style.willChange = 'transform'; // 鼠标悬停时添加 will-change
        element.style.transform = 'translateX(100px)'; // 执行动画
      });
      
      element.addEventListener('mouseout', () => {
        element.style.willChange = 'auto'; // 鼠标移开时移除 will-change
        element.style.transform = 'translateX(0)'; // 恢复原状
      });
    2. 使用 JavaScript 动态控制 will-change

      function toggleWillChange(element, property, enable) {
        element.style.willChange = enable ? property : 'auto';
      }
      
      const element = document.querySelector('.element');
      
      // 启用 will-change: transform
      toggleWillChange(element, 'transform', true);
      
      // 执行动画
      
      // 禁用 will-change: transform
      toggleWillChange(element, 'transform', false);
    3. 避免对静态元素使用 will-change

      不要对没有动画或过渡的静态元素使用 will-change,这会浪费资源。

    4. will-change 结合 transform 和 opacity 的使用:

      .element {
        /* 告诉浏览器,这个元素将会发生 transform 和 opacity 变化 */
        will-change: transform, opacity;
        transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
      }
      
      .element:hover {
        transform: scale(1.2);
        opacity: 0.8;
      }
  • 一个完整的 will-change 优化案例:

    假设我们有一个卡片元素,当鼠标悬停在卡片上时,卡片会放大并改变透明度。

    HTML:

    <div class="card">
      <img src="image.jpg" alt="卡片图片">
      <div class="card-content">
        <h3>卡片标题</h3>
        <p>卡片内容</p>
      </div>
    </div>

    CSS (优化前):

    .card {
      width: 200px;
      height: 300px;
      border: 1px solid #ccc;
      transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
    }
    
    .card:hover {
      transform: scale(1.1);
      opacity: 0.8;
    }

    CSS (优化后):

    .card {
      width: 200px;
      height: 300px;
      border: 1px solid #ccc;
      will-change: transform, opacity; /* 提前告诉浏览器,这个元素将会发生 transform 和 opacity 变化 */
      transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
    }
    
    .card:hover {
      transform: scale(1.1);
      opacity: 0.8;
    }

    通过添加 will-change: transform, opacity;,浏览器可以提前为卡片元素分配更多的资源,从而使动画更加流畅。

总结:性能优化,永无止境!

今天我们学习了如何使用 WebP/AVIF 等现代图片格式来减小图片体积,以及如何使用 CSS will-change 属性来优化动画性能。但请记住,性能优化是一个持续的过程,需要不断地学习和实践。

以下是一些额外的建议:

  • 使用 CDN: 将你的静态资源(例如图片、CSS、JavaScript 文件)部署到 CDN 上,可以加快加载速度。
  • 压缩代码: 使用工具压缩你的 CSS 和 JavaScript 代码,可以减小文件体积。
  • 懒加载: 对于长页面,可以使用懒加载技术来延迟加载图片,提高首屏加载速度。
  • 代码分割: 将你的 JavaScript 代码分割成多个小文件,可以减少首次加载的代码量。
  • 使用 Chrome DevTools 进行性能分析: Chrome DevTools 提供了强大的性能分析工具,可以帮助你找到页面中的性能瓶颈。
  • 定期进行性能测试: 定期对你的网站进行性能测试,可以及时发现和解决性能问题。

记住,用户体验是第一位的。只有不断地优化你的网站性能,才能留住用户,赢得他们的喜爱。

希望今天的讲座对大家有所帮助! 谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注