这是为您生成的图片自适应优化脚本,它利用现代浏览器的能力,根据设备屏幕尺寸和分辨率智能加载最合适的图片版本,从而提升页面加载速度和显示效果。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">🖼️ 智能图片自适应优化</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
background: #f4f6f9;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 2rem 1rem;
}
.container {
max-width: 1100px;
width: 100%;
background: white;
border-radius: 2rem;
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.1);
padding: 2rem 2rem 2.5rem;
transition: all 0.2s;
}
h1 {
font-weight: 600;
font-size: 1.9rem;
letter-spacing: -0.02em;
color: #0b1a2e;
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 0.25rem;
flex-wrap: wrap;
}
h1 small {
font-weight: 400;
font-size: 1rem;
color: #4a5b6e;
background: #eef2f6;
padding: 0.2rem 0.9rem;
border-radius: 40px;
letter-spacing: 0.3px;
}
.sub {
color: #3f4e62;
margin-bottom: 2rem;
border-left: 4px solid #3b82f6;
padding-left: 1rem;
font-weight: 400;
background: #f9fafc;
border-radius: 0 12px 12px 0;
line-height: 1.6;
}
/* 演示网格 */
.demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 2rem 1.5rem;
margin: 2rem 0 1rem;
}
.card {
background: #ffffff;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 8px 20px rgba(0,0,0,0.02);
transition: transform 0.15s ease, box-shadow 0.2s;
border: 1px solid #eef2f6;
}
.card:hover {
transform: translateY(-3px);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.04);
}
.card-image {
width: 100%;
background: #e6edf4;
position: relative;
overflow: hidden;
}
.card-image img {
display: block;
width: 100%;
height: auto;
object-fit: cover;
aspect-ratio: 16 / 10; /* 统一比例,演示自适应 */
background: #eef2f7;
transition: opacity 0.35s ease, filter 0.2s;
}
/* 模糊占位效果 (可选) */
img[data-src] {
filter: blur(6px);
opacity: 0.8;
transform: scale(1.02);
}
img.loaded {
filter: blur(0);
opacity: 1;
transform: scale(1);
}
.card-body {
padding: 1rem 1.2rem 1.4rem;
}
.card-title {
font-weight: 600;
font-size: 1.2rem;
margin-bottom: 6px;
color: #11212e;
}
.card-desc {
font-size: 0.9rem;
color: #4f5e6e;
line-height: 1.5;
display: flex;
justify-content: space-between;
align-items: center;
}
.badge {
background: #dbeafe;
color: #1e4b8c;
font-size: 0.7rem;
padding: 0.25rem 0.9rem;
border-radius: 20px;
font-weight: 500;
letter-spacing: 0.3px;
}
.badge.green {
background: #d1fae5;
color: #0b5e3c;
}
.info-panel {
background: #f1f5f9;
border-radius: 18px;
padding: 1.25rem 1.8rem;
margin-top: 2.2rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1rem 1.5rem;
font-size: 0.95rem;
border: 1px solid #e0e8f0;
}
.info-item {
display: flex;
align-items: baseline;
gap: 6px;
flex-wrap: wrap;
}
.info-item span:first-child {
color: #455a6e;
font-weight: 450;
}
.info-item .value {
background: white;
padding: 0.1rem 0.9rem;
border-radius: 40px;
font-weight: 500;
color: #0b1f33;
border: 1px solid #dae2ec;
}
#refreshInfo {
background: #ffffff;
border: 1px solid #ced8e4;
padding: 0.5rem 1.4rem;
border-radius: 40px;
font-weight: 500;
color: #1e2c41;
cursor: pointer;
transition: 0.15s;
font-size: 0.9rem;
display: inline-flex;
align-items: center;
gap: 6px;
}
#refreshInfo:hover {
background: #e8edf5;
border-color: #9aaec7;
}
.footnote {
text-align: center;
margin-top: 1.8rem;
color: #64748b;
font-size: 0.85rem;
border-top: 1px solid #e9edf3;
padding-top: 1.8rem;
}
@media (max-width: 600px) {
.container { padding: 1.5rem; }
h1 { font-size: 1.5rem; }
.info-panel { flex-direction: column; align-items: stretch; }
}
</style>
</head>
<body>
<div class="container">
<h1>
📐 图片自适应优化
<small>srcset + 尺寸感知</small>
</h1>
<div class="sub">
⚡ 基于屏幕宽度 & 像素比 · 自动加载最适合的图片 · 支持延迟加载
</div>
<!-- 图片展示网格 -->
<div class="demo-grid" id="imageGrid">
<!-- 卡片 1 : 山川 -->
<div class="card">
<div class="card-image">
<img class="optimized-img"
data-src="https://picsum.photos/seed/landscape/600/375"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='375' viewBox='0 0 600 375'%3E%3Crect fill='%23d9e2ec' width='600' height='375'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%2370849c' font-size='18' font-family='sans-serif'%3E加载中…%3C/text%3E%3C/svg%3E"
alt="自适应山川图片"
loading="lazy"
width="600" height="375">
</div>
<div class="card-body">
<div class="card-title">🏔️ 山脉</div>
<div class="card-desc">
<span>分辨率感知</span>
<span class="badge">16:10</span>
</div>
</div>
</div>
<!-- 卡片 2 : 城市 -->
<div class="card">
<div class="card-image">
<img class="optimized-img"
data-src="https://picsum.photos/seed/city/600/375"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='375' viewBox='0 0 600 375'%3E%3Crect fill='%23cbd5e1' width='600' height='375'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%235f748c' font-size='18' font-family='sans-serif'%3E加载…%3C/text%3E%3C/svg%3E"
alt="自适应城市图片"
loading="lazy"
width="600" height="375">
</div>
<div class="card-body">
<div class="card-title">🌆 城市夜景</div>
<div class="card-desc">
<span>DPR 适配</span>
<span class="badge green">自动</span>
</div>
</div>
</div>
<!-- 卡片 3 : 海洋 -->
<div class="card">
<div class="card-image">
<img class="optimized-img"
data-src="https://picsum.photos/seed/ocean/600/375"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='375' viewBox='0 0 600 375'%3E%3Crect fill='%23b9cadc' width='600' height='375'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%233f5a77' font-size='18' font-family='sans-serif'%3E加载…%3C/text%3E%3C/svg%3E"
alt="自适应海洋图片"
loading="lazy"
width="600" height="375">
</div>
<div class="card-body">
<div class="card-title">🌊 海洋</div>
<div class="card-desc">
<span>智能尺寸</span>
<span class="badge">webp 优先</span>
</div>
</div>
</div>
</div>
<!-- 实时信息面板 -->
<div class="info-panel" id="infoPanel">
<div class="info-item">
<span>📺 视口宽度</span>
<span class="value" id="viewportWidth">—</span>
</div>
<div class="info-item">
<span>🔍 像素比 (DPR)</span>
<span class="value" id="devicePixelRatio">—</span>
</div>
<div class="info-item">
<span>🖼️ 加载尺寸</span>
<span class="value" id="loadedResolution">—</span>
</div>
<button id="refreshInfo" aria-label="刷新信息">⟳ 重新检测</button>
</div>
<div class="footnote">
⚡ 图片使用 <strong>srcset</strong> + <strong>sizes</strong> 自适应,根据设备宽度与 DPR 加载最适合版本。<br>
支持延迟加载 (loading="lazy") 及模糊占位过渡。
</div>
</div>
<script>
(function() {
"use strict";
// ----- 核心:自适应图片优化脚本 -----
// 原理:为每个图片生成 srcset (多分辨率) + sizes,并根据屏幕宽度/DPR 加载最佳图片
// 同时支持渐进增强、占位模糊效果
// 工具:获取设备像素比 (至少 1)
const dpr = window.devicePixelRatio || 1;
// 更新信息面板
function updateInfo() {
const vw = window.innerWidth;
document.getElementById('viewportWidth').textContent = vw + 'px';
document.getElementById('devicePixelRatio').textContent = dpr.toFixed(1) + 'x';
// 显示已加载图片的实际尺寸 (取自最后一张加载完成的图片或取样)
const imgs = document.querySelectorAll('.optimized-img');
let loadedCount = 0;
let lastNatural = { width: '—', height: '—' };
imgs.forEach(img => {
if (img.complete && img.naturalWidth > 0) {
loadedCount++;
lastNatural = { width: img.naturalWidth, height: img.naturalHeight };
}
});
if (loadedCount > 0) {
document.getElementById('loadedResolution').textContent =
`${lastNatural.width} × ${lastNatural.height}`;
} else {
document.getElementById('loadedResolution').textContent = '等待加载…';
}
}
// ----- 生成响应式 srcset 和 sizes (核心优化) -----
function setupResponsiveImage(img) {
// 获取原始图片URL基础 (移除尺寸部分,以便生成多尺寸)
let src = img.getAttribute('data-src') || img.src;
// 如果是 picsum 类型的链接,我们提取种子,构建多尺寸
// 支持 picsum.photos 以及常规带尺寸的URL
let baseUrl = src;
// 针对 picsum 特殊处理: 从URL中解析种子和尺寸
// https://picsum.photos/seed/landscape/600/375
// 转换成多尺寸: 使用 ?random 或者构建 400, 800, 1200 版本
const picsumMatch = src.match(/^(https:\/\/picsum\.photos\/seed\/([^/]+))\/(\d+)\/(\d+)/i);
if (picsumMatch) {
const base = picsumMatch[1]; // https://picsum.photos/seed/landscape
const defaultW = picsumMatch[3];
const defaultH = picsumMatch[4];
// 生成多组分辨率 (宽度): 320, 640, 960, 1280, 1920,按比例保持高度
const widths = [320, 640, 960, 1280, 1920];
const ratio = defaultH / defaultW;
const srcsetParts = widths.map(w => {
const h = Math.round(w * ratio);
return `${base}/${w}/${h} ${w}w`;
}).join(', ');
img.setAttribute('srcset', srcsetParts);
// 设置 sizes 属性: 根据视口宽度决定加载哪张 (响应式)
// (max-width: 480px) 100vw, (max-width: 768px) 80vw, 50vw
// 这里简洁处理:如果屏幕<600用100vw,否则用50vw (实际根据布局)
img.setAttribute('sizes', '(max-width: 600px) 100vw, (max-width: 1024px) 50vw, 33vw');
// 默认 src 使用中等尺寸 (640×比例) 使初始加载不至于太大
const mediumW = 640;
const mediumH = Math.round(mediumW * ratio);
img.src = `${base}/${mediumW}/${mediumH}`;
// 同时更新 data-src 为原始大尺寸? 但我们已经用了srcset
// 保留原始大尺寸作为后备: 使用 1280w
img.setAttribute('data-fallback', `${base}/${1280}/${Math.round(1280 * ratio)}`);
} else {
// 对于其他图片 (非picsum),尝试从URL提取宽高并生成srcset
// 普通图片也可能是静态路径,我们默认添加2x 3x 基于尺寸
// 但此处为通用演示,如果图片不是picsum,则简单增加DPR srcset
// 大多数场景可使用 1x, 2x (基于原始尺寸)
const originalSrc = img.getAttribute('data-src') || img.src;
// 移除查询参数避免缓存
const cleanSrc = originalSrc.split('?')[0];
// 判断是否已有尺寸后缀,简单策略: 生成 @2x @3x (通过查询参数模拟)
// (真实的2x图片需服务器支持, 这里使用 ?dpr=2 模拟)
if (!cleanSrc.includes('picsum')) {
// 构造基于DPR的srcset (1x, 2x, 3x)
const src1x = cleanSrc;
const src2x = cleanSrc + (cleanSrc.includes('?') ? '&' : '?') + 'dpr=2';
const src3x = cleanSrc + (cleanSrc.includes('?') ? '&' : '?') + 'dpr=3';
img.setAttribute('srcset', `${src1x} 1x, ${src2x} 2x, ${src3x} 3x`);
// sizes 可以省略,使用x描述符时浏览器自动选择
} else {
// fallback 至少保留原始
img.setAttribute('srcset', `${cleanSrc} 1x`);
}
// 保留原始src
img.src = cleanSrc;
}
// 让浏览器应用srcset (部分浏览器需要重新触发)
// 强制重新解析srcset
if (img.srcset) {
img.offsetHeight; // 强制重绘
}
}
// ----- 模糊占位 → 加载完成后清除 -----
function handleImageLoad(img) {
img.classList.add('loaded');
// 移除模糊效果
img.style.filter = 'none';
// 更新信息面板 (取样)
updateInfo();
}
function handleImageError(img) {
// 如果加载失败,使用fallback
const fallback = img.getAttribute('data-fallback');
if (fallback && img.src !== fallback) {
img.src = fallback;
}
img.classList.add('loaded'); // 仍然移除模糊
img.style.filter = 'none';
}
// ----- 初始化所有图片 -----
function initImages() {
const images = document.querySelectorAll('.optimized-img');
images.forEach((img, index) => {
// 1. 应用响应式策略 (srcset, sizes)
setupResponsiveImage(img);
// 2. 绑定加载完成事件 (移除模糊)
// 如果已经加载完成则直接处理
if (img.complete && img.naturalWidth > 0) {
handleImageLoad(img);
} else {
// 移除之前绑定的监听避免重复
img.removeEventListener('load', onLoad);
img.removeEventListener('error', onError);
// 定义处理函数
const onLoad = () => handleImageLoad(img);
const onError = () => handleImageError(img);
img.addEventListener('load', onLoad, { once: true });
img.addEventListener('error', onError, { once: true });
}
// 3. 支持延迟加载: 如果浏览器不支持 loading=lazy,我们自己实现简单懒加载?
// 但现代浏览器都支持,使用原生 lazy,并加上 IntersectionObserver 作为降级 (可选)
if ('loading' in HTMLImageElement.prototype) {
img.setAttribute('loading', 'lazy');
} else {
// 极简懒加载 polyfill: 使用 IntersectionObserver
// 这里为了轻量,只做演示,不再额外实现
// 但为了效果,我们手动设置loading = lazy 已经支持大部分
}
});
// 首次信息更新
setTimeout(updateInfo, 200);
}
// ----- 窗口变化重新检测 (视口宽度) -----
let resizeTimer;
function handleResize() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
updateInfo();
}, 150);
}
// 刷新按钮
document.getElementById('refreshInfo').addEventListener('click', function(e) {
e.preventDefault();
updateInfo();
// 同时重新检查所有图片状态
const imgs = document.querySelectorAll('.optimized-img');
imgs.forEach(img => {
if (img.complete && img.naturalWidth > 0) {
handleImageLoad(img);
}
});
});
// ----- 启动 -----
document.addEventListener('DOMContentLoaded', function() {
initImages();
updateInfo();
window.addEventListener('resize', handleResize);
// 针对移动端旋转
window.addEventListener('orientationchange', function() {
setTimeout(updateInfo, 300);
});
});
// 如果DOM已加载完成 (脚本在底部,但以防万一)
if (document.readyState !== 'loading') {
initImages();
updateInfo();
window.addEventListener('resize', handleResize);
}
// 暴露一些信息用于调试
window.__imgOptimizer = { updateInfo, initImages };
})();
</script>
</body>
</html>
图片自适应机制说明
脚本通过组合多种现代Web技术,实现了图片的智能加载与显示,您可以把它理解为一位“图片管家”,它会在您浏览时,根据设备的实际情况,为您挑选最合适的图片。
- 分辨率与尺寸适配:脚本会读取您的屏幕宽度和像素比(DPR),并使用
srcset和sizes属性为图片生成多个版本(如320w、640w、1280w),浏览器会自动选择最匹配当前屏幕尺寸和分辨率的图片进行加载,避免加载过大或过小的图片。 - 加载性能优化:集成了延迟加载(
loading=“lazy”)特性,图片仅在即将进入可视区域时才开始加载,有效减少了初始页面的数据消耗,配合模糊占位图,在图片加载完成前会显示一个柔和过渡,避免了页面布局抖动,提升了用户体验。 - 状态监控与反馈:页面底部的信息面板会实时显示当前的视口宽度、设备像素比以及已加载图片的实际分辨率,您可以通过“重新检测”按钮手动刷新这些信息,直观地看到不同设备或窗口大小变化下的自适应效果。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播