《很全面的前端面试题》——HTML篇

前言

本文整理了小编学习的一些(其实是大量)的面试题,这里主要是HTML方面的面试题,会对每一个面试题进行详尽的讲解,如果有什么没有提到的HTML方面的常考面试题,欢迎大家补充,共同进步!

一、src 和 href 的区别

点开你的项目中的一个HTML文档,你很可能发现下面的两段代码

ini 复制代码
<link href="styles.css" rel="stylesheet">
xml 复制代码
<script src="app.js"></script>

两段代码分别是对外部css和js资源的引用,但是引用的方式却不相同

一个引用时使用href,而另一个则是使用src,那么这是为何呢,明明都是加载外部文件不是吗?

带着这个疑问,我们开启下面的讲解------src与href的区别...


1.下面的这句话是我们讲解的基础

最核心区别:
src 直接嵌入并替换当前元素内容 (如JS执行、图片显示),而 href 建立与外部资源的关联关系(如CSS应用、链接跳转)。

本质差异:
src"把资源拿过来用"href"告诉浏览器这个资源和我有关"

我们提取关键词,src是'嵌入',href是'关联'

2.那么何为嵌入?何为关联?

看下面的例子

html 复制代码
    <img src="http://gips3.baidu.com/it/u=1022347589,1106887837&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280" alt="" width="100px" height="100px">
    <a href="http://gips3.baidu.com/it/u=1022347589,1106887837&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280">点击下载图片</a>

这里的图片直接显示在页面上,这就是'嵌入'

这里的一个超链接,不会将图片直接显示在页面上,这就叫'关联'

这里只是举个例子方便大家理解,实际上'嵌入'和'关联'不只是展示和不展示的关系,还有更深层的关系

我们再次回到在文章开篇给大家的例子,css和js的引用

3.为什么css就是关联,而js就得嵌入?

我们来研究一下css,css只是修饰 HTML,不改变文档结构,只影响渲染样式。

而js呢,动态修改 DOM、执行逻辑,可能改变文档结构或行为。

一个不会影响HTML的文档结构,而另一个会影响 ,这就是为什么css是关联,而js是嵌入,不嵌入如何影响文档结构呢?不影响文档结构为什么要嵌入呢

4.性能上的区别

当然上述只是较为浅显的讲解了src和href的直观的区别,其实src与href还有诸如性能上的区别

下面我们基于下面的表来讲解

对比项 src href
加载方式 同步加载(默认阻塞渲染) 异步加载(不阻塞 DOM 解析)
执行/渲染 立即生效(如执行 JS、显示图片) 按需生效(如点击链接、应用 CSS)
缓存策略 强缓存优先(如 Cache-Control 协商缓存优先(如 ETag
错误影响 可能导致元素失效(如图片裂图) 通常降级处理(如 CSS 加载失败)

(1)加载方式的区别

src 的加载特点

src 属性用于嵌入式资源 ,浏览器会同步加载这些资源。这意味着:

ini 复制代码
<script src="app.js"></script>
<img src="photo.jpg">

当浏览器解析到这些标签时:

  1. 暂停 HTML 解析
  2. 立即下载 app.jsphoto.jpg
  3. 执行/渲染资源内容
  4. 完成后才继续解析后续 HTML

这种同步加载机制可能导致页面渲染延迟(特别是当脚本很大时)。

href 的加载特点

href 属性用于关联性资源 ,浏览器会异步加载这些资源:

ini 复制代码
<link href="styles.css" rel="stylesheet">
<a href="about.html">关于我们</a>

加载过程:

  1. 继续解析 HTML(不阻塞)
  2. 后台并行下载 styles.css
  3. 按需应用(CSS 下载完成后才渲染样式)

例外情况:CSS 会阻塞渲染(避免"无样式内容闪烁"),但仍异步加载。

(2)执行/渲染时机的区别

src 资源的执行

src 资源的生效是立即且强制性的

xml 复制代码
<!-- 图片会立即加载并显示 -->
<img src="banner.jpg" alt="广告横幅">

<!-- JS 会立即下载并执行 -->
<script src="analytics.js"></script>

如果资源加载失败:

  • 图片会显示破损图标
  • JS 会抛出错误并中断执行

href 资源的应用

href 资源的生效是按需或延迟的

xml 复制代码
<!-- CSS 下载完成后才会应用样式 -->
<link href="theme.css" rel="stylesheet">

<!-- 只有点击链接才会加载页面 -->
<a href="contact.html">联系我们</a>

如果资源加载失败:

  • CSS 会降级使用浏览器默认样式
  • 链接点击会跳转到错误页面

(33)缓存策略的区别

src 资源的缓存

浏览器对 src 资源倾向于使用强缓存

xml 复制代码
<!-- 图片可能被长期缓存 -->
<img src="logo.png" alt="公司标志">

缓存表现:

  • 优先使用 Cache-Control: max-age
  • 适合不变资源(如图片、静态JS)

href 资源的缓存

href 资源更多使用协商缓存

xml 复制代码
<!-- CSS 经常使用ETag验证 -->
<link href="styles.css" rel="stylesheet">

缓存表现:

  • 优先使用 ETag/Last-Modified
  • 适合频繁更新的资源(如CSS)

(4)错误处理的区别

src 资源错误

加载失败会直接影响功能:

xml 复制代码
<!-- 图片加载失败会显示alt文本 -->
<img src="missing.jpg" alt="图片缺失提示">

<!-- JS加载失败会中断后续脚本 -->
<script src="missing.js"></script>

href 资源错误

加载失败通常有优雅降级:

xml 复制代码
<!-- CSS加载失败会使用浏览器默认样式 -->
<link href="missing.css" rel="stylesheet">

<!-- 链接失效会显示404页面 -->
<a href="deleted.html">已删除的页面</a>

二、对HTML语义化标签的理解

对于这个问题,确实是面试官经常问到的,而且回答比较固定,就按照下面的解读顺序来解答

1. 定义语义化标签

"语义化标签是指HTML中那些具有明确含义和用途的标签,它们不仅能告诉浏览器如何显示内容,更重要的是能清晰地表达内容的含义和结构。"

2. 语义化标签的优势

"使用语义化标签主要有以下几个好处:

  • 更好的可读性:代码更易于理解和维护
  • 更佳的SEO:搜索引擎能更好地理解页面内容
  • 更强的可访问性:辅助技术(如屏幕阅读器)能更准确地解读页面
  • 更清晰的文档结构:使页面层次更加分明"

3. 常见语义化标签举例

"HTML5引入了一些重要的语义化标签,比如:

  • <header>表示页眉或内容区块的头部
  • <nav>定义导航链接
  • <main>表示文档的主要内容
  • <article>表示独立的内容区块
  • <section>定义文档中的节或段
  • <aside>表示与周围内容相关但不直接相关的内容
  • <footer>表示页脚或内容区块的底部"

4. 与传统div布局的对比

"相比传统的div+class命名方式,语义化标签:

  • 使HTML结构更直观
  • 减少了不必要的class命名
  • 提供了更丰富的文档结构信息"

5. 实际应用建议

"在实际开发中,我通常会:

  1. 优先使用合适的语义化标签
  2. 只在没有合适语义标签时使用div
  3. 结合ARIA属性进一步增强可访问性
  4. 确保标签的嵌套关系合理"

如果面试官表现出兴趣,可以进一步深入展示自己的知识面:

(1)历史背景

"在HTML5之前,开发者主要依赖div和span配合class来构建页面,这导致了所谓的'div汤'问题。HTML5引入语义化标签正是为了解决这个问题。"

(2)技术细节

"语义化标签不仅影响文档结构,还与DOM API和CSS选择器有很好的配合。例如,我们可以直接使用document.querySelector('main')来获取主要内容区域。"

(3)性能考量

"虽然语义化标签本身对性能影响不大,但它们可以带来更好的代码组织和维护性,间接影响开发效率和长期项目性能。"

(4)实际案例

"在我之前参与的项目中,我们通过重构使用语义化标签,使得页面在搜索引擎中的排名提升了约15%,同时屏幕阅读器用户的满意度也有显著提高。"

三、<script>标签中的Async 与Defer 的区别

script 标签的 defer 和 async 属性,是为解决传统脚本加载阻塞 HTML 解析的问题而生传统方式中,脚本加载执行会暂停 HTML 解析,易致白屏或 DOM 操作错误。 defer 让脚本并行加载,等 HTML 解析完按顺序执行,适合需操作 DOM 或有依赖的脚本;async 使脚本并行加载,完成后立即执行,顺序不定,适合独立脚本。二者提升了加载效率,优化了用户体验。

HTML 中,<script>标签的deferasync属性都用于控制脚本的加载和执行时机,但它们有以下区别:

  1. 加载方式
  • defer:脚本会与 HTML 并行加载,但会等到 HTML 解析完成后(DOMContentLoaded 事件触发前)才执行
  • async:脚本会与 HTML 并行加载,加载完成后立即执行,可能会打断 HTML 的解析
  1. 执行顺序
  • defer:多个带defer的脚本会按照它们在 HTML 中出现的顺序执行
  • async:多个带async的脚本执行顺序不确定,先加载完成的先执行
  1. 适用场景
  • defer:适用于需要在 DOM 加载完成后执行,但顺序很重要的脚本,如操作 DOM 的库或框架。

  • async:适用于独立的、不依赖其他脚本和 DOM 的脚本,如广告、分析脚本。

下面是一个简单的示例,展示它们的区别:

xml 复制代码
    <!DOCTYPE html>
    <html>
    <head>
        <!-- 1. 正常脚本:立即加载并执行,阻塞HTML解析 -->
        <script src="script1.js"></script>
        
        <!-- 2. defer脚本:并行加载,按顺序执行,HTML解析完成后 -->
        <script defer src="script2.js"></script>
        
        <!-- 3. async脚本:并行加载,加载完成立即执行,顺序不确定 -->
        <script async src="script3.js"></script>
    </head>
    <body>
        <!-- 页面内容 -->
    </body>
    </html>

执行流程大致为:

script1.js 会阻塞 HTML 解析 script2.js 和 script3.js 会并行加载 script3.js 可能在 HTML 解析完成前执行(如果加载快) script2.js 会在 HTML 解析完成后,按顺序执行(无论何时加载完成)

四、谈谈web worker

给大家推荐一篇关于web worker的文章www.ruanyifeng.com/blog/2018/0...

Web Worker 是 HTML5 引入的一项浏览器 API,它允许 JavaScript 在后台线程中运行复杂计算,避免阻塞主线程(UI 渲染线程),从而显著提升页面响应速度和用户体验。

我们通过一个最简单的Web Worker案例,去体验一下Web Worker是如何运行的

下面是一个最简单的 Web Worker 示例 ,包括主脚本和 worker 脚本两部分

主脚本 (main.js)

首先,在你的 HTML 文件中引入主脚本:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Web Worker Demo</title>
</head>
<body>
    <h1>Web Worker Example</h1>
    <script src="main.js"></script>
</body>
</html>

然后,创建 main.js 文件,并添加以下代码:

javascript 复制代码
// 这段代码首先检查当前浏览器是否支持 Web Workers。`Worker` 是创建 Web Worker 的构造函数。
// 如果浏览器不支持 Web Workers,则会显示一条消息给用户。
if (typeof(Worker) !== "undefined") {
    //通过 `new Worker("worker.js")` 创建一个新的 Web Worker 实例,
    //这里 `"worker.js"` 是指向 Worker 脚本的路径。
    //这意味着将要运行的后台脚本位于名为 `worker.js` 的文件中。
    var worker = new Worker("worker.js");

    // 当接收到消息时触发
    worker.onmessage = function(event) {
        console.log("从 Worker 接收到的消息: " + event.data);
    };

    // 向 Worker 发送消息
    worker.postMessage("Hello Worker!");
} else {
    console.log("抱歉,你的浏览器不支持 Web Workers...");
}
Worker 脚本 (worker.js)

接着,创建一个名为 worker.js 的文件,并添加以下代码:

csharp 复制代码
// 当接收到消息时触发
onmessage = function(event) {
    console.log("从主线程接收到的消息: " + event.data);

    // 处理完数据后,发送消息回主线程
    postMessage("你好,主线程!已收到你的消息: " + event.data);
};

具体的代码解释,我以注释的方式放在了代码之中,值得注意的一点是接收消息是onmessage、发送消息是postMessage这是内置的函数,不要随意修改

上述的代码就完成了worker.js中的内容会在独立的线程中运行,不会影响主线程,而且可以和主线程进行通讯

当然,我们也可以和面试官聊一聊web worker的缺点

  1. 性能开销:创建新线程需要额外资源,初始化成本较高,对于轻量级任务反而可能降低效率。
  2. 通信瓶颈:线程间数据传递需通过序列化 / 反序列化(深拷贝)实现,频繁通信会导致显著延迟。
  3. 功能受限 :无法直接操作 DOM 或访问主线程的 windowdocument 对象,应用场景受限。
  4. 调试复杂:多线程环境下的调试难度较大,错误堆栈追踪和问题定位更具挑战性。
  5. 内存管理 :Worker 线程不会自动销毁,需手动调用 terminate(),否则可能导致内存泄漏。

如果想深入了解web worker在项目中的使用,可以看我之前的一篇文章从零带你解构GitHub爆火项目------前端实现类谷歌翻译功能<( ̄︶ ̄)↗[GO!]

五、HTML5的离线储存如何使用?

再推荐一篇文章 HTML5-离线缓存(Application Cache)

这个已经被弃用了,不知道会不会有面试官问

六、iframe 的优缺点

<iframe> 是 HTML 中用于在当前页面嵌入另一个网页的标签,它创建了一个独立的浏览上下文(browsing context),允许在父页面中显示外部资源。

该标签有广泛的应用场景

下面讲解三个<iframe>最主要的特点

1. 内容隔离性

iframe 创建了一个独立的浏览上下文,内部的 DOM、CSS 和 JavaScript 与父页面完全隔离,避免样式冲突和脚本干扰。

ini 复制代码
<iframe src="https://third-party.com/widget"></iframe>

无论第三方内容如何渲染,都不会影响父页面的布局或功能。

2. 跨域加载能力

iframe 可直接加载不同域名的资源,突破同源策略限制(需目标网站允许)。

xml 复制代码
<iframe src="https://maps.google.com/maps"></iframe> <!-- 加载Google地图 -->

无需复杂的 CORS 配置,即可嵌入第三方服务。

3. 独立生命周期

iframe 内的页面有自己的加载和渲染流程,不依赖父页面。

父页面加载完成后,iframe 仍可异步加载内容:

xml 复制代码
<body>
  <iframe src="heavy-content.html"></iframe> <!-- 不阻塞父页面渲染 -->
</body>

iframe 的优点

1.iframe 的核心优势在于内容隔离和跨域集成。 通过创建独立的浏览上下文,它能将第三方内容(如地图、广告)与主页面完全隔离,避免样式冲突和脚本干扰

例如,嵌入 Google 地图只需一行代码:<iframe src="https://maps.google.com"></iframe>,无需复杂的 API 对接。

2.此外,iframe 支持加载不同域名的资源,突破同源策略限制,适合快速整合外部服务。其独立的生命周期也允许异步加载内容,不阻塞主页面渲染,提升用户体验。

iframe 的缺点

1.iframe 的主要代价在于性能开销和开发复杂性。 每个 iframe 都需独立加载资源并占用额外内存,多层嵌套会导致加载速度显著下降。
2.与主页面通信需通过 postMessage,且需严格验证消息来源以防止 XSS 攻击。
3.响应式设计也颇具挑战 ,需手动计算高度或依赖 JavaScript 动态调整。

此外,搜索引擎通常不会索引 iframe 内容,影响 SEO。安全方面 ,若未正确配置 sandbox 属性,嵌入不可信来源可能引入安全风险。

因此,现代前端更倾向于使用组件化框架(如 React/Vue)替代 iframe 实现内部功能复用。

七、你认为label标签如何使用?

<label> 标签在 HTML 中用于为表单元素(如 inputselecttextarea)创建关联文本,主要作用是增强表单的可访问性和用户体验

一、基础用法:显式关联

通过 for 属性与表单元素的 id 绑定,点击标签时会聚焦到对应元素。

ini 复制代码
<label for="username">用户名:</label>
<input type="text" id="username" name="username">

二、隐式关联:嵌套表单元素

将表单元素直接放在 <label> 内,无需 forid

xml 复制代码
<label>
  记住我
  <input type="checkbox" name="remember">
</label>

三、增强交互体验

  1. 扩大点击区域:用户点击标签文本时,也能触发表单元素。

    ini 复制代码
    <label for="subscribe">
      <input type="checkbox" id="subscribe">
      订阅 newsletter
    </label>
  2. 提升无障碍性:屏幕阅读器会朗读标签文本,帮助视力障碍用户理解表单用途。

其实面试官最想听到的就是第三点,增强交互体验,这是label区别于div,span等标签的重要一点

八、Canvas和SVG的区别

Canvas 和 SVG 都是 HTML5 中用于绘制图形的技术,但核心逻辑和适用场景差异很大。

Canvas 是基于像素的位图绘制技术 ,通过 JavaScript 动态操作像素,优势在于处理高频更新的动态场景 ,比如游戏动画、实时数据可视化(像股票 K 线的实时刷新),因为它直接操作像素,绘制大量元素时性能更优;但缺点是放大后可能模糊,且需要手动计算点击区域来实现交互

SVG 则是基于 XML 的矢量图形 ,用标签描述图形的几何信息,优势是缩放时不会失真,适合静态或交互简单的场景 ,比如图标、流程图、地图(像点击某个区域高亮),而且原生支持 DOM 事件,交互实现更简单;但如果图形复杂(比如包含上万节点),会因为 DOM 节点过多影响性能。

实际开发中会根据场景选择:需要高性能动态效果选 Canvas,需要无损缩放或简单交互选 SVG,有时也会结合使用,比如用 Canvas 做底层渲染、SVG 做上层交互层。

九、介绍一下img的srcset属性

img标签的srcset属性主要用于解决不同设备(如手机、平板、桌面端)在屏幕尺寸、分辨率上的差异,实现图片的自适应加载,提升页面性能和用户体验

它的核心作用是让浏览器根据当前设备的条件(比如屏幕宽度、像素密度),从开发者提供的多个图片版本中自动选择最合适的一张加载。使用时需要指定多个图片资源及其对应的适配条件,格式是 "图片路径 + 空格 + 条件描述",多个资源用逗号分隔。

下面举一个例子方便大家理解

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>srcset 属性示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
    }
    .image-container {
      margin: 20px 0;
      text-align: center;
    }
    img {
      max-width: 100%;
      height: auto;
      border-radius: 8px;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    }
    .info {
      margin-top: 10px;
      color: #666;
      font-size: 14px;
    }
  </style>
</head>
<body>
  <h1>img srcset 属性示例</h1>
  
  <div class="image-container">
    <!-- srcset + sizes 组合使用 -->
    <img 
      src="https://picsum.photos/800/400"  <!-- 兼容不支持srcset的浏览器 -->
      srcset="
        https://picsum.photos/400/200 400w,
        https://picsum.photos/800/400 800w,
        https://picsum.photos/1200/600 1200w,
        https://picsum.photos/1600/800 1600w
      "
      sizes="
        (max-width: 600px) 100vw,   <!-- 屏幕宽度≤600px时,图片宽度为视口宽度 -->
        (max-width: 1000px) 50vw,  <!-- 屏幕宽度≤1000px时,图片宽度为视口宽度的50% -->
        800px                       <!-- 其他情况,图片宽度为800px -->
      "
      alt="风景图示例"
    >
    <div class="info">
      此图片会根据设备屏幕尺寸和像素密度自动选择最合适的版本加载。
      <br>
      当前加载的是:<span id="loadedImage"></span>
    </div>
  </div>

  <script>
    // 显示当前加载的图片信息(仅用于演示)
    document.addEventListener('DOMContentLoaded', () => {
      const img = document.querySelector('img');
      const info = document.getElementById('loadedImage');
      
      // 图片加载完成后
      img.onload = () => {
        info.textContent = `${img.naturalWidth}×${img.naturalHeight}px`;
      };
      
      // 窗口大小变化时重新检查
      window.addEventListener('resize', () => {
        setTimeout(() => {
          info.textContent = `${img.naturalWidth}×${img.naturalHeight}px`;
        }, 300);
      });
    });
  </script>
</body>
</html>

这个属性的优势在于避免了 "一刀切" 加载同一张图(比如在小屏幕加载过大图片浪费带宽,或在高清屏加载低清图导致模糊),既优化了加载速度,又保证了显示效果。

十、介绍一下HTML5 drag API

HTML5 Drag and Drop API 提供了一套原生的拖放功能,允许用户在网页中拖动元素并将其放置到指定区域。

先给大家一个例子,大家可以先玩一玩

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: 'Arial', sans-serif;
      background-color: #f5f7fa;
      padding: 20px;
    }
    
    .board {
      display: flex;
      gap: 15px;
      margin-top: 20px;
    }
    
    .column {
      background-color: #ebecf0;
      border-radius: 8px;
      padding: 12px;
      width: 250px;
      min-height: 400px;
    }
    
    .column-title {
      font-weight: bold;
      padding: 8px;
      margin-bottom: 10px;
      color: #172b4d;
    }
    
    .task {
      background-color: white;
      border-radius: 6px;
      padding: 12px;
      margin-bottom: 10px;
      box-shadow: 0 1px 2px rgba(0,0,0,0.1);
      cursor: grab;
      transition: transform 0.1s, box-shadow 0.2s;
    }
    
    .task:active {
      cursor: grabbing;
    }
    
    .task.dragging {
      opacity: 0.5;
      transform: scale(1.02);
      box-shadow: 0 4px 8px rgba(0,0,0,0.15);
    }
    
    .column.drop-zone {
      background-color: #e1e4e8;
    }
  </style>
</head>
<body>
  <h2>任务看板</h2>
  <div class="board">
    <div class="column" id="todo">
      <div class="column-title">待处理</div>
      <div class="task" draggable="true" data-task-id="1">设计登录页面</div>
      <div class="task" draggable="true" data-task-id="2">编写API文档</div>
    </div>
    
    <div class="column" id="progress">
      <div class="column-title">进行中</div>
      <div class="task" draggable="true" data-task-id="3">用户注册功能开发</div>
    </div>
    
    <div class="column" id="done">
      <div class="column-title">已完成</div>
      <div class="task" draggable="true" data-task-id="4">首页UI设计</div>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', () => {
      // 获取所有可拖动任务和列
      const tasks = document.querySelectorAll('.task');
      const columns = document.querySelectorAll('.column');
      
      // 当前被拖动的任务
      let draggedTask = null;
      
      // 为每个任务添加拖动事件
      tasks.forEach(task => {
        task.addEventListener('dragstart', () => {
          draggedTask = task;
          setTimeout(() => {
            task.classList.add('dragging');
          }, 0);
        });
        
        task.addEventListener('dragend', () => {
          task.classList.remove('dragging');
        });
      });
      
      // 为每个列添加放置事件
      columns.forEach(column => {
        column.addEventListener('dragover', e => {
          e.preventDefault();
          column.classList.add('drop-zone');
        });
        
        column.addEventListener('dragleave', () => {
          column.classList.remove('drop-zone');
        });
        
        column.addEventListener('drop', e => {
          e.preventDefault();
          column.classList.remove('drop-zone');
          
          // 如果目标列中有其他任务,可以插入到特定位置
          // 这里简单追加到列末尾
          if (draggedTask) {
            column.appendChild(draggedTask);
            
            // 在实际应用中,这里可以发送AJAX请求更新服务器状态
            console.log(`任务 ${draggedTask.dataset.taskId} 移动到 ${column.id} 列`);
          }
        });
      });
    });
  </script>
</body>
</html>

下面给大家简单的讲解一下这些API的使用

1. 让元素可以拖动

首先,告诉浏览器哪些东西能拖动:

ini 复制代码
<div draggable="true">把我拖走</div>

加上 draggable="true" 这个元素就能被拖动了

2. 设置拖放区域

然后,指定哪些地方能接收被拖动的元素:

bash 复制代码
<div id="drop-area">拖到这里放下</div>

3. 添加4个关键事件

(1) 拖动开始时(dragstart)
javascript 复制代码
document.querySelector('[draggable]').addEventListener('dragstart', function(e) {
  e.dataTransfer.setData('text/plain', '随便带点数据'); // 像快递一样带上数据
  this.style.opacity = '0.5'; // 拖动时变半透明
});
(2) 拖到目标上方时(dragover)
javascript 复制代码
document.getElementById('drop-area').addEventListener('dragover', function(e) {
  e.preventDefault(); // 必须写这句才能放下
  this.style.background = 'lightblue'; // 高亮显示
});
(3) 离开目标区域时(dragleave)
javascript 复制代码
document.getElementById('drop-area').addEventListener('dragleave', function() {
  this.style.background = ''; // 取消高亮
});
(4) 放下时(drop)
javascript 复制代码
document.getElementById('drop-area').addEventListener('drop', function(e) {
  e.preventDefault();
  const data = e.dataTransfer.getData('text/plain'); // 取出之前带的数据
  this.innerHTML = `收到了:${data}`; // 显示收到的内容
  this.style.background = ''; // 取消高亮
});

十一、<!Doctype html>有何作用?

<!DOCTYPE html> 是 HTML5 文档的文档类型声明(Document Type Declaration),它是 HTML 文档的第一行代码,用于告诉浏览器当前文档使用的是 HTML5 标准。

面试过程中,你可能会遇到如下的问题

1. 基本作用

  • 声明文档类型:明确告诉浏览器这是一个 HTML5 文档,使用最新的 HTML 规范解析。
  • 触发标准模式(Standards Mode):确保浏览器按照现代 Web 标准渲染页面,避免旧浏览器的兼容性问题。

2. 为什么必须放在第一行?

  • 避免浏览器进入混杂模式(Quirks Mode)
    如果 <!DOCTYPE html> 缺失或不在文档开头,浏览器可能会以"混杂模式"渲染页面,导致样式和布局表现异常(如盒模型计算错误)。
  • 确保文档解析正确
    HTML 解析器需要先读取 DOCTYPE 来决定如何解析后续内容。

4. 对浏览器渲染模式的影响

  • 标准模式(Standards Mode)

    • 启用条件:存在正确的 <!DOCTYPE html>
    • 特性:严格遵循 W3C 标准,正确解析 CSS 和 JavaScript。
    • 示例:width: 100px 仅包含内容宽度(不包含 paddingborder)。
  • 混杂模式|怪异模式(Quirks Mode)

    • 启用条件:缺失或错误的 DOCTYPE。
    • 特性:模拟旧浏览器(如 IE5)的渲染行为,可能导致布局错乱。
    • 示例:width: 100px 包含内容 + padding + border(类似 box-sizing: border-box)。

5. 实际开发中的意义

  1. 确保跨浏览器一致性

    现代框架(如 React/Vue)的模板默认包含 <!DOCTYPE html>,避免因浏览器差异导致布局问题。

  2. 避免兼容性问题

    例如,在混杂模式下:

    • marginpadding 的计算可能异常。
    • 某些 CSS3 属性(如 flexbox)可能失效。
  3. 验证工具依赖

    W3C 验证器等工具需要 DOCTYPE 来判断文档是否符合标准。


6. 如何验证当前模式?

通过 JavaScript 检测:

javascript 复制代码
if (document.compatMode === "CSS1Compat") {
  console.log("标准模式");
} else {
  console.log("混杂模式");
}

十二、meta viewport 有什么作用,怎么写?

<meta name="viewport"> 是移动端网页开发的核心标签,用于控制网页在移动设备上的显示方式和缩放行为。

注意:如果只写 <meta name="viewport"> 而不指定 content 属性,该标签将完全无效,浏览器会直接忽略它。

一般的写法如下

html 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

具体的参数意义如下------

参数 作用 示例
width device-width 视口宽度=设备宽度 width=375(iPhone6/7/8)
initial-scale 数字 初始缩放比例 1.0(不缩放)
minimum-scale 数字 最小缩放比例 0.5(可缩小至50%)
maximum-scale 数字 最大缩放比例 2.0(可放大至200%)
user-scalable yes/no 是否允许用户缩放 no(禁止缩放)

十三、浏览器乱码的原因是什么?如何解决?

乱码的主要原因

  1. 字符编码声明错误或缺失

    • 网页未指定编码或指定了错误的编码
    • 服务器发送的HTTP头与页面声明的编码不一致
  2. 文件实际编码与声明编码不匹配

    • 文件保存的编码(如UTF-8)与HTML中声明的编码(如GBK)不同
  3. 浏览器自动检测编码失败

    • 浏览器自动识别功能可能误判编码类型
  4. 字体支持问题

    • 浏览器缺少显示特定字符所需的字体

解决方案

1. 正确声明HTML文档编码

xml 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">  <!-- 推荐使用UTF-8编码 -->
    <!-- 或者传统的声明方式 -->
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <!-- 页面内容 -->
</body>
</html>

2. 确保文件实际编码与声明一致

  • 使用代码编辑器(如VS Code)检查并转换文件编码
  • 保存文件时选择正确的编码格式(推荐UTF-8)

3. 配置服务器HTTP头

确保服务器发送正确的Content-Type头:

css 复制代码
Content-Type: text/html; charset=utf-8

4. 检查字体支持

  • 在CSS中指定备用字体
css 复制代码
body {
    font-family: "Microsoft YaHei", Arial, sans-serif;
}

十四、介绍一下渐进增强与优雅降级

渐进增强:先保证所有设备能看(基础HTML),再给新设备加特效(CSS/JS)
优雅降级:先做出最酷效果(最新技术),再让旧设备凑合能用

下面举例子让大家了解一下两者的开发流程

1. 渐进增强(Progressive Enhancement)

核心思想 :先保证基础功能可用(HTML),再逐步增强(CSS → JS)。
适用场景:内容型网站(博客、新闻站)、对可访问性要求高的项目。

① HTML 基础结构(所有设备都能访问)

xml 复制代码
<!-- 基础链接 - 即使没有JS也能跳转 -->
<a href="/details.html" class="enhanced-link">查看详情</a>

② 添加 CSS 增强(提升视觉体验)

css 复制代码
/* 基础样式(所有浏览器) */
.enhanced-link {
  color: blue;
  text-decoration: underline;
}

/* 增强样式(支持CSS3的浏览器) */
@supports (display: flex) {
  .enhanced-link {
    padding: 8px 12px;
    background: #f0f0f0;
  }
}

③ 用 JavaScript 增强交互(现代浏览器才生效)

javascript 复制代码
// 检测浏览器是否支持JS和Fetch API
if ('fetch' in window) {
  const link = document.querySelector('.enhanced-link');
  link.addEventListener('click', (e) => {
    e.preventDefault(); // 阻止默认跳转
    fetch('/api/details').then(...); // AJAX加载内容
  });
}

✅ 优点

  • 低端设备(如旧手机、屏幕阅读器)至少能看内容
  • 代码更健壮,不容易完全崩溃

2. 优雅降级(Graceful Degradation)

核心思想 :先按最新技术开发完整功能,再兼容旧浏览器。
适用场景:Web 应用(如在线工具)、内部系统(可控浏览器环境)。

实现方法

① 默认使用最新技术(如 CSS Grid、AJAX)

bash 复制代码
<button id="ajax-button">加载数据</button>
<div id="content"></div>
javascript 复制代码
// 默认用Fetch API
document.getElementById('ajax-button').addEventListener('click', () => {
  fetch('/api/data').then(response => response.json()).then(updateUI);
});

② 检测兼容性并降级

javascript 复制代码
// 如果不支持Fetch,改用XMLHttpRequest或直接跳转
if (!('fetch' in window)) {
  document.getElementById('ajax-button').onclick = () => {
    window.location.href = '/legacy-data.html'; // 降级方案
  };
}

CSS 降级示例 (用 @supports 检测)

css 复制代码
/* 现代浏览器:用CSS Grid */
.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* 旧浏览器降级为Flexbox */
@supports not (display: grid) {
  .container {
    display: flex;
    flex-wrap: wrap;
  }
  .container > * {
    width: 50%;
  }
}

✅ 优点

  • 现代用户获得最佳体验
  • 开发效率高(先实现理想效果,再处理兼容)

十五、介绍一下HTML5的新特性

这是一个很宽泛的问题,面试官只是想考察我们对HTML发展的掌握,我认为应该挑其中的重点来回答,比较重要的包括下面的五部分

大部分前文都有介绍,部分没介绍的会放到之后的文章介绍,比如存储API会放在面试浏览器篇介绍

1.语义化标签

css 复制代码
<header> <nav> <article> <section> <footer> <aside> <main>
  • 替代<div>,提升可访问性和SEO

2.媒体支持

  • 原生音视频:<audio> <video>(不再依赖Flash)
  • 画布绘图:<canvas> + JavaScript API

3.表单增强

  • 新输入类型:email url date range color
  • 属性:placeholder required pattern autofocus

4.存储API

  • localStorage/sessionStorage(替代Cookie)
  • IndexedDB(结构化数据存储)

5.Web Workers

  • 多线程计算,避免阻塞UI

十六、b与strong的区别

我们可以从以下的几个角度回答

1.视觉表现

两者默认都显示为加粗文本

2.语义差异

<b>:仅表示视觉上的加粗,没有语义含义;<strong>:表示内容具有重要性或紧急性,带有语义强调

3.使用场景

<b>:当只需要视觉上加粗,不需要特别强调内容重要性时;用<strong>:当内容确实重要,需要特别强调时(如警告、关键信息)

4.对辅助设备的影响

屏幕阅读器会以不同语调朗读<strong>的内容;<b>对辅助设备没有特殊处理

★★★但是,我们的回答不要止步于此,碰到了自己擅长的领域必须好好的'秀秀肌肉'

1.<i> vs <em>

<i>:仅表示视觉斜体(如图标、术语);<em>:表示需要强调的文本(语义斜体)

2.<s> vs <del>

<s>:仅表示视觉删除线(如促销价);<del>:表示文档中被删除的内容(有语义)

3.<u> vs <ins>

<u>:仅表示视觉下划线;<ins>:表示文档中新增的内容

结语

HTML 面试题看似基础,但往往藏着不少细节,掌握它们不仅能让你在面试中游刃有余,还能在日常开发中写出更优雅的代码。希望这篇整理能帮你查漏补缺,信心满满地迎接面试挑战!

记住,面试官也是从新手过来的,放轻松,展现你的实力就好!

祝你面试顺利,offer 拿到手软! 如果有其他问题,欢迎在评论区交流~

相关推荐
文心快码BaiduComate8 小时前
给 AI 装上“员工手册”:如何用Rules 给文心快码 (Comate) 赋能提效?
前端·程序员·前端框架
twl8 小时前
注意力机制在Code Agent的应用
前端
涔溪8 小时前
如何使用 CSS Grid 实现响应式布局?
前端·css
想用offer打牌8 小时前
一站式了解数据库三大范式(库表设计基础)
数据库·后端·面试
未来读啥科教资讯8 小时前
2026年深圳国际户外用品展览会参展效果如何?影响力如何?
前端
码农胖大海9 小时前
浏览器及标签页关闭时登出的解决方案
前端·浏览器
喵爸的小作坊9 小时前
StreamPanel:一个让 SSE 调试不再痛苦的 Chrome 插件
前端·后端·http
star learning white9 小时前
xm C语言12
服务器·c语言·前端
tabzzz9 小时前
大道至简:万字漫谈前端性能监控
前端·javascript·性能优化
0思必得09 小时前
[Web自动化] CSS基础概念和介绍
前端·css·python·自动化·html·web自动化