请简单说一下 src 与 href 他俩有什么区别?

大白话 请简单说一下 src 与 href 他俩有什么区别?

上周帮新来的实习生改bug,屏幕上赫然一行红色报错:GET http://localhost:8080/logo.png 404。我点开代码一看——<img href="./logo.png">,当时差点把手里的咖啡泼键盘上。

“哥,我明明路径没错啊,为啥图片就是不出来?”实习生挠着头,黑眼圈比我熬夜改React项目时还重。

这场景是不是特眼熟?咱前端er天天跟HTML标签打交道,srchref就像俩穿同款衣服的孪生兄弟,看着差不多,脾气却差了十万八千里。用错了,轻则图片不显示、脚本跑不起来,重则整个页面白屏,老板在身后盯着时能让你手心冒汗。

今天咱就来给这俩“祖宗”做个全面体检,从3个核心差异讲到8段实战代码,再附赠面试时的“保命回答模板”。保证你看完之后,再遇到srchref的问题,就像吃了布洛芬一样——通透、舒服,再也不用对着屏幕发呆。

(偷偷说:文末有4个“坑王级”扩展问题,90%的前端在项目里踩过,记得看到最后)

问题场景:这些崩溃瞬间,你肯定经历过

先别急着翻技术文档,咱先来盘盘那些因为搞混srchref而踩过的坑,看看你中了几个:

  • Vue项目里的图片谜案:用v-bind:href绑定图片路径,本地开发好好的,一打包上线全变成裂开的图标。后来才发现,webpack对src引入的资源会特殊处理,href只是个普通字符串。
  • React组件的脚本灾难:在useEffect里动态创建link标签加载JS,结果控制台疯狂报错“Uncaught SyntaxError: Unexpected token ‘<’”。原来加载脚本得用srchref只会让浏览器把JS当样式表解析。
  • CSS加载的玄学延迟:把link标签的href写成src,页面加载时样式闪一下就没了。查了半天才知道,src会让浏览器把CSS当成“必须执行的资源”,加载完就扔了,根本不会应用到DOM上。
  • a标签的跳转失灵:想做个锚点跳转,写成<a src="#footer">去底部</a>,点半天没反应。同事路过瞥了一眼:“哥们儿,a标签认href不认src,这是HTML5基础啊”。

这些坑本质上都是一个问题:没搞懂srchref在浏览器眼里到底是啥角色。接下来咱就扒开浏览器的“脑回路”,看看它是怎么处理这俩属性的。

技术原理:浏览器眼里的“搬运工”和“介绍信”

其实srchref的核心区别,用一句话就能说清:src是“搬运工”,负责把外部资源搬进页面并替换自己;href是“介绍信”,只告诉浏览器“我和某个资源有关系”,不搬东西

咱来拆解开说:

关于src:“这东西我要了,现在就用!”

src的全名叫“source”,翻译过来就是“源头”。当浏览器看到带src的标签(比如<img><script>),会立刻停下手里的活儿,去下载这个资源,下载完之后直接把src所在的标签换成资源内容。

比如<script src="app.js"></script>,浏览器会:

  1. 暂停DOM解析(这就是为啥script放头部会阻塞页面加载)
  2. 发送HTTP请求下载app.js
  3. 下载完成后,把<script>标签换成app.js里的代码并执行
  4. 执行完再继续解析后面的DOM

这就像你正在砌墙(解析DOM),突然发现少了块砖(外部资源),于是停下手里的活,亲自去建材市场把砖拉回来(下载资源),把砖嵌进墙里(替换标签),再继续砌墙。

关于href:“这是我朋友,你们认识下”

href的全名叫“hypertext reference”,翻译是“超文本引用”。当浏览器遇到带href的标签(比如<link><a>),只会记录“这个标签和某个资源有关联”,然后继续干自己的事,不会停下解析DOM。

比如<link href="style.css" rel="stylesheet">,浏览器会:

  1. 记下“这个link标签关联着style.css,是个样式表”
  2. 继续解析后面的DOM,同时“偷偷”并行下载style.css
  3. 下载完之后,把样式表应用到已解析的DOM上,不影响之前的解析流程

这就像你在写报告(解析DOM),看到一句“参考资料见附件A”(href),你会先记下来附件A的位置,继续写报告,等有空了再去翻附件(下载资源),不会停下写报告的进度。

关键区别:阻塞 vs 不阻塞

这是最影响前端性能的一点:src会阻塞DOM解析,href不会

为啥script标签推荐放body底部?就是因为src加载JS时会阻塞DOM解析,放头部可能导致页面半天出不来。而link标签加载CSS用href,浏览器可以一边解析DOM一边下载CSS,两者并行,页面加载更快——这也是前端性能优化里“关键CSS内联”的底层逻辑。

代码示例:8段代码让你看清“谁在干活,谁在摸鱼”

光说原理太抽象,咱直接上代码。下面8段示例,包含正确用法、错误用法和对比效果,每句代码都加了注释,保证你一看就懂。

1. img标签:src是亲妈,href是后妈

<!-- 正确用法:用src引入图片 -->
<!-- 浏览器会下载pic.jpg,并用图片替换img标签 -->
<img src="pic.jpg" alt="风景图">

<!-- 错误用法:用href引入图片 -->
<!-- 浏览器只会记录“img标签和pic.jpg有关”,不会下载图片,所以显示alt文字 -->
<img href="pic.jpg" alt="风景图(这行会显示错误)">

效果对比:第一个img会显示图片,第二个只会显示“风景图(这行会显示错误)”,打开控制台会看到“GET … 404”(如果路径对的话也不会显示,因为img不认识href)。

2. script标签:src是执行者,href是摆设

<!-- 正确用法:用src引入JS -->
<!-- 浏览器会下载app.js,暂停DOM解析,执行JS后继续解析 -->
<script src="app.js"></script>

<!-- 错误用法:用href引入JS -->
<!-- 浏览器不知道该怎么处理,不会下载JS,更不会执行 -->
<script href="app.js"></script>

<!-- 正确用法:内联JS不需要src -->
<script>
  // 直接写在script标签里的代码,浏览器会直接执行
  console.log('我是内联JS,不用src也能跑');
</script>

效果对比:第一个script会执行app.js里的代码,第二个啥也不做,第三个会在控制台输出文字。

3. link标签:href是联络员,src是捣蛋鬼

<!-- 正确用法:用href引入CSS -->
<!-- 浏览器会并行下载style.css,解析DOM的同时处理样式 -->
<link rel="stylesheet" href="style.css">

<!-- 错误用法:用src引入CSS -->
<!-- 浏览器会下载style.css,但不会应用样式,白下载了 -->
<link rel="stylesheet" src="style.css">

<!-- 正确用法:用href引入icon -->
<!-- 浏览器会下载favicon.ico,显示在标签页上 -->
<link rel="icon" href="favicon.ico">

效果对比:第一个link会让页面应用style.css的样式,第二个link下载的CSS不会生效,第三个link会在浏览器标签页显示图标。

4. a标签:只认href,跟src没关系

<!-- 正确用法:用href做跳转 -->
<!-- 点击会跳转到baidu.com,href还能写锚点#footer、邮箱mailto:test@163.com -->
<a href="https://www.baidu.com">去百度</a>

<!-- 错误用法:用src做跳转 -->
<!-- 点击没反应,a标签根本不认识src属性 -->
<a src="https://www.baidu.com">点我没用</a>

效果对比:第一个a标签点击会跳转,第二个点击毫无反应。

5. iframe标签:src是窗口,href是空气

<!-- 正确用法:用src引入iframe内容 -->
<!-- 浏览器会下载page.html,在iframe里显示页面内容 -->
<iframe src="page.html" frameborder="0"></iframe>

<!-- 错误用法:用href引入iframe内容 -->
<!-- iframe不会加载任何内容,只会显示空白 -->
<iframe href="page.html" frameborder="0"></iframe>

效果对比:第一个iframe会显示page.html的内容,第二个是空白框。

6. Vue中的动态绑定:v-bind:src vs v-bind:href

<template>
  <div>
    <!-- 正确:动态绑定图片用v-bind:src -->
    <!-- webpack会处理src路径,打包时正确引入图片 -->
    <img :src="imgUrl" alt="vue图片">

    <!-- 错误:动态绑定图片用v-bind:href -->
    <!-- webpack不会处理href路径,打包后可能出现404 -->
    <img :href="imgUrl" alt="vue图片(错误)">

    <!-- 正确:跳转链接用v-bind:href -->
    <a :href="linkUrl">去首页</a>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imgUrl: require('./assets/pic.jpg'), // 注意:Vue中动态src需要用require
      linkUrl: '/home'
    }
  }
}
</script>

效果对比:Vue项目中,第一个img会正确显示图片,第二个img可能显示错误,a标签点击会跳转到/home

7. React中的资源引入:src的特殊待遇

import React from 'react';
// React中引入图片需要import,相当于src的作用
import logo from './logo.png';

function App() {
  return (
    <div>
      {/* 正确:用src引入图片,需要先import */}
      <img src={logo} alt="react logo" />

      {/* 错误:直接写字符串路径,打包后会找不到 */}
      <img src="./logo.png" alt="错误示例" />

      {/* 正确:加载外部脚本用src */}
      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    </div>
  );
}

效果对比:第一个img能显示logo,第二个在开发环境可能正常,打包后会404(因为React的打包工具不会处理字符串路径)。

8. 性能优化:src的阻塞与破解

<!-- 问题:script的src会阻塞DOM解析,放头部会让页面加载变慢 -->
<script src="slow.js"></script> <!-- 假设这个JS要加载3秒 -->

<!-- 解决方案1:用async,下载时不阻塞,下载完立即执行(可能打乱顺序) -->
<script src="fast.js" async></script>

<!-- 解决方案2:用defer,下载时不阻塞,等DOM解析完再执行(保持顺序) -->
<script src="order1.js" defer></script>
<script src="order2.js" defer></script> <!-- 会在order1之后执行 -->

<!-- 解决方案3:把script放body底部,等DOM解析完再加载 -->
<body>
  <!-- 页面内容 -->
  <script src="last.js"></script>
</body>

效果对比:第一个script会让页面停3秒再继续解析,asyncdefer的脚本不会阻塞,body底部的脚本会在页面内容显示后再加载。

对比效果:一张表格分清“谁该干什么”

为了让大家更直观地对比,我做了一张表格,从定义、作用、浏览器处理、常见标签等8个维度整理了srchref的区别:

维度src(搬运工)href(介绍信)
核心作用引入外部资源并替换当前标签建立当前文档与外部资源的关联
浏览器处理方式暂停DOM解析,下载资源后执行/替换标签不暂停DOM解析,并行下载资源(如果需要)
是否阻塞解析是(会阻塞,除非加async/defer)否(并行处理,不影响解析)
资源加载完成后资源内容会成为标签的一部分(比如JS执行、图片显示)资源会被浏览器记录关联(比如CSS应用、跳转目标)
常见标签<img><script><iframe><video><link><a><base>
路径处理(框架中)webpack/Vite会特殊处理(比如打包时替换路径)仅作为字符串处理,需要手动确保路径正确
典型错误场景用src加载CSS导致样式不生效用href加载图片导致图片不显示
性能影响可能阻塞页面加载,需优化(async/defer等)几乎无阻塞,可放心放头部

面试题的两种回答方法:专业版 vs 大白话版

面试时被问到“src和href的区别”,该怎么回答?我准备了两种版本,根据面试官的风格选着用:

正常回答方法(专业版)

srchref都是HTML中用于引入外部资源的属性,核心区别在于作用机制不同:

  • src(source)用于引入必须嵌入到当前文档的资源,浏览器会暂停DOM解析,下载并执行该资源,然后用资源内容替换当前标签。例如<script src="app.js">会下载并执行JS,<img src="pic.jpg">会下载并显示图片。src会阻塞DOM解析,因此在加载JS时通常需要用asyncdefer或放在body底部优化性能。

  • href(hypertext reference)用于建立当前文档与外部资源的关联,浏览器不会暂停DOM解析,只会记录关联关系并并行下载资源(如果需要)。例如<link href="style.css">会关联CSS并应用样式,<a href="page.html">会指定跳转目标。href不阻塞解析,因此link标签加载CSS可以放心放在头部。

此外,src常用于<img><script><iframe>等标签,href常用于<link><a><base>等标签,在Vue、React等框架中,src引入的资源会被打包工具特殊处理,href则作为普通字符串处理。”

大白话回答方法(接地气版)

“其实就是俩干活方式不一样的属性:

src是个急性子,看到它浏览器就跟接到快递似的,立马停下手里的活去取,取回来当场拆开用,还得把自己的位置让给快递(替换标签)。所以<script>src时会让页面卡一下,因为浏览器在等快递。

href是个慢性子,就像给浏览器递了张名片,说“我认识某某资源,你们熟络下”,然后该干嘛干嘛。浏览器收到名片后,会抽空去联系那个资源(比如下载CSS),但手里的活(解析DOM)不停。所以<link>加载CSS用href,页面加载不会卡。

简单说,src是“我要这个东西,现在就用”,href是“我认识这个东西,需要时找它”。”

面试官追问时的加分回答

如果面试官继续问“在性能优化中怎么处理src的阻塞问题?”,可以这样答:

“主要有三种方式:一是给<script>asyncdefer属性,async让JS下载时不阻塞,下载完立即执行;defer让JS下载完等待DOM解析完再执行,还能保证顺序。二是把<script>放在body底部,等DOM解析完再加载。三是用动态创建script标签的方式异步加载,比如在DOMContentLoaded事件后加载非关键JS。这些方法在React、Vue项目中也常用,比如通过import()动态导入组件,本质上也是优化资源加载的阻塞问题。”

总结:3句话记住核心区别

看到这里,估计大家对srchref已经门儿清了,最后用3句话总结下核心点:

  1. 作用不同src是“拿来用”(引入并替换),href是“认个亲”(建立关联)。
  2. 阻塞不同src会阻塞DOM解析,href不会。
  3. 场景不同:加载图片、JS、视频用src;加载CSS、做跳转、关联资源用href

记住这3点,以后写代码时就不会再把这俩兄弟弄混了。

扩展思考:4个“坑王级”问题解答

光懂基础还不够,实际开发中还有很多“变种问题”。我整理了4个前端er最常遇到的扩展问题,逐个解答:

问题1:为什么<script>src时会阻塞CSSOM?

答:这是浏览器的“渲染流水线”决定的。浏览器解析HTML生成DOM,解析CSS生成CSSOM,两者结合才能生成渲染树(Render Tree)。当<script>src加载JS时,JS可能会操作DOM或CSSOM(比如document.styleSheets),所以浏览器会等CSSOM构建完再执行JS,这就导致src加载的JS不仅阻塞DOM解析,还会阻塞CSSOM——这也是“关键CSS内联”能提升首屏加载速度的原因(减少CSSOM构建时间,让JS更快执行)。

问题2:<link>标签的href加载CSS时,会阻塞渲染吗?

答:会阻塞渲染,但不会阻塞DOM解析。浏览器在解析到<link href="style.css">时,会继续解析DOM,但渲染树的生成必须等CSSOM构建完,所以如果CSS加载慢,会导致页面“白屏”或“无样式内容闪烁(FOUC)”。解决办法是:把关键CSS内联到<style>标签,非关键CSS用media="print"延迟加载,或通过JS动态加载。

问题3:Vue的v-bind:srcv-bind:href在打包时有什么区别?

答:在Vue项目中,v-bind:src会被webpack/Vite特殊处理:如果路径是相对路径(比如./pic.jpg),打包工具会把图片当成资源处理,生成哈希文件名(比如pic.8f32d.jpg),并自动替换路径;而v-bind:href只会把路径当成普通字符串,打包后不会改变。所以在Vue中动态加载图片必须用v-bind:src,且路径需要用require包裹(Vue2)或import引入(Vue3),否则会出现404。

问题4:为什么<base>标签的href能影响整个页面的相对路径?

答:<base>标签的href是页面所有相对路径的“基准地址”。比如设置<base href="https://www.example.com/page/">后,页面中所有的相对路径(比如<img src="pic.jpg">)都会被解析为https://www.example.com/page/pic.jpg。这是href的“全局关联”特性,它不引入资源,只定义路径规则,所以<base>只能用href不能用src

结尾:你踩过最离谱的src/href的坑是啥?

写到这里,关于srchref的知识点就全讲完了。从凌晨改bug的崩溃,到浏览器的处理机制,再到面试回答技巧,希望这些内容能让你下次遇到这俩属性时,不再头大。

其实前端开发就是这样,很多基础知识点看着简单,实际用起来全是细节。就像srchref,懂了是“理所当然”,不懂就是“天坑不断”。

别忘了点赞+收藏,下次遇到类似问题,直接翻出来看——毕竟好记性不如烂笔头,好文章不如常回顾~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端布洛芬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值