《很全面的前端面试题》——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 拿到手软! 如果有其他问题,欢迎在评论区交流~

相关推荐
sasaraku.22 分钟前
serviceWorker缓存资源
前端
RadiumAg1 小时前
记一道有趣的面试题
前端·javascript
yangzhi_emo1 小时前
ES6笔记2
开发语言·前端·javascript
yanlele2 小时前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
中微子3 小时前
React状态管理最佳实践
前端
烛阴3 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
小兵张健3 小时前
武汉拿下 23k offer 经历
java·面试·ai编程
中微子3 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...3 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
爱莉希雅&&&4 小时前
技术面试题,HR面试题
开发语言·学习·面试