网页中的 loading 效果(加载动画)是一个非常常见且重要的用户体验元素,它的主要目的是在内容(如图片、数据、页面)完全加载完成前,给用户一个明确的反馈,告诉系统正在“努力工作”,从而减少用户的焦虑感,并营造一种专业和流畅的体验。

(图片来源网络,侵删)
下面我将从 原理、实现方式、最佳实践 三个方面,详细为你讲解网页中的 loading 是怎么做的。
核心原理:控制可见性的时机
所有 loading 效果的核心原理都是的显示时机。
- 显示 Loading 动画:在页面或内容开始加载的瞬间,立即显示一个 loading 动画。
- 隐藏 Loading 动画:在页面或内容完全加载完毕后,隐藏 loading 动画,并展示实际内容。
这个过程可以通过监听不同的事件来实现,具体取决于你要加载的是什么。
常见的实现方式
根据加载对象的不同,实现 loading 效果的方式也多种多样。

(图片来源网络,侵删)
整页面加载
这是最基础的一种,用于页面从服务器获取 HTML 并完全渲染的过程。
- 实现原理:监听
window对象的load事件。load事件在整个页面及其所有资源(如图片、CSS、JS 文件)都加载完毕后触发。 - 如何实现:
- 在
<body>标签开始处,放置一个全屏的 loading 动画遮罩层,并设置其z-index确保在最上层。 - 给这个遮罩层一个初始的
display: block;或opacity: 1;。 - 在
<script>标签中,监听window.onload事件,在事件触发后将遮罩层隐藏(display: none;或opacity: 0;)。
- 在
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">Page Loading</title>
<style>
/* Loading 遮罩层样式 */
.page-loader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff; /* 背景色,与页面背景一致 */
display: flex;
justify-content: center;
align-items: center;
z-index: 9999; /* 确保在最上层 */
transition: opacity 0.5s ease-out; /* 添加淡出效果 */
}
.page-loader.hidden {
opacity: 0;
pointer-events: none; /* 隐藏后不可交互 */
}
/* 简单的旋转动画 */
.spinner {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<!-- Loading 遮罩层 -->
<div class="page-loader" id="pageLoader">
<div class="spinner"></div>
</div>
<!-- 页面实际内容 -->
<h1>欢迎来到我的网站!</h1>
<p>这里有很多内容...</p>
<img src="https://via.placeholder.com/150" alt="Placeholder Image">
<script>
// 监听整个页面的 load 事件
window.addEventListener('load', function() {
// 页面加载完成后,隐藏 loader
const loader = document.getElementById('pageLoader');
loader.classList.add('hidden');
});
</script>
</body>
</html>
加载 (AJAX/Fetch)
这是现代 Web 开发中最常见的方式,例如点击“加载更多”按钮、从服务器获取数据并渲染到页面上。
- 实现原理:
- 用户触发一个操作(如点击按钮)。
- 显示 loading 动画(通常是一个图标或文字)。
- 使用
fetch或XMLHttpRequest发送异步请求。 - 在请求的
then(或onload) 回调中,处理返回的数据并渲染到页面上。 - 在
finally(或onload/onerror) 回调中,无论成功失败,都隐藏 loading 动画。
示例代码 (使用 Fetch API):

(图片来源网络,侵删)
<button id="loadDataBtn">加载数据</button>
<div id="dataContainer"></div>
<div id="ajaxLoader" style="display: none;">加载中...</div>
<script>
const loadBtn = document.getElementById('loadDataBtn');
const dataContainer = document.getElementById('dataContainer');
const ajaxLoader = document.getElementById('ajaxLoader');
loadBtn.addEventListener('click', function() {
// 1. 显示 loading
ajaxLoader.style.display = 'block';
dataContainer.innerHTML = ''; // 清空旧数据
// 2. 发起异步请求
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(data => {
// 3. 请求成功,渲染数据
dataContainer.innerHTML = `<h2>${data.title}</h2><p>${data.body}</p>`;
})
.catch(error => {
console.error('请求失败:', error);
dataContainer.innerHTML = '<p>加载失败,请重试。</p>';
})
.finally(() => {
// 4. 无论成功失败,都隐藏 loading
ajaxLoader.style.display = 'none';
});
});
</script>
图片懒加载
对于包含大量图片的页面,懒加载可以显著提升初始加载速度,loading 效果通常用在图片即将进入视口时。
- 实现原理:
- 在
<img>标签中,不直接设置src属性,而是设置一个占位图或背景色到src,并将真实图片的 URL 存放在data-src属性中。 - 使用
IntersectionObserverAPI 来检测图片元素是否进入用户的可视区域(Viewport)。 - 当图片进入视口时,将
data-src的值赋给src属性,浏览器开始加载图片。 - 在图片加载过程中,可以显示一个 loading 动画(一个灰色背景或骨架屏)。
- 在
示例代码:
<style>
.lazy-img {
width: 300px;
height: 200px;
background-color: #f0f0f0; /* 占位背景色 */
display: block;
}
</style>
<img class="lazy-img" data-src="https://picsum.photos/300/200?random=1" alt="Lazy Image 1">
<img class="lazy-img" data-src="https://picsum.photos/300/200?random=2" alt="Lazy Image 2">
<img class="lazy-img" data-src="https://picsum.photos/300/200?random=3" alt="Lazy Image 3">
<script>
document.addEventListener("DOMContentLoaded", function() {
const lazyImages = document.querySelectorAll('img.lazy-img');
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// 如果图片进入视口
if (entry.isIntersecting) {
const img = entry.target;
const src = img.getAttribute('data-src');
// 设置 src 开始加载
img.src = src;
img.classList.remove('lazy-img'); // 移除占位样式类
// 图片加载完成后,停止观察
img.onload = () => {
observer.unobserve(img);
};
}
});
});
// 开始观察所有懒加载图片
lazyImages.forEach(img => {
imageObserver.observe(img);
});
} else {
// 降级处理:对于不支持 IntersectionObserver 的浏览器
// 可以使用 scroll 事件监听等方式
console.log("浏览器不支持 IntersectionObserver");
}
});
</script>
Loading 动画的类型和最佳实践
Loading 效果本身也有很多种形式,选择合适的类型至关重要。
常见的动画类型
- 旋转加载器:最经典、最通用的类型,适用于大多数场景。
- 骨架屏加载完成前,先显示一个与最终布局相似的灰色占位框,这能给用户一个很好的预期,感知到内容的结构和加载进度,常用于新闻列表、商品列表等。
- 进度条:当可以预估加载时间时(如文件上传、视频缓冲),进度条是最佳选择,因为它能提供最明确的进度反馈。
- 涟漪/脉冲效果:更现代、更轻量的设计,通常用于按钮点击或小模块的加载反馈。
- 自定义动画:结合品牌特色的有趣动画,能提升品牌记忆点,但要注意不要过于花哨分散用户注意力。
最佳实践
- 明确告知用户:Loading 动画必须清晰可见,让用户一眼就知道系统正在响应。
- 提供反馈:除了动画,文字提示如“加载中...”、“正在保存...”也非常有效。
- 控制时长:如果加载时间超过几秒钟,考虑提供取消操作的选项或更详细的进度说明。
- 不要滥用:只在真正需要等待的时候显示,对于瞬间就能完成的后台操作,可能不需要 loading 动画。
- 性能优化:Loading 动画本身不能成为性能瓶颈,避免使用过于复杂的 CSS 动画或大量 JavaScript 计算,尤其是在页面首次加载时。
- 无障碍性:为 loading 状态添加 ARIA 属性,如
aria-live="polite",以便屏幕阅读器可以通知视障用户内容正在更新。
网页中的 loading 效果是一个系统工程,它结合了 HTML 结构、CSS 样式/动画 和 JavaScript 逻辑。
- 原理:通过控制内容的显示与隐藏来管理用户预期。
- 实现:根据加载对象(整页面、异步数据、图片)选择不同的事件监听方法(
window.onload,fetch().finally(),IntersectionObserver)。 - 设计:根据场景选择合适的动画类型(旋转器、骨架屏、进度条),并遵循最佳实践,以提供最佳的用户体验。
