Skip to content

body 元素 ​

<body> 元素是 HTML 文档中所有用户可见内容的容器。页面中显示的文字、图片、链接、表格、表单、音视频等所有内容,都必须放在 <body> 内部。

前置知识

阅读本节前,建议先了解:head 元素

基础概念 ​

body 的作用 ​

<body> 元素定义了 HTML 文档的内容区域。如果说 <head> 是文档的"幕后配置",那么 <body> 就是文档的"舞台"——所有用户能看到的、能交互的内容都在这里呈现。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>body 元素演示</title>
</head>
<body>
  <!-- 用户能看到的所有内容都在这里 -->
  <header>
    <h1>网站标题</h1>
    <nav>导航菜单</nav>
  </header>
  <main>
    <p>这是页面的主要内容区域。</p>
  </main>
  <footer>
    <p>页脚信息</p>
  </footer>
</body>
</html>

body 的层级关系 ​

Document
 └── html (根元素)
      ├── head (元信息)
      │    ├── meta
      │    ├── title
      │    └── link
      └── body (内容区域) ← 本节重点
           ├── header
           │    ├── h1
           │    └── nav
           ├── main
           │    ├── article
           │    ├── section
           │    └── aside
           └── footer

body 与 document.body ​

在 JavaScript 中,document.body 是访问 <body> 元素的快捷方式:

javascript
// 两种方式等价
var body1 = document.body;
var body2 = document.getElementsByTagName('body')[0];
var body3 = document.querySelector('body');

注意

如果脚本在 <head> 中同步执行(没有 defer 或 async),此时 document.body 可能为 null,因为 <body> 还未被解析。

语法 ​

基本语法 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>页面标题</title>
</head>
<body>
  <!-- 页面内容 -->
</body>
</html>

body 的全局属性 ​

<body> 元素除了支持所有 HTML 全局属性外,还支持以下专属的事件属性:

窗口事件属性 ​

属性说明触发时机
onload页面加载完成所有资源(图片、样式表、脚本等)加载完毕
onunload页面卸载用户离开页面时
onbeforeunload页面即将卸载在 unload 之前触发,可用于提示用户保存
onpageshow页面显示页面加载或从缓存中恢复时
onpagehide页面隐藏用户离开页面或页面被缓存时
onresize窗口大小改变浏览器窗口尺寸变化时
onscroll页面滚动用户滚动页面时
onerror加载错误资源加载失败时

表单事件属性 ​

属性说明
onfocus元素获得焦点
onblur元素失去焦点
onreset表单重置
onsubmit表单提交
onchange元素值改变
oninput用户输入时
onselect文本被选中
oninvalid表单验证失败

拖拽事件属性 ​

属性说明
ondrag元素被拖动
ondragstart拖动开始
ondragend拖动结束
ondragover拖过目标元素
ondragenter拖入目标元素
ondragleave拖离目标元素
ondrop在目标元素上放下
onscroll滚动事件

剪贴板事件属性 ​

属性说明
oncopy复制内容
oncut剪切内容
onpaste粘贴内容

键盘事件属性 ​

属性说明
onkeydown按下键盘按键
onkeypress按下字符键(已废弃)
onkeyup释放键盘按键

鼠标事件属性 ​

属性说明
onclick单击
ondblclick双击
onmousedown鼠标按下
onmouseup鼠标释放
onmouseover鼠标移入
onmousemove鼠标移动
onmouseout鼠标移出
onmouseenter鼠标进入(不冒泡)
onmouseleave鼠标离开(不冒泡)
onwheel滚轮滚动
oncontextmenu右键菜单

关于内联事件属性

虽然在 <body> 标签上使用事件属性(如 onload="init()")是合法的,但不推荐这种写法。推荐使用 JavaScript 的 addEventListener 方法来绑定事件,以实现关注点分离。

详细说明 ​

body 的默认样式 ​

浏览器为 <body> 元素提供了默认样式,不同浏览器的默认值略有差异:

css
/* 大多数浏览器的 body 默认样式 */
body {
  display: block;
  margin: 8px;          /* 浏览器默认有 8px 的外边距 */
  /* Chrome/Safari 的默认值 */
}

通常在开发中,我们会重置 body 的默认样式:

css
/* 常见的 CSS 重置 */
body {
  margin: 0;
  padding: 0;
  font-family: system-ui, -apple-system, sans-serif;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
}

body 的背景与前景 ​

<body> 元素是设置页面背景色和默认文字颜色的标准位置:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>body 背景</title>
  <style>
    /* 通过 CSS 设置 body 背景 */
    body {
      background-color: #f5f5f5;
      color: #333;
      background-image: url('background.jpg');
      background-size: cover;
      background-position: center;
      background-attachment: fixed;
      min-height: 100vh;
    }
  </style>
</head>
<body>
  <h1>页面内容</h1>
</body>
</html>

补充说明

根据 HTML 规范,如果 <body> 没有设置背景,浏览器会将 <html> 元素的背景应用到整个画布。但为了清晰和可预测性,建议直接在 <body> 上设置背景样式。

onload 事件详解 ​

onload 是 <body> 最常用的事件属性,它在页面所有资源加载完成后触发。

使用内联事件属性(不推荐) ​

html
<!-- 不推荐:内联事件处理器 -->
<body onload="init()">

使用 JavaScript addEventListener(推荐) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>onload 事件</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      max-width: 700px;
      margin: 40px auto;
      padding: 0 20px;
    }
  </style>
</head>
<body>
  <h1>页面加载事件</h1>
  <p id="status">加载中...</p>
  <img src="https://picsum.photos/800/400" alt="演示图片" id="demo-img">

  <script>
    // 推荐:使用 addEventListener
    window.addEventListener('load', function() {
      document.getElementById('status').textContent =
        '所有资源已加载完成!(包括图片)';
    });

    // DOMContentLoaded:DOM 解析完成即触发,不等待图片等资源
    document.addEventListener('DOMContentLoaded', function() {
      console.log('DOM 已解析完成,但图片可能还在加载。');
    });
  </script>
</body>
</html>

load 与 DOMContentLoaded 的区别 ​

特性loadDOMContentLoaded
触发时机所有资源加载完成(图片、CSS、JS、iframe)DOM 解析完成(不等待图片和样式表)
触发对象windowdocument
等待图片是否
等待 CSS是否(但同步脚本会阻塞解析)
等待 iframe是否
适用场景需要操作图片尺寸等依赖资源就绪的场景需要尽早操作 DOM 的场景
性能触发较晚触发较早
javascript
// load 事件:等待所有资源
window.addEventListener('load', function() {
  var img = document.getElementById('my-image');
  // 此时可以安全地获取图片的宽高
  console.log('图片宽度:', img.naturalWidth);
  console.log('图片高度:', img.naturalHeight);
});

// DOMContentLoaded 事件:DOM 解析完成
document.addEventListener('DOMContentLoaded', function() {
  // 此时 DOM 已可操作,但图片可能未加载
  var list = document.getElementById('user-list');
  // 可以安全地操作 DOM 元素
  list.innerHTML = '<li>用户 1</li><li>用户 2</li>';
});

body 中的内容组织 ​

<body> 内部通常按照语义化标签来组织内容:

html
<body>
  <!-- 页面头部 -->
  <header>
    <h1>网站名称</h1>
    <nav>
      <ul>
        <li><a href="/">首页</a></li>
        <li><a href="/about">关于</a></li>
        <li><a href="/contact">联系</a></li>
      </ul>
    </nav>
  </header>

  <!-- 主要内容 -->
  <main>
    <article>
      <h2>文章标题</h2>
      <p>文章内容...</p>
    </article>

    <aside>
      <h3>侧边栏</h3>
      <p>相关链接和推荐内容</p>
    </aside>
  </main>

  <!-- 页面底部 -->
  <footer>
    <p>&copy; 2024 网站名称. 保留所有权利。</p>
  </footer>
</body>

body 与 iframe ​

在 iframe 中,内部页面也有自己的 <body> 元素:

html
<!-- 父页面 -->
<body>
  <h1>父页面</h1>
  <iframe src="child.html" id="my-iframe"></iframe>

  <script>
    var iframe = document.getElementById('my-iframe');

    // 访问 iframe 内部的 body
    iframe.addEventListener('load', function() {
      var innerBody = iframe.contentDocument.body;
      innerBody.style.backgroundColor = '#ffffcc';
    });
  </script>
</body>

跨域限制

如果 iframe 加载的是跨域页面,由于同源策略限制,父页面无法访问 iframe 内部的 DOM。

实战示例 ​

页面加载进度指示器 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>加载进度指示器</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: system-ui, sans-serif;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background-color: #f8f9fa;
    }
    /* 加载遮罩 */
    #loading-overlay {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: white;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      z-index: 9999;
      transition: opacity 0.5s ease;
    }
    #loading-overlay.hidden {
      opacity: 0;
      pointer-events: none;
    }
    .progress-bar {
      width: 300px;
      height: 6px;
      background: #e0e0e0;
      border-radius: 3px;
      overflow: hidden;
      margin-top: 20px;
    }
    .progress-fill {
      height: 100%;
      background: linear-gradient(90deg, #0066cc, #00aaff);
      border-radius: 3px;
      width: 0%;
      transition: width 0.3s ease;
    }
    .loading-text {
      margin-top: 12px;
      color: #666;
      font-size: 14px;
    }
    /* 主内容 */
    #main-content {
      text-align: center;
      display: none;
    }
    #main-content h1 {
      font-size: 2em;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <!-- 加载遮罩 -->
  <div id="loading-overlay">
    <div class="progress-bar">
      <div class="progress-fill" id="progress-fill"></div>
    </div>
    <p class="loading-text" id="loading-text">正在加载资源...</p>
  </div>

  <!-- 主内容(初始隐藏) -->
  <div id="main-content">
    <h1>页面加载完成</h1>
    <p>所有资源已成功加载,欢迎访问!</p>
    <img src="https://picsum.photos/600/300" alt="演示图片">
  </div>

  <script>
    var progressFill = document.getElementById('progress-fill');
    var loadingText = document.getElementById('loading-text');
    var overlay = document.getElementById('loading-overlay');
    var mainContent = document.getElementById('main-content');

    // 模拟加载进度
    var progress = 0;
    var timer = setInterval(function() {
      progress += Math.random() * 15 + 5;
      if (progress > 90) progress = 90; // 停在 90% 等待真实加载
      progressFill.style.width = progress + '%';
    }, 200);

    // DOM 加载完成
    document.addEventListener('DOMContentLoaded', function() {
      loadingText.textContent = '正在渲染页面...';
    });

    // 所有资源加载完成
    window.addEventListener('load', function() {
      clearInterval(timer);
      progressFill.style.width = '100%';
      loadingText.textContent = '加载完成!';

      setTimeout(function() {
        overlay.classList.add('hidden');
        mainContent.style.display = 'block';
      }, 500);
    });
  </script>
</body>
</html>

实时显示滚动信息 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>滚动信息</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      margin: 0;
      padding: 0;
      line-height: 1.6;
    }
    /* 固定信息栏 */
    #scroll-info {
      position: fixed;
      bottom: 0;
      left: 0;
      width: 100%;
      background: rgba(0, 0, 0, 0.85);
      color: white;
      padding: 10px 20px;
      font-size: 14px;
      font-family: monospace;
      z-index: 1000;
    }
    #scroll-info span {
      margin-right: 20px;
    }
    /* 生成足够多的内容以便滚动 */
    .content-section {
      min-height: 100vh;
      padding: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1.5em;
      color: white;
    }
    .section-1 { background: linear-gradient(135deg, #667eea, #764ba2); }
    .section-2 { background: linear-gradient(135deg, #f093fb, #f5576c); }
    .section-3 { background: linear-gradient(135deg, #4facfe, #00f2fe); }
    .section-4 { background: linear-gradient(135deg, #43e97b, #38f9d7); }
    .section-5 { background: linear-gradient(135deg, #fa709a, #fee140); }
  </style>
</head>
<body>
  <div id="scroll-info">
    <span>scrollY: <b id="scroll-y">0</b>px</span>
    <span>窗口高度: <b id="win-height">0</b>px</span>
    <span>文档高度: <b id="doc-height">0</b>px</span>
    <span>滚动百分比: <b id="scroll-percent">0</b>%</span>
  </div>

  <div class="content-section section-1"><h1>第一部分</h1></div>
  <div class="content-section section-2"><h1>第二部分</h1></div>
  <div class="content-section section-3"><h1>第三部分</h1></div>
  <div class="content-section section-4"><h1>第四部分</h1></div>
  <div class="content-section section-5"><h1>第五部分 - 到底了!</h1></div>

  <script>
    var scrollYEl = document.getElementById('scroll-y');
    var winHeightEl = document.getElementById('win-height');
    var docHeightEl = document.getElementById('doc-height');
    var scrollPercentEl = document.getElementById('scroll-percent');

    // 使用 passive 事件监听器提高滚动性能
    window.addEventListener('scroll', function() {
      var scrollY = window.scrollY || window.pageYOffset;
      var winHeight = window.innerHeight;
      var docHeight = document.documentElement.scrollHeight;
      var maxScroll = docHeight - winHeight;
      var percent = maxScroll > 0 ? Math.round((scrollY / maxScroll) * 100) : 0;

      scrollYEl.textContent = scrollY;
      winHeightEl.textContent = winHeight;
      docHeightEl.textContent = docHeight;
      scrollPercentEl.textContent = percent;
    }, { passive: true });
  </script>
</body>
</html>

注意事项 ​

html
<!-- 错误!meta 和 link 应该在 head 中 -->
<body>
  <meta charset="UTF-8">
  <title>错误示例</title>
  <link rel="stylesheet" href="style.css">
  <h1>内容</h1>
</body>

<!-- 正确 -->
<head>
  <meta charset="UTF-8">
  <title>正确示例</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>内容</h1>
</body>

虽然浏览器能容错处理这种情况,但这是不规范的写法。

2. 避免在 body 上直接设置样式属性 ​

html
<!-- 不推荐:使用 HTML 属性设置样式 -->
<body bgcolor="#ffffff" text="#333333" link="#0066cc" vlink="#663399" alink="#ff0000">

<!-- 推荐:使用 CSS 设置样式 -->
<body>
  <style>
    body {
      background-color: #ffffff;
      color: #333333;
    }
    a { color: #0066cc; }
    a:visited { color: #663399; }
    a:active { color: #ff0000; }
  </style>

bgcolor、text、link、vlink、alink 等 body 属性已在 HTML5 中被废弃。

3. 避免过深的嵌套 ​

虽然 <body> 可以包含任意深度的嵌套元素,但过深的嵌套会影响性能和可读性:

html
<!-- 不推荐:过深的嵌套 -->
<body>
  <div>
    <div>
      <div>
        <div>
          <div>
            <p>内容</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

建议嵌套层级不超过 5~7 层。

4. 确保 body 有足够的可访问性 ​

html
<!-- 推荐:使用语义化标签 -->
<body>
  <a href="#main-content" class="skip-link">跳转到主要内容</a>
  <header>...</header>
  <main id="main-content">...</main>
  <footer>...</footer>
</body>

最佳实践 ​

1. 使用 CSS 重置 body 默认样式 ​

css
/* 推荐:CSS 重置或 Normalize.css */
body {
  margin: 0;
  padding: 0;
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

2. 使用语义化标签组织内容 ​

html
<body>
  <header>
    <nav>...</nav>
  </header>
  <main>
    <article>...</article>
    <aside>...</aside>
  </main>
  <footer>...</footer>
</body>

3. 使用 JavaScript 事件监听器,而非内联事件 ​

html
<!-- 不推荐 -->
<body onload="init()" onscroll="handleScroll()">

<!-- 推荐 -->
<script>
  window.addEventListener('load', init);
  window.addEventListener('scroll', handleScroll, { passive: true });
</script>

4. 为 body 设置 min-height ​

css
/* 确保页面内容不足时,背景色仍覆盖整个视口 */
body {
  min-height: 100vh;
}
html
<body>
  <a href="#main" style="position:absolute; left:-9999px;">
    跳转到主要内容
  </a>
  <main id="main">
    <!-- 主要内容 -->
  </main>
</body>

下一节

继续学习:title 标题

参考链接 ​