跳到主要内容

图像和多媒体✅

图片优化策略?

答案

图片优化是提升网站性能和用户体验的关键策略,主要从格式选择、压缩处理、加载策略和现代技术四个维度进行。

图片格式选择

格式压缩算法透明度文件大小浏览器支持适用场景
JPEG有损压缩不支持全部照片、复杂图像
PNG无损压缩支持全部图标、简单图形
WebP有损/无损支持最小现代浏览器通用替代方案
AVIF先进压缩支持极小部分浏览器未来标准

压缩与构建优化

// Webpack 图片优化配置
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, // < 8KB 转 base64
name: '[name].[contenthash].[ext]',
outputPath: 'images/'
}
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: { quality: 80, progressive: true },
pngquant: { quality: [0.65, 0.8] },
webp: { quality: 75 }
}
}
]
}
]
}
}

现代加载策略

<!-- 1. 响应式图片 -->
<picture>
<source media="(min-width: 1200px)" srcset="large.webp" type="image/webp">
<source media="(min-width: 768px)" srcset="medium.webp" type="image/webp">
<img src="small.jpg" alt="响应式图片" loading="lazy">
</picture>

<!-- 2. 懒加载 -->
<img class="lazy" data-src="image.jpg" alt="懒加载图片">

<!-- 3. 预加载关键图片 -->
<link rel="preload" as="image" href="hero-image.jpg">

JavaScript 实现懒加载

// Intersection Observer 懒加载
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.classList.remove('lazy')
observer.unobserve(img)
}
})
})

document.querySelectorAll('.lazy').forEach(img => {
imageObserver.observe(img)
})

// 渐进式加载
function progressiveLoad (placeholder, highRes) {
const img = new Image()
img.onload = () => {
placeholder.src = highRes
placeholder.classList.add('loaded')
}
img.src = highRes
}

现代优化技术

/* CSS 优化 */
.image-container {
/* 内容可见性优化 */
content-visibility: auto;
contain-intrinsic-size: 300px 200px;
}

.lazy-image {
/* 平滑过渡效果 */
opacity: 0;
transition: opacity 0.3s;
}

.lazy-image.loaded {
opacity: 1;
}

/* 响应式图片优化 */
.responsive-image {
width: 100%;
height: auto;
object-fit: cover;
}

实际开发建议

  • 格式优先级 WebP > JPEG > PNG,提供 fallback
  • 尺寸控制 根据显示尺寸提供合适的图片大小
  • CDN 加速 使用 CDN 分发图片资源
  • 缓存策略 设置合理的缓存头,启用浏览器缓存
  • 监控优化 使用 Core Web Vitals 监控图片加载性能
提示

优化顺序:选择合适格式 > 压缩处理 > 懒加载实现 > 响应式适配 > 性能监控

延伸阅读

图片懒加载原理?

答案

图片懒加载是一种性能优化技术,通过延迟加载视口外的图片来减少初始页面加载时间和带宽消耗。

核心原理

懒加载的核心思想是将图片的真实URL存储在自定义属性中(如 data-src),当图片进入或即将进入视口时,再将URL赋值给 src 属性触发加载。

实现方式对比

方式优势劣势适用场景
Intersection Observer性能优异,异步处理兼容性稍差(IE不支持)现代浏览器项目
滚动监听兼容性好频繁触发影响性能需要兼容老浏览器
原生 loading="lazy"零代码实现兼容性有限,功能简单简单场景快速实现

Intersection Observer 实现

// 现代化的懒加载实现
class LazyImageLoader {
constructor (options = {}) {
this.options = {
rootMargin: '50px',
threshold: 0.1,
...options
}
this.observer = this.createObserver()
}

createObserver () {
return new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target)
this.observer.unobserve(entry.target)
}
})
}, this.options)
}

loadImage (img) {
const src = img.dataset.src
if (src) {
img.src = src
img.classList.remove('lazy')
img.classList.add('loaded')
}
}

observe (selector = '.lazy') {
document.querySelectorAll(selector).forEach(img => {
this.observer.observe(img)
})
}
}

// 使用示例
const lazyLoader = new LazyImageLoader({
rootMargin: '100px' // 提前100px加载
})
lazyLoader.observe()

滚动监听实现(兼容性方案)

// 防抖优化的滚动监听
function createLazyLoader () {
let timeout

function checkImages () {
const images = document.querySelectorAll('.lazy')
const windowHeight = window.innerHeight
const scrollTop = window.pageYOffset

images.forEach(img => {
const rect = img.getBoundingClientRect()
// 提前200px开始加载
if (rect.top <= windowHeight + 200) {
img.src = img.dataset.src
img.classList.remove('lazy')
}
})
}

function handleScroll () {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(checkImages, 100)
}

window.addEventListener('scroll', handleScroll)
checkImages() // 初始检查
}

createLazyLoader()

HTML 结构优化

<!-- 占位符优化,避免布局抖动 -->
<div class="image-wrapper" style="aspect-ratio: 16/9;">
<img
class="lazy"
data-src="high-quality.jpg"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3C/svg%3E"
alt="图片描述"
loading="lazy"
>
</div>

<!-- 渐进式加载 -->
<img
class="lazy progressive"
data-src="full-resolution.jpg"
src="low-quality-placeholder.jpg"
alt="渐进式加载图片"
>

CSS 增强效果

.lazy {
opacity: 0;
transition: opacity 0.3s;
}

.lazy.loaded {
opacity: 1;
}

/* 加载动画效果 */
.image-wrapper {
position: relative;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}

@keyframes loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}

性能优化建议

  • 预加载距离 设置合理的 rootMargin 值,平衡用户体验和性能
  • 图片优化 结合响应式图片和现代格式(WebP、AVIF)
  • 占位符设计 使用固定宽高比避免布局抖动
  • 错误处理 添加图片加载失败的降级方案
提示

推荐使用 Intersection Observer API,它在主线程之外异步执行,不会阻塞页面渲染,性能更优。

延伸阅读

请解释什么是精灵图(css sprites),以及如何实现?

答案

核心概念

精灵图(CSS Sprites)是一种网页图片应用处理方式,它允许将一个页面涉及到的所有零星图片都包含到一张大图中去,然后通过 CSS 的 background-imagebackground-repeatbackground-position 的组合进行背景定位,访问页面时避免图片载入缓慢的现象。

实现原理

精灵图的核心思想是将多个小图片合并成一张大图片,然后通过 CSS 的 background-position 属性来显示图片的特定部分,从而减少 HTTP 请求数量,提高页面加载速度。

实现方法

  1. **准备精灵图
  2. **:将多个小图标合并成一张大图片
  3. 设置容器:为每个需要显示图标的位置创建一个容器元素
  4. 应用背景:使用 background-image 设置精灵图
  5. 定位显示:使用 background-position 定位到具体图标位置

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 精灵图演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .sprite-demo {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .icon {
            display: inline-block;
            width: 32px;
            height: 32px;
            margin: 10px;
            background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiBmaWxsPSIjRkY2QjZCIi8+CjxyZWN0IHg9IjMyIiB5PSIzMiIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSIjNENDRENDIi8+CjxyZWN0IHg9IjY0IiB5PSI2NCIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSIjNDVCN0QxIi8+CjxyZWN0IHg9IjMyIiB5PSI2NCIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSIjOTZDRUI0Ii8+Cjwvc3ZnPgo=');
            background-repeat: no-repeat;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        
        .icon-home {
            background-position: 0 0;
        }
        
        .icon-user {
            background-position: -32px 0;
        }
        
        .icon-settings {
            background-position: -64px 0;
        }
        
        .icon-search {
            background-position: -96px 0;
        }
        
        .icon-heart {
            background-position: 0 -32px;
        }
        
        .icon-star {
            background-position: -32px -32px;
        }
        
        .icon-bell {
            background-position: -64px -32px;
        }
        
        .icon-mail {
            background-position: -96px -32px;
        }
        
        .sprite-explanation {
            background: #e8f4fd;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
        }
        
        .code-block {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            margin: 10px 0;
            overflow-x: auto;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .benefits {
            background: #fff3cd;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
        }
        
        .benefits h3 {
            margin-top: 0;
            color: #856404;
        }
        
        .benefits ul {
            margin: 10px 0;
        }
        
        .benefits li {
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CSS 精灵图(Sprites)演示</h1>
        
        <div class="sprite-explanation">
            <h3>什么是精灵图?</h3>
            <p>精灵图是一种网页图片应用处理方式,将多个小图标合并成一张大图片,通过 CSS 的 <code>background-position</code> 来显示特定部分,从而减少 HTTP 请求数量。</p>
        </div>
        
        <div class="sprite-demo">
            <h2>精灵图效果演示</h2>
            <p>以下图标都来自同一张精灵图,通过不同的 <code>background-position</code> 显示不同图标:</p>
            
            <div>
                <span class="icon icon-home" title="首页"></span>
                <span class="icon icon-user" title="用户"></span>
                <span class="icon icon-settings" title="设置"></span>
                <span class="icon icon-search" title="搜索"></span>
                <span class="icon icon-heart" title="喜欢"></span>
                <span class="icon icon-star" title="星标"></span>
                <span class="icon icon-bell" title="通知"></span>
                <span class="icon icon-mail" title="邮件"></span>
            </div>
        </div>
        
        <div class="code-block">
            <h3>CSS 实现代码:</h3>
            <pre><code>.icon {
  display: inline-block;
  width: 32px;
  height: 32px;
  background-image: url('sprite.png');
  background-repeat: no-repeat;
}

.icon-home {
  background-position: 0 0;
}

.icon-user {
  background-position: -32px 0;
}

.icon-settings {
  background-position: -64px 0;
}</code></pre>
        </div>
        
        <div class="benefits">
            <h3>精灵图的优势:</h3>
            <ul>
                <li><strong>减少 HTTP 请求</strong>:多个图片合并为一张,减少网络请求次数</li>
                <li><strong>提高加载速度</strong>:减少请求次数,提升页面加载性能</li>
                <li><strong>减少图片体积</strong>:合并后的图片通常比多个小图片的总体积更小</li>
                <li><strong>便于维护</strong>:统一管理图标资源</li>
            </ul>
        </div>
        
        <div class="sprite-explanation">
            <h3>注意事项:</h3>
            <ul>
                <li>精灵图不宜过大,建议控制在 200KB 以内</li>
                <li>需要精确计算每个图标的位置坐标</li>
                <li>适合图标类图片,不适合大图片</li>
                <li>现代开发中可以考虑使用 SVG 图标或字体图标作为替代方案</li>
            </ul>
        </div>
    </div>
</body>
</html>

Open browser consoleTests

优势

  • 减少 HTTP 请求:多个图片合并为一张,减少网络请求
  • 提高加载速度:减少请求次数,提升页面加载性能
  • 减少图片体积:合并后的图片通常比多个小图片的总体积更小
  • 便于维护:统一管理图标资源

注意事项

  • 精灵图不宜过大,建议控制在 200KB 以内
  • 需要精确计算每个图标的位置坐标
  • 适合图标类图片,不适合大图片
  • 现代开发中可以考虑使用 SVG 图标或字体图标作为替代方案

面试官视角

该题考察对前端性能优化的理解,是前端开发中的重要知识点。面试官通过此题可以了解候选人对网页性能优化的掌握程度。

延伸阅读