轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • JavaScript
  • TypeScript
  • Node.js
  • Vue.js
  • 前端工程化
  • 浏览器与Web API
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • JavaScript
  • TypeScript
  • Node.js
  • Vue.js
  • 前端工程化
  • 浏览器与Web API
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript

  • TypeScript

  • Node.js

  • Vue.js

  • 工程化

  • 浏览器与Web API

    • HTML基础-语义化标签与文档结构
    • HTML基础-文本与排版标签
    • HTML基础-列表与表格
    • HTML表单-Input类型详解
    • HTML表单-表单元素与验证
    • HTML交互-多媒体元素
      • 一、Audio音频元素
        • 1.1 基本用法
        • 1.2 多格式支持
        • 1.3 音频属性
        • 1.4 JavaScript控制
        • 1.5 自定义播放器
      • 二、Video视频元素
        • 2.1 基本用法
        • 2.2 多格式支持
        • 2.3 响应式视频
        • 2.4 字幕和多语言
        • 2.5 JavaScript控制
      • 三、Picture响应式图片
        • 3.1 基本用法
        • 3.2 不同格式支持
        • 3.3 高分辨率屏幕
        • 3.4 艺术指导
      • 四、Canvas画布
        • 4.1 基本用法
        • 4.2 绘制基本图形
        • 4.3 图片处理
        • 4.4 动画
      • 五、SVG矢量图形
        • 5.1 内联SVG
        • 5.2 复杂图形
        • 5.3 SVG动画
        • 5.4 交互式SVG
      • 六、综合示例
      • 七、最佳实践
        • 7.1 性能优化
        • 7.2 可访问性
        • 7.3 移动端优化
        • 7.4 安全考虑
      • 八、总结
    • HTML工程化-模板与组件化
    • HTML工程化-性能优化
    • CSS基础-选择器与优先级
    • CSS基础-盒模型与布局基础
    • CSS基础-单位与颜色系统
    • CSS基础-文本与字体
    • CSS基础-背景、列表与表格样式
    • CSS布局-Flexbox完全指南
    • CSS布局-Grid网格布局
    • CSS布局-响应式设计实践
    • CSS进阶-动画与过渡
    • CSS进阶-渐变与阴影效果
    • CSS进阶-Transform与3D变换
    • CSS进阶-滤镜与混合模式
    • 现代CSS-CSS预处理器对比
    • 现代CSS-CSS-in-JS方案
    • 现代CSS-原子化CSS与Tailwind
    • CSS工程化-架构与规范
    • CSS工程化-性能优化
    • CSS工程化-PostCSS实战指南
    • Web API基础-DOM操作完全指南
    • Web API基础-事件处理与委托
    • Web API基础-BOM与浏览器环境
    • Web API存储-客户端存储方案
    • Web API网络-HTTP请求详解
    • Web API网络-实时通信方案
    • Web API交互-用户体验增强
    • HTML&CSS历代版本新特性
  • 前端
  • 浏览器与Web API
轩辕李
2019-04-21
目录

HTML交互-多媒体元素

多媒体元素是现代Web应用的重要组成部分。HTML5引入了原生的 <audio>、<video> 元素,以及增强的 <picture>、<canvas>、<svg> 等元素,使得在网页中嵌入和控制多媒体内容变得简单而强大。

本文将详细介绍HTML多媒体元素的使用方法、最佳实践和实际应用场景。

# 一、Audio音频元素

# 1.1 基本用法

<audio src="music.mp3" controls>
  您的浏览器不支持音频播放
</audio>

核心属性:

  • src: 音频文件路径
  • controls: 显示播放控件
  • autoplay: 自动播放(需谨慎使用)
  • loop: 循环播放
  • muted: 静音
  • preload: 预加载策略(none/metadata/auto)

# 1.2 多格式支持

为了兼容不同浏览器,提供多种格式。

<audio controls>
  <source src="music.mp3" type="audio/mpeg">
  <source src="music.ogg" type="audio/ogg">
  <source src="music.wav" type="audio/wav">
  您的浏览器不支持音频播放
</audio>

常见格式:

  • MP3: 兼容性最好,所有现代浏览器支持
  • OGG: 开源格式,Firefox、Chrome支持
  • WAV: 无损格式,文件较大
  • AAC: 高质量,iOS Safari首选

# 1.3 音频属性

<audio id="myAudio" 
       src="music.mp3"
       controls
       loop
       preload="metadata"
       volume="0.8">
</audio>

preload策略:

  • none: 不预加载
  • metadata: 仅加载元数据(时长、比特率等)
  • auto: 尽可能预加载(默认)

# 1.4 JavaScript控制

<audio id="myAudio" src="music.mp3"></audio>

<button onclick="play()">播放</button>
<button onclick="pause()">暂停</button>
<button onclick="stop()">停止</button>
<button onclick="changeVolume()">音量50%</button>

<script>
  const audio = document.getElementById('myAudio');
  
  function play() {
    audio.play();
  }
  
  function pause() {
    audio.pause();
  }
  
  function stop() {
    audio.pause();
    audio.currentTime = 0;
  }
  
  function changeVolume() {
    audio.volume = 0.5; // 0.0 到 1.0
  }
  
  // 监听事件
  audio.addEventListener('play', () => {
    console.log('开始播放');
  });
  
  audio.addEventListener('pause', () => {
    console.log('暂停播放');
  });
  
  audio.addEventListener('ended', () => {
    console.log('播放结束');
  });
  
  audio.addEventListener('timeupdate', () => {
    console.log('当前时间:', audio.currentTime);
  });
</script>

常用属性和方法:

  • audio.play(): 播放
  • audio.pause(): 暂停
  • audio.currentTime: 当前播放位置(秒)
  • audio.duration: 总时长
  • audio.volume: 音量(0-1)
  • audio.muted: 是否静音
  • audio.playbackRate: 播放速率

# 1.5 自定义播放器

<div class="audio-player">
  <audio id="player" src="music.mp3"></audio>
  
  <button id="playBtn">▶️</button>
  <input type="range" id="progress" min="0" max="100" value="0">
  <span id="time">00:00 / 00:00</span>
  <input type="range" id="volume" min="0" max="100" value="100">
</div>

<script>
  const player = document.getElementById('player');
  const playBtn = document.getElementById('playBtn');
  const progress = document.getElementById('progress');
  const timeDisplay = document.getElementById('time');
  const volumeControl = document.getElementById('volume');
  
  // 播放/暂停
  playBtn.addEventListener('click', () => {
    if (player.paused) {
      player.play();
      playBtn.textContent = '⏸️';
    } else {
      player.pause();
      playBtn.textContent = '▶️';
    }
  });
  
  // 进度条
  player.addEventListener('timeupdate', () => {
    const percent = (player.currentTime / player.duration) * 100;
    progress.value = percent;
    
    const current = formatTime(player.currentTime);
    const total = formatTime(player.duration);
    timeDisplay.textContent = `${current} / ${total}`;
  });
  
  progress.addEventListener('input', () => {
    const time = (progress.value / 100) * player.duration;
    player.currentTime = time;
  });
  
  // 音量控制
  volumeControl.addEventListener('input', () => {
    player.volume = volumeControl.value / 100;
  });
  
  function formatTime(seconds) {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }
</script>

# 二、Video视频元素

# 2.1 基本用法

<video src="movie.mp4" controls width="640" height="360">
  您的浏览器不支持视频播放
</video>

核心属性:

  • src: 视频文件路径
  • controls: 显示控件
  • width/height: 尺寸
  • poster: 封面图
  • autoplay: 自动播放
  • loop: 循环播放
  • muted: 静音
  • preload: 预加载策略

# 2.2 多格式支持

<video controls width="640" height="360" poster="poster.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <source src="movie.ogg" type="video/ogg">
  您的浏览器不支持视频播放
</video>

常见格式:

  • MP4 (H.264): 兼容性最好,所有现代浏览器支持
  • WebM: 开源格式,Chrome、Firefox支持
  • OGG: 开源格式,Firefox支持

# 2.3 响应式视频

<!-- 方式1: 百分比宽度 -->
<video controls style="width: 100%; height: auto;">
  <source src="movie.mp4" type="video/mp4">
</video>

<!-- 方式2: 固定宽高比容器 -->
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
  <video controls style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
    <source src="movie.mp4" type="video/mp4">
  </video>
</div>

# 2.4 字幕和多语言

<video controls>
  <source src="movie.mp4" type="video/mp4">
  
  <!-- 字幕轨道 -->
  <track kind="subtitles" src="subtitles-zh.vtt" srclang="zh" label="中文" default>
  <track kind="subtitles" src="subtitles-en.vtt" srclang="en" label="English">
  
  <!-- 描述轨道 -->
  <track kind="descriptions" src="descriptions.vtt" srclang="zh">
</video>

WebVTT字幕格式:

WEBVTT

00:00:00.000 --> 00:00:02.000
这是第一句字幕

00:00:02.500 --> 00:00:05.000
这是第二句字幕

# 2.5 JavaScript控制

<video id="myVideo" width="640" height="360">
  <source src="movie.mp4" type="video/mp4">
</video>

<div>
  <button onclick="playPause()">播放/暂停</button>
  <button onclick="makeBig()">放大</button>
  <button onclick="makeSmall()">缩小</button>
  <button onclick="makeNormal()">正常</button>
</div>

<script>
  const video = document.getElementById('myVideo');
  
  function playPause() {
    if (video.paused) {
      video.play();
    } else {
      video.pause();
    }
  }
  
  function makeBig() {
    video.width = 960;
    video.height = 540;
  }
  
  function makeSmall() {
    video.width = 320;
    video.height = 180;
  }
  
  function makeNormal() {
    video.width = 640;
    video.height = 360;
  }
  
  // 监听事件
  video.addEventListener('play', () => {
    console.log('视频开始播放');
  });
  
  video.addEventListener('ended', () => {
    console.log('视频播放结束');
  });
  
  video.addEventListener('loadedmetadata', () => {
    console.log('视频时长:', video.duration);
  });
</script>

# 三、Picture响应式图片

# 3.1 基本用法

<picture> 元素用于响应式图片,根据条件显示不同图片。

<picture>
  <source media="(min-width: 1024px)" srcset="large.jpg">
  <source media="(min-width: 768px)" srcset="medium.jpg">
  <img src="small.jpg" alt="响应式图片">
</picture>

# 3.2 不同格式支持

<picture>
  <!-- WebP格式(现代浏览器) -->
  <source srcset="image.webp" type="image/webp">
  
  <!-- AVIF格式(最新浏览器) -->
  <source srcset="image.avif" type="image/avif">
  
  <!-- 备用JPEG -->
  <img src="image.jpg" alt="图片描述">
</picture>

# 3.3 高分辨率屏幕

<picture>
  <source srcset="image-2x.jpg 2x, image-1x.jpg 1x">
  <img src="image-1x.jpg" alt="图片">
</picture>

# 3.4 艺术指导

不同屏幕显示不同构图的图片。

<picture>
  <!-- 桌面:横向构图 -->
  <source media="(min-width: 1024px)" srcset="landscape.jpg">
  
  <!-- 平板:方形构图 -->
  <source media="(min-width: 768px)" srcset="square.jpg">
  
  <!-- 手机:竖向构图 -->
  <img src="portrait.jpg" alt="响应式艺术指导">
</picture>

# 四、Canvas画布

# 4.1 基本用法

<canvas id="myCanvas" width="400" height="300"></canvas>

<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');
  
  // 绘制矩形
  ctx.fillStyle = '#667eea';
  ctx.fillRect(50, 50, 200, 100);
  
  // 绘制文本
  ctx.fillStyle = 'white';
  ctx.font = '24px Arial';
  ctx.fillText('Hello Canvas', 80, 110);
</script>

# 4.2 绘制基本图形

<canvas id="shapes" width="600" height="400"></canvas>

<script>
  const canvas = document.getElementById('shapes');
  const ctx = canvas.getContext('2d');
  
  // 矩形
  ctx.fillStyle = '#667eea';
  ctx.fillRect(50, 50, 100, 80);
  
  // 描边矩形
  ctx.strokeStyle = '#764ba2';
  ctx.lineWidth = 3;
  ctx.strokeRect(200, 50, 100, 80);
  
  // 圆形
  ctx.fillStyle = '#28a745';
  ctx.beginPath();
  ctx.arc(400, 90, 40, 0, 2 * Math.PI);
  ctx.fill();
  
  // 线条
  ctx.strokeStyle = '#dc3545';
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.moveTo(50, 200);
  ctx.lineTo(150, 250);
  ctx.lineTo(100, 300);
  ctx.stroke();
  
  // 文本
  ctx.fillStyle = '#333';
  ctx.font = '20px Arial';
  ctx.fillText('Canvas绘图', 50, 350);
</script>

# 4.3 图片处理

<canvas id="imageCanvas" width="400" height="300"></canvas>

<script>
  const canvas = document.getElementById('imageCanvas');
  const ctx = canvas.getContext('2d');
  const img = new Image();
  
  img.onload = () => {
    // 绘制原图
    ctx.drawImage(img, 0, 0, 200, 150);
    
    // 绘制缩放图
    ctx.drawImage(img, 210, 0, 100, 75);
    
    // 获取像素数据
    const imageData = ctx.getImageData(0, 0, 200, 150);
    
    // 灰度滤镜
    for (let i = 0; i < imageData.data.length; i += 4) {
      const avg = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3;
      imageData.data[i] = avg;     // Red
      imageData.data[i + 1] = avg; // Green
      imageData.data[i + 2] = avg; // Blue
    }
    
    // 绘制处理后的图片
    ctx.putImageData(imageData, 0, 160);
  };
  
  img.src = 'photo.jpg';
</script>

# 4.4 动画

<canvas id="animation" width="600" height="400"></canvas>

<script>
  const canvas = document.getElementById('animation');
  const ctx = canvas.getContext('2d');
  
  let x = 50;
  let y = 200;
  let dx = 2;
  let dy = 2;
  const radius = 20;
  
  function draw() {
    // 清空画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 绘制小球
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fillStyle = '#667eea';
    ctx.fill();
    
    // 碰撞检测
    if (x + dx > canvas.width - radius || x + dx < radius) {
      dx = -dx;
    }
    if (y + dy > canvas.height - radius || y + dy < radius) {
      dy = -dy;
    }
    
    // 更新位置
    x += dx;
    y += dy;
    
    // 请求下一帧
    requestAnimationFrame(draw);
  }
  
  draw();
</script>

# 五、SVG矢量图形

# 5.1 内联SVG

<svg width="200" height="200">
  <!-- 矩形 -->
  <rect x="50" y="50" width="100" height="80" fill="#667eea" />
  
  <!-- 圆形 -->
  <circle cx="100" cy="150" r="30" fill="#764ba2" />
  
  <!-- 文本 -->
  <text x="100" y="190" text-anchor="middle" fill="#333">SVG图形</text>
</svg>

# 5.2 复杂图形

<svg width="400" height="300" viewBox="0 0 400 300">
  <!-- 渐变定义 -->
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
    </linearGradient>
  </defs>
  
  <!-- 使用渐变的矩形 -->
  <rect x="50" y="50" width="300" height="200" fill="url(#grad1)" rx="10" />
  
  <!-- 路径 -->
  <path d="M 100 100 L 200 100 L 150 180 Z" fill="#fff" opacity="0.5" />
  
  <!-- 星形 -->
  <polygon points="200,80 220,140 280,140 230,170 250,230 200,200 150,230 170,170 120,140 180,140"
           fill="#ffc107" />
</svg>

# 5.3 SVG动画

<svg width="200" height="200">
  <circle cx="100" cy="100" r="40" fill="#667eea">
    <!-- 颜色动画 -->
    <animate attributeName="fill"
             values="#667eea;#764ba2;#667eea"
             dur="3s"
             repeatCount="indefinite" />
    
    <!-- 缩放动画 -->
    <animate attributeName="r"
             values="40;60;40"
             dur="2s"
             repeatCount="indefinite" />
  </circle>
</svg>

# 5.4 交互式SVG

<svg width="300" height="200" id="interactiveSVG">
  <circle cx="150" cy="100" r="50" fill="#667eea" class="hoverable" />
  <rect x="50" y="50" width="80" height="60" fill="#764ba2" class="hoverable" />
</svg>

<style>
  .hoverable {
    cursor: pointer;
    transition: all 0.3s;
  }
  
  .hoverable:hover {
    opacity: 0.7;
    transform: scale(1.1);
  }
</style>

<script>
  document.querySelectorAll('.hoverable').forEach(element => {
    element.addEventListener('click', (e) => {
      const currentColor = e.target.getAttribute('fill');
      const newColor = currentColor === '#667eea' ? '#28a745' : '#667eea';
      e.target.setAttribute('fill', newColor);
    });
  });
</script>

# 六、综合示例

<html>
  <div class="multimedia-demo-b1c2d">
    <h2>多媒体展示中心</h2>
    
    <!-- 视频播放器 -->
    <section class="section-b1c2d">
      <h3>📹 视频播放</h3>
      <div class="video-container-b1c2d">
        <video id="video-b1c2d" class="video-b1c2d" poster="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='360'%3E%3Crect fill='%23667eea' width='640' height='360'/%3E%3Ctext fill='white' font-size='48' font-family='Arial' x='50%25' y='50%25' text-anchor='middle' dy='.3em'%3E视频封面%3C/text%3E%3C/svg%3E">
          <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
          您的浏览器不支持视频播放
        </video>
        <div class="video-controls-b1c2d">
          <button id="playBtn-b1c2d" class="control-btn-b1c2d">▶️</button>
          <input type="range" id="progress-b1c2d" class="progress-b1c2d" min="0" max="100" value="0">
          <span id="time-b1c2d" class="time-b1c2d">00:00 / 00:00</span>
          <input type="range" id="volume-b1c2d" class="volume-b1c2d" min="0" max="100" value="100" title="音量">
        </div>
      </div>
    </section>
    
    <!-- SVG图形 -->
    <section class="section-b1c2d">
      <h3>✨ SVG交互图形</h3>
      <svg width="600" height="300" class="svg-container-b1c2d" id="svg-b1c2d">
        <defs>
          <linearGradient id="grad-b1c2d" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
          </linearGradient>
        </defs>
        
        <circle cx="100" cy="100" r="50" fill="url(#grad-b1c2d)" class="svg-shape-b1c2d">
          <animate attributeName="r" values="50;60;50" dur="2s" repeatCount="indefinite" />
        </circle>
        
        <rect x="200" y="50" width="100" height="100" fill="#28a745" class="svg-shape-b1c2d" />
        
        <polygon points="450,50 500,100 450,150 400,100" fill="#ffc107" class="svg-shape-b1c2d" />
        
        <text x="300" y="250" text-anchor="middle" fill="#333" font-size="20">
          点击图形改变颜色
        </text>
      </svg>
    </section>
  </div>
</html>
<style>
  .multimedia-demo-b1c2d {
    padding: 2rem;
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    min-height: 100vh;
  }
  
  .multimedia-demo-b1c2d h2 {
    text-align: center;
    color: #333;
    font-size: 2rem;
    margin-bottom: 2rem;
  }
  
  .section-b1c2d {
    background: white;
    padding: 2rem;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    margin-bottom: 2rem;
  }
  
  .section-b1c2d h3 {
    margin: 0 0 1.5rem 0;
    color: #667eea;
    font-size: 1.5rem;
  }
  
  /* 视频播放器 */
  .video-container-b1c2d {
    max-width: 640px;
    margin: 0 auto;
  }
  
  .video-b1c2d {
    width: 100%;
    border-radius: 8px;
    display: block;
  }
  
  .video-controls-b1c2d {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 1rem;
    padding: 1rem;
    background: #f8f9fa;
    border-radius: 8px;
  }
  
  .control-btn-b1c2d {
    background: #667eea;
    color: white;
    border: none;
    padding: 0.5rem 1rem;
    border-radius: 6px;
    cursor: pointer;
    font-size: 1.2rem;
    transition: all 0.3s;
  }
  
  .control-btn-b1c2d:hover {
    background: #5a67d8;
    transform: scale(1.05);
  }
  
  .progress-b1c2d {
    flex: 1;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: #dee2e6;
    border-radius: 3px;
    outline: none;
  }
  
  .progress-b1c2d::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background: #667eea;
    border-radius: 50%;
    cursor: pointer;
  }
  
  .time-b1c2d {
    color: #495057;
    font-size: 0.9rem;
    min-width: 100px;
  }
  
  .volume-b1c2d {
    width: 100px;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: #dee2e6;
    border-radius: 3px;
    outline: none;
  }
  
  .volume-b1c2d::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 12px;
    height: 12px;
    background: #667eea;
    border-radius: 50%;
    cursor: pointer;
  }
  
  /* SVG */
  .svg-container-b1c2d {
    display: block;
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
    border: 2px solid #dee2e6;
    border-radius: 8px;
    background: white;
  }
  
  .svg-shape-b1c2d {
    cursor: pointer;
    transition: all 0.3s;
  }
  
  .svg-shape-b1c2d:hover {
    opacity: 0.7;
    transform: scale(1.1);
  }
  
  @media (max-width: 768px) {
    .multimedia-demo-b1c2d {
      padding: 1rem;
    }
    
    .section-b1c2d {
      padding: 1.5rem;
    }
    
    .video-controls-b1c2d {
      flex-wrap: wrap;
    }
    
    .time-b1c2d {
      width: 100%;
      text-align: center;
    }
  }
</style>
<script>
  // 视频控制
  const video = document.getElementById('video-b1c2d');
  const playBtn = document.getElementById('playBtn-b1c2d');
  const progress = document.getElementById('progress-b1c2d');
  const timeDisplay = document.getElementById('time-b1c2d');
  const volumeControl = document.getElementById('volume-b1c2d');
  
  if (video && playBtn) {
    playBtn.addEventListener('click', () => {
      if (video.paused) {
        video.play();
        playBtn.textContent = '⏸️';
      } else {
        video.pause();
        playBtn.textContent = '▶️';
      }
    });
    
    video.addEventListener('timeupdate', () => {
      const percent = (video.currentTime / video.duration) * 100;
      progress.value = percent;
      
      const current = formatTime(video.currentTime);
      const total = formatTime(video.duration);
      timeDisplay.textContent = `${current} / ${total}`;
    });
    
    progress.addEventListener('input', () => {
      const time = (progress.value / 100) * video.duration;
      video.currentTime = time;
    });
    
    volumeControl.addEventListener('input', () => {
      video.volume = volumeControl.value / 100;
    });
  }
  
  function formatTime(seconds) {
    if (isNaN(seconds)) return '00:00';
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }
  
  // Canvas动画
  const canvas = document.getElementById('canvas-b1c2d');
  const ctx = canvas ? canvas.getContext('2d') : null;
  let animationId = null;
  const balls = [];
  
  class Ball {
    constructor() {
      this.x = Math.random() * (canvas.width - 40) + 20;
      this.y = Math.random() * (canvas.height - 40) + 20;
      this.dx = (Math.random() - 0.5) * 4;
      this.dy = (Math.random() - 0.5) * 4;
      this.radius = Math.random() * 20 + 10;
      this.color = `hsl(${Math.random() * 360}, 70%, 60%)`;
    }
    
    draw() {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
      ctx.fillStyle = this.color;
      ctx.fill();
    }
    
    update() {
      if (this.x + this.dx > canvas.width - this.radius || this.x + this.dx < this.radius) {
        this.dx = -this.dx;
      }
      if (this.y + this.dy > canvas.height - this.radius || this.y + this.dy < this.radius) {
        this.dy = -this.dy;
      }
      this.x += this.dx;
      this.y += this.dy;
    }
  }
  
  function startAnimation() {
    if (!ctx) return;
    // 检查动画是否已经在运行
    if (animationId) return;
    if (balls.length === 0) {
      for (let i = 0; i < 10; i++) {
        balls.push(new Ball());
      }
    }
    animate();
  }
  
  function animate() {
    if (!ctx) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    balls.forEach(ball => {
      ball.draw();
      ball.update();
    });
    
    animationId = requestAnimationFrame(animate);
  }
  
  function stopAnimation() {
    if (animationId) {
      cancelAnimationFrame(animationId);
      animationId = null;
    }
  }
  
  function clearCanvas() {
    if (!ctx) return;
    stopAnimation();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    balls.length = 0;
  }
  
  // SVG交互
  const svgShapes = document.querySelectorAll('.svg-shape-b1c2d');
  const colors = ['#667eea', '#764ba2', '#28a745', '#ffc107', '#dc3545', '#17a2b8'];
  
  svgShapes.forEach(shape => {
    shape.addEventListener('click', () => {
      const randomColor = colors[Math.floor(Math.random() * colors.length)];
      shape.setAttribute('fill', randomColor);
    });
  });
</script>

# 七、最佳实践

# 7.1 性能优化

延迟加载:

<!-- 视频延迟加载 -->
<video preload="none" poster="poster.jpg">
  <source src="video.mp4" type="video/mp4">
</video>

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

压缩和优化:

  • 使用适当的视频编码和比特率
  • 优化图片大小和格式
  • Canvas使用离屏渲染
  • SVG压缩和精简

# 7.2 可访问性

<!-- 提供替代内容 -->
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="zh" label="中文字幕">
  <p>您的浏览器不支持视频播放。<a href="video.mp4">下载视频</a></p>
</video>

<!-- Canvas提供替代文本 -->
<canvas aria-label="销售数据图表">
  <!-- 提供文字说明 -->
  <p>2024年Q1销售额为100万,环比增长20%</p>
</canvas>

# 7.3 移动端优化

<!-- 自适应视频 -->
<video controls playsinline>
  <source src="video.mp4" type="video/mp4">
</video>

<!-- 响应式Canvas -->
<canvas id="responsive" style="width: 100%; height: auto;"></canvas>

<script>
  const canvas = document.getElementById('responsive');
  const dpr = window.devicePixelRatio || 1;
  const rect = canvas.getBoundingClientRect();
  
  canvas.width = rect.width * dpr;
  canvas.height = rect.height * dpr;
  
  const ctx = canvas.getContext('2d');
  ctx.scale(dpr, dpr);
</script>

# 7.4 安全考虑

<!-- 禁止自动播放(用户体验) -->
<video controls>
  <source src="video.mp4" type="video/mp4">
</video>

<!-- Canvas内容安全 -->
<canvas id="secure"></canvas>
<script>
  const canvas = document.getElementById('secure');
  const ctx = canvas.getContext('2d');
  
  // 避免从不信任的源绘制图片
  const img = new Image();
  img.crossOrigin = 'anonymous'; // 设置跨域
  img.src = 'trusted-source.jpg';
</script>

# 八、总结

掌握HTML多媒体元素的关键点:

  1. Audio/Video: 使用原生元素,提供多格式支持
  2. Picture: 响应式图片,优化不同设备体验
  3. Canvas: 动态绘图和动画,适合游戏和数据可视化
  4. SVG: 矢量图形,可缩放、可交互
  5. 性能优化: 延迟加载、压缩、适当的预加载策略
  6. 可访问性: 提供字幕、替代内容、键盘控制
  7. 移动端: 响应式设计、自适应播放控件

HTML多媒体元素为Web应用提供了丰富的交互体验,掌握这些技术能够创建更生动、更吸引人的网页内容。

祝你变得更强!

编辑 (opens new window)
#HTML#多媒体
上次更新: 2025/11/28
HTML表单-表单元素与验证
HTML工程化-模板与组件化

← HTML表单-表单元素与验证 HTML工程化-模板与组件化→

最近更新
01
AI编程时代的一些心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code 最佳实践(个人版)
08-01
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式