
1. 从零搭起一个页面骨架DOCTYPE、html、head 与 body很多刚接触前端的人打开编辑器第一件事就是噼里啪啦敲标签敲了半天发现页面显示一团乱麻中文变成乱码、样式怎么都加载不出来、浏览器提示“奇怪的字符”。我见过太多新手栽在这些基础问题上所以咱们不开篇讲什么高深理论先把一段最基础的 HTML 骨架摆出来对照着说清楚每一行的作用。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的第一个页面/title /head body !-- 页面可见内容都写在这里 -- /body /html第一行!DOCTYPE html是文档类型声明放在所有代码的最顶部告诉浏览器“我这个页面用的是 HTML5 规范”。别看它不起眼少了这一行浏览器可能会进入“怪异模式”导致盒模型计算方式改变、CSS 样式各种错乱。第二行html langzh-CN是根元素lang属性声明页面语言是简体中文这对屏幕阅读器、翻译插件和搜索引擎都很有意义。你写英文页面就写langen这个习惯越早养成越好。head区域存放的是页面的“元信息”用户看不见但对浏览器和搜索引擎极其重要。meta charsetUTF-8这行必须放最前面它决定了浏览器用什么编码来解码这个文件。我遇到很多“中文变乱码”的求助九成都是忘记写这行或者写成了GBK而文件实际是 UTF-8 保存的。meta nameviewport是移动端适配的关键让页面宽度跟随设备宽度并且初始缩放比例为 1写 H5 页面没这行手机上显示的效果会非常糟糕。title里的内容会显示在浏览器标签页上同时也是 SEO 的重要权重因素。body才是用户能看到的一切内容的容器。我个人的习惯是写任何页面都先把这段骨架敲出来再往 body 里填内容。这就是所谓的“HTML 基础必备标签”的核心——不是让你背多少个标签而是让你理解文档结构是怎么组织起来的。1.1 meta 标签的两个高频用法meta是个自闭合标签没有闭合标签作用是通过属性来提供页面的元数据。除了上面提到的 charset 和 viewport还有两个场景你一定会用到。一个是关键词和描述早期 SEO 常用meta namekeywords contentHTML, H5, 标签教程 meta namedescription content从零开始学习HTML基础标签涵盖HTML5新增语义化标签和表单控件另一个是页面跳转比如有的场景需要做一个临时的活动入口页自动跳转到主页面meta http-equivrefresh content5;urlhttps://example.com这行的意思是 5 秒后自动跳转到指定网址。当然现代开发中这种整页自动跳转更推荐用 JS 实现但 meta 方式依然有它的使用场景比如纯静态页面的应急处理。1.2 为什么说注释和缩进也是“必备标签”注释虽然不算标签但它在 HTML 中的地位绝不亚于任何标签。HTML 里用!-- 注释内容 --来写注释浏览器不会渲染它但看代码的人会。我第一次维护别人写的页面时看到一屏密密麻麻的 div 嵌套没有缩进、没有注释捋了半小时才搞清楚层级关系。从那以后我写 HTML 一定会注意两点标签嵌套必须缩进对齐关键块级区域必须加注释说明。这是给自己省时间也是在给后来接手的人留活路。2. 文本与结构标签h1 到 p、a、img 这些“日用品”一个页面 80% 的内容是文字和图片。这块的标签用好了页面结构清楚SEO 也会更友好。先说标题标签h1到h6一共六级从大到小表示内容的重要性和层级。很多新手有个误区觉得 h1 字号太大不好看于是把标题文字直接写在div或者span里面再用 CSS 把字号调大。这样做页面视觉效果没区别但搜索引擎爬虫和屏幕阅读器读到的就是“一堆没有层级结构的文字”内容的重要性完全体现不出来。正确做法是用h1~h6标记内容层级再用 CSS 去覆盖它的默认样式视觉上长什么样完全由 CSS 说了算。一个页面理论上只应该有一个h1一般放站点名称或当前页面的核心标题。新闻详情页就放新闻标题首页就放网站名。如果页面上出现了多个h1虽然不会报错但对 SEO 并不友好。下面的层级结构应该有所递进h2 是板块标题h3 是二级小标题以此类推且最好不要跳级使用比如从 h2 直接跳到 h5。段落标签p前面经常被误用。它的语义是“一段文字”属于块级元素默认占满整行段与段之间有垂直间距。新手需要注意p里面不能嵌套块级元素比如pdivxxx/div/p这种写法是不符合规范的浏览器解析时可能会自动断开导致结构错乱。行内元素比如span、a、img、strong放在p里面是没问题的。2.1 a 标签链接不只是“能点就行”a标签算是 HTML 里最常用的行内标签之一了它的核心属性有href链接地址、target打开方式和title鼠标悬停提示。最基本的用法就是a hrefhttps://www.example.com访问示例网站/a这里要注意外部完整网址必须写https://前缀否则浏览器会把它当成相对路径去解析。比如你写hrefwww.example.com浏览器会在当前域名下找www.example.com这个文件结果当然是 404。内部页面之间的跳转写相对路径就行比如hrefabout.html。target_blank表示在新窗口打开链接这是大家搜得很多的一个需求。但你可能没注意的是纯静态页面用_blank会有个安全隐患——新打开的页面可以通过window.opener操作原来的页面。解决方法是加上relnoopener noreferrera hrefhttps://www.example.com target_blank relnoopener noreferrer新窗口打开/a我做项目时只要涉及_blank必定带上relnoopener noreferrer这是从业者之间心照不宣的规范。还有一种情况你希望点击链接不跳转、只执行 JavaScript 操作。这时可以把href写成javascript:;或#。用#会跳转到页面顶部且 URL 会多一个烦人的#符号用javascript:void(0);最干净既不跳转也不改变 URL。不过现在更推荐直接用button元素配合 JS 事件来承载交互功能链接就该去做链接的活按钮就该去做按钮的活。2.2 img 标签一个 src 和 alt 就能看出专业度图片标签img是自闭合标签不需要写闭合标签。核心属性有src图片路径、alt替代文本、width/height宽度和高度。alt属性经常被忽略但它非常重要图片加载失败时显示的就是它搜索引擎主要也是靠它来识别图片内容。辅助读屏器会一字一句地把 alt 里的文字读给视障用户听。所以 alt 的写法也有讲究不能写一句堆砌关键词的废话而是用自然语言描述图片内容。比如img srcphoto.jpg alt团队在2024年年会上举杯庆祝的照片图片路径是初学者踩坑重灾区。相对路径、绝对路径、根目录路径要清楚区分。images/logo.png是相对当前文件的images目录去找/images/logo.png是从站点根目录去找https://xxx.com/images/logo.png是绝对路径直接从网络地址加载。H5 项目部署到不同环境时路径写错了图片就全挂。我的建议是项目内资源一律用相对路径避免部署到子目录时出问题。width和height可以写在 HTML 里也可以写在 CSS 里。区别在于写在 HTML 里浏览器解析时会预留对应空间能有效避免图片加载过程中页面内容跳动只写一个值时另一个值会自动等比缩放。不过现在响应式布局场景更多用 CSS 来控制图片尺寸HTML 属性更多用于固定尺寸的图标类图片。2.3 列表标签ul、ol、li 的大用途列表标签经常被低估但它其实特别实用。无序列表ul里的每一项是li适合导航菜单、功能列表、商品陈列这类没有先后顺序的场景。有序列表ol的每一项会自动显示序号适合操作步骤、排行榜、文档目录这类有顺序的内容。在实际项目中导航菜单几乎清一色是用ul li a的结构来写的然后通过 CSS 去掉默认的圆点和缩进。这种写法不只是语义正确也方便后续增加交互效果和响应式布局。还有一个容易被忽略的用法dl、dt、dd是描述列表适合做图文配对展示比如商品参数“品牌xxx”“尺寸xxx”比表格更贴近语义化。2.4 换行、分割线和无语义标签br、hr、div、span 的正确打开方式br是换行标签在文字中强制换行比如写一段古诗、分行地址。但注意它不应该用来做段落之间的距离那是margin的职责。hr是水平分割线在语义上表示“主题切换”比如一篇文章上下两段讲的是不同话题中间可以加一条hr。虽然它默认显示为一条横线但别把它当纯装饰线用装饰线请交给 CSS 的border来做。div和span是 HTML 里最特殊的一对它们没有任何语义就是个纯粹的“容器”。div 是块级容器默认占满整行span 是行内容器宽度由内容决定。它们的作用是配合 CSS 和 JavaScript 实现布局与交互。理论上任何页面都能用 div 写出来但如果整个页面全是 div那就是俗称的“div 地狱”可读性和 SEO 都会得病。所以正确的思路是优先用有语义的标签header、nav、article、section、footer实在没有合适语义的再用 div 和 span。3. 表格标签table、tr、td 与 colspan 合并的实操讲解表格标签在“ divCSS 布局”成为主流后它作为页面布局工具已经被淘汰了但作为数据展示工具依然不可或缺。其核心结构是table表格、tr行、td单元格、th表头单元格。一个最基础的带表头的表格长这样table border1 tr th姓名/th th年龄/th th城市/th /tr tr td张三/td td25/td td北京/td /tr tr td李四/td td30/td td上海/td /tr /tableth和td的区别不只是加粗和居中更重要的是语义th 表示表头搜索引擎和无障碍设备会把它当作表格的“列标题”来对待。表格里还有一个caption标签可以描述表格主题相当于给表格加个标题这个对 SEO 和无障碍都有帮助。现在项目里的表格通常还需要一个thead和tbody结构——前者包裹表头行后者包裹数据行。这样做的好处是浏览器解析时可以在数据很多的情况下分批渲染CSS 写样式时也能针对性操作。写法和上面的例子统一后加一层即可table caption员工信息一览表/caption thead tr th姓名/th th年龄/th /tr /thead tbody tr td张三/td td25/td /tr /tbody /table3.1 colspan 和 rowspan 的合并规则单元格合并是我被问到最多的问题之一。colspan是水平合并即一个单元格跨多列rowspan是垂直合并即一个单元格跨多行。理解合并有一个关键点合并后这一行里其他单元格的数量会相应减少。举个例子一张课程表星期一上午有两节课合在一起table border1 tr th时间/th th星期一/th th星期二/th /tr tr td上午/td td colspan2数学课/td /tr tr td下午/td td语文/td td英语/td /tr /table上面的表格第一行有 3 列时间、星期一、星期二。第二行上午这一行只用了一个 td但它 colspan 为 2所以实际占了两列这一行里的单元格总数是 2“上午”“数学课”列数依然对应为 3。这里容易出错的点是误以为合并后还要保持原来的单元格数量于是多写了一个 td导致表格被额外撑出一列。记住规则合并是“实际占据多列”不是“删掉其他 td”。rowspan 的用法类似但要注意它跨的是“行”所以受影响的是下一行的单元格数量。我的建议是遇到复杂的合并表格先在纸上画网格数清楚每一行实际需要几个单元格再动手写 HTML能省大量调试时间。还有一点值得提醒别再用table去搭页面布局。手机端自适应、复杂的层叠效果、响应式改版用表格布局都会变得极其痛苦。CSS Grid 和 Flexbox 在布局上的能力远超表格表格就老老实实用来展示格式化数据。这句话我在真实项目中验证过无数次。3.2 表单标签form 与 input 的“一见钟情”表单是 HTML 中交互性最强的部分一切需要用户输入信息的功能——登录、注册、搜索、留言——都离不开它。基础结构是form actionsubmit.php methodpost label forusername用户名/label input typetext idusername nameusername placeholder请输入用户名 br label forpassword密码/label input typepassword idpassword namepassword br button typesubmit登录/button /formform的action属性是表单提交到的地址method是提交方式常见的有get数据拼在 URL 后面适合搜索和post数据放在请求体里适合涉及隐私和内容较多的场景。不过现代前端开发中纯表单提交已经不太常见了更多人通过 JavaScript 拦截提交事件再用fetch或axios异步发送数据。但基本的 form 结构你依然得懂因为它是浏览器原生能力很多场景比 JS 方案更可靠。表单内部永远记住一个原则每个输入框都要用label标签来关联说明文字。label的for属性要填对应输入框的id这样点击“用户名”三个字时光标会自动聚焦到输入框里。这对鼠标操作不精准的人、触屏设备和无障碍访问都是刚需。不用 label 直接摆一行文字虽然看起来一样但缺失了这层关联交互体验就打了折扣。placeholder是输入框里的占位提示文字输入内容后自动消失。有一个坑大家要留意placeholder不能替代label。很多移动端页面设计得比较简洁只有一个输入框而没有文字标签只靠 placeholder 提示“请输入用户名”。这在视觉上干净但问题在于 placeholder 一输内容就没了用户如果忘了要填什么又得清空才知道无障碍上也有缺陷。规范的写法是保留 label只是用 CSS 把它“视觉隐藏”掉——这也是我写表单页面一直坚持的细节。3.3 input 的常用 type 属性对比input 标签的type属性决定了它的形态和行为HTML5 时代后这个家族已经非常庞大了。我这里把实际项目中最常用的几个整理成表格方便你对照着记type 值作用适用场景注意事项text单行文本输入用户名、搜索关键词最通用不加 type 默认就是它password密码输入登录、注册输入内容会显示为圆点email邮箱地址输入邮箱注册移动端会弹出带的键盘浏览器会做格式校验number数字输入数量、价格移动端会弹出数字键盘但不能完全替代自定义校验tel电话输入手机号移动端弹数字键盘date日期选择器生日、预约日期各浏览器弹的日历样式不同color颜色选择器自定义主题色原生弹出的取色器样式比较简陋file文件上传头像上传、附件上传结合 accept 属性可限制文件类型checkbox多选复选框兴趣爱好、同意条款多个 checkbox 用相同的 name 组成一组radio单选按钮性别、支付方式同组的 radio 必须 name 相同且只能选一个range滑块选择音量、评分拖动滑块实时取值要靠 JS 监听submit提交按钮提交表单value 属性可以改显示文字button普通按钮配合 JS 使用写在 form 内还必须设 typebutton否则会当 submit这里特别提醒两个工作中容易出的幺蛾子。第一个input标签不加type默认就是text很多新手以为不加 type 是报错其实不会但建议永远显式写出来方便别人阅读。第二个typesubmit的按钮放在 form 里点击就会触发表单提交并刷新页面如果你只是想用 JS 处理点击事件而不想提交记得加typebutton——这件事无数人踩过坑包括我自己。3.4 select、textarea、button 的使用心得下拉选择框select的语法是select namecity idcity option valuebeijing北京/option option valueshanghai selected上海/option option valueguangzhou广州/option /selectoption里加selected表示默认选中项value是提交给后端或 JS 拿到的真实值。如果希望做成可以输入搜索的下拉框纯原生 select 做不到一般用第三方组件库比如 Element Plus、Ant Design 里的 Select 组件但底层的 name/value 思想是一样的。多行文本textarea可以理解为能多行输入的大号文本框用在留言板、评论、自我介绍这种场景。它有rows和cols属性控制显示行数列数但更常用的是通过 CSS 的width、height去控制尺寸。注意textarea是成对标签内容写在开闭标签之间比如textarea这里显示默认内容/textarea它不像 input 那样用 value 存内容别写岔了。button标签比用input typebutton更灵活因为它内部可以放图标、加粗文字甚至其他 HTML 内容。凡是需要复杂按钮样式的场景我基本都用 button 标签。4. HTML5 新增语义化标签header、nav、main、article 到底怎么用HTML5 最大的变化之一就是带来了一批“语义化标签”目标是让页面结构像文章的章节一样清晰。所谓语义化就是标签的名称本身就表达它的用途。这些新标签出现之前大家写页面凡是区域就用 div比如div classheader div classnav div classmain div classfooterclass 名称是自己约定的不同项目风格能差出十万八千里。HTML5 直接把这些结构固化成标签浏览器、搜索引擎、开发人员看到header就知道是页头看到nav就知道是导航结构一目了然。新标签常用的有这些body header网站页头logo、站点名/header nav主导航菜单/nav main article h2文章标题/h2 p文章正文/p /article aside侧边栏广告、友情链接/aside /main footer页脚版权信息、联系方式/footer /bodyheader是页头放置站点 logo、标语nav是导航区域放菜单链接main是页面主体内容区域一个页面建议只有一个article是独立成文的内容块比如一篇博客、一个产品卡片section是对内容的主题分区使用时要配合标题使用aside是跟主体内容相关但可独立存在的侧边内容footer是页脚放版权和联系方式。4.1 article 和 section 的选择逻辑这两个标签经常被混淆。我提供一个判断思路article强调“独立性和完整性”意思是这部分内容拎出来也能单独成立。一篇文章、一条新闻、一个评论、一个产品封面卡片都是典型的 article。而section强调“对一段区域的主题分区”通常内容被包裹在 article 内部或者页面主体区域内部比如文章里的“第一章”“第二章”或者一个详情页拆成“基本信息”“买家评价”“售后服务”这几个区块每个区块都可以用 section。还有一点section 里一般要有标题h2、h3 均可不然它跟一个普通 div 几乎没有差别。反过来说如果你只是想包一层用于布局的容器不需要任何语义含义直接用 div 就好不要为了“语义化”而硬塞 section那样反而是过度设计。我见过不少项目为了语义化把一屏布局里的一列列卡片全部包成section看起来好像很规范检索时却发现每个 section 里面根本没有标题反而是 div 更贴切语境。语义化是个好习惯但不能走火入魔核心标准永远是“这个标签的语义跟内容匹配吗”。4.2 header 和 footer 的扩展用法header并不是只能用作页面页头。一个 article 内部也可以有自己的 header——文章标题、作者信息、发布时间放进去就很合适。同理footer也不只是页脚一个 article 可以有它自己的 footer用来放“阅读全文”“分享到朋友圈”这类操作区域。HTML5 语义标签是“可以嵌套”的这一点很少有人提但其实非常实用。4.3 其他实用 H5 标签figure、mark、time、progress除了大头部的结构标签HTML5 还带来了一批细节层面的好工具figure是“插图或图表独立容器”里面放图片、图表、代码块配合figcaption写图注。这样图跟说明就能绑定在一起而不是图片下面随手写个段落文字。figure img srcchart.png alt2024年营收趋势图 figcaption图12024年各季度营收趋势/figcaption /figuremark表示高亮标记文字默认带黄色背景适合搜索结果的关键词高亮、文章重点句提示。time表示时间datetime属性可以写精确到秒的机器可读时间利于搜索引擎读懂时间信息。progress是进度条显示任务的完成进度原生自带样式适合做上传进度、问卷完成度这类可视化。这些标签单个看起来都很小但组合在一起使用页面的语义完整度会上升一个维度这也是 HTML5 时代和 2010 年之前页面之间的本质差别。5. HTML5 多媒体标签audio 和 video 的调用细节以前在网页里放视频是件麻烦事要写 object、embed还要处理不同浏览器的兼容。HTML5 带来了video和audio这两个原生多媒体标签直接通过 src 引入视频/音频文件就能播放。最基础的 video 写法video srcmovie.mp4 controls/videocontrols属性让浏览器显示自带的播放控件包括播放键、进度条、音量。如果不写视频画面会显示但不出现控件用户无法播放这是新手经常会“踩”的坑——以为视频坏了其实只是没加 controls。常见的属性还有autoplay自动播放、loop循环播放、muted默认静音、preload预加载模式、poster设置视频封面图。移动端浏览器的自动播放政策比较严格很多浏览器要求“必须静音才能自动播放”所以如果你的页面想在微信里打开时自动播放视频常规做法是同时加上autoplay muted并把playsinline也加上防止 iOS 上自动全屏播放。为了适配不同格式video 标签还会配合source子标签使用video controls source srcmovie.webm typevideo/webm source srcmovie.mp4 typevideo/mp4 您的浏览器不支持 video 标签。 /video浏览器会按顺序尝试第一个能播放的格式就采用如果都不支持就显示内部那段提示文字。audio标签的用法和 video 完全一样只是没有画面和 poster 属性适合放背景音乐、语音消息、播客等。我自己的习惯是只要是媒体资源尽量指定preloadmetadata这样页面加载时只获取媒体信息而不下载完整文件首屏速度会有明显提升。6. HTML5 新增表单控件从 type 到 input 的高级玩法HTML5 对表单的增强是革命性的很多以前要用 JavaScript 才能完成的校验现在原生属性直接就能做。这是搜索热词“HTML5新增表单标签”底下最值得展开的内容。先看几个新 typeinput typeemail nameemail placeholderyouexample.com required input typeurl nameurl placeholderhttps://example.com input typetel nametel placeholder请输入手机号 input typenumber namequantity min1 max10 step1 input typedate namebirthday input typecolor namethemeColor value#ff0000 input typerange namevolume min0 max100 input typesearch namekeyword placeholder搜索...typeemail在提交时浏览器会自动检查格式是否合法required表示必填项没填就提交时浏览器会给出提示并阻止提交。typenumber配合min、max、step可以限制数字范围和步进值比如数量选择 1 到 10 步进 1。typedate会自动弹日历。这些都是原生能力不用引入任何前端框架或插件。还有一些更便于无障碍的表单新属性placeholder输入提示autofocus页面加载后自动聚焦到该控件pattern用正则表达式校验输入内容比如手机号验证pattern1[3-9]\d{9}disabled禁用控件提交时这项数据不会包含readonly只读值可以提交但不能编辑patter 属性有个典型的坑它只对文本框类型有效对number等类型是无效的。另外不同浏览器对 pattern 校验的触发时机不一样有的在输入时就给提示有的在提交时才验证。我一般把它当第一道防线真正的业务校验仍然交给 JS 逻辑把关。还值得一提的是datalist标签它给 input 提供“可输入的候选列表”效果。比如搜索框想要联想词input typetext listbrowsers datalist idbrowsers option valueChrome option valueFirefox option valueEdge /datalist用户既可以直接输入自定义内容也可以从列表中选择。这类“半受控”的下拉联想在某些轻量场景可以完全替代引入一个完整的组件库代码量少而且加载快。7. 旧浏览器兼容问题与工程化小建议HTML5 标签虽然好用但也要面对现实老的浏览器特指 IE8 及更早版本不认识这些新标签在它们眼里header就是“未知元素”默认不显示为块级而且样式也会丢失。虽然现在的项目基本已经不再兼容 IE 这个级别的老古董但如果你负责的网站用户群体里还有少量低版本浏览器备一手方案总是值得的。历史上有两个经典方案。一个是引入html5shiv.js这个补丁脚本它用 JavaScript 创建这些新元素让老浏览器认识它们然后配合 CSS 里给这些新标签统一设置display: block。另一个更纯粹直接用 CSSheader, nav, main, article, section, aside, footer, figure, figcaption { display: block; }让未知元素以块级盒展示大部分布局都不受影响了。现在你写页面大概率不需要处理这么老的环境但知道这条路在哪里面试时被问到“HTML5新标签在老浏览器中怎么兼容”你就能答出 html5shiv、CSS display 设置这两件套。工程化建议方面有人说 HTML 很简单不需要工具链。但真实项目里尤其是 H5 页面我依然建议做好三件事文件组织规范、代码格式化、浏览器兼容检查。文件组织上一个 H5 项目最常见的方式是根目录下index.html作为首页css/放样式文件js/放脚本文件images/放图片资源。图片资源命名用英文小写加连字符比如banner-main.png不要用中文名和含空格的命名——这些在服务端部署时很容易出问题。代码格式化方面如今前端项目普遍接入 Prettier 或格式化插件统一缩进、引号、换行风格。如果你用的是 VSCode装上 Prettier 插件并设置为保存时自动格式化HTML 文件会自动帮你缩进对齐省心很多。浏览器兼容检查上开发完要分别用 Chrome、Safari、移动端微信内置浏览器各过一遍。HTML5 中有些新控件比如 date、color在不同浏览器里的长得完全不一样iOS Safari 的日期选择器跟 Chrome 的也是两套交互这些都要在实际设备上检查才心里有底。我个人还有一个习惯页面上线前会拿 Chrome 的手机模拟器过一遍首屏渲染确认没有横向滚动条、字体大小正常、表单控件可用。这一步往往能提前拦下一批问题。8. 常见问题与排查技巧实录积累了一批好问题这一节专门做速查式整理基本覆盖我这些年遇到的高频选手。8.1 中文显示为乱码怎么办先确认文件保存编码是不是 UTF-8不同编辑器显示方式不同VSCode 右下角会直接显示当前编码。然后在head最前面检查是否有meta charsetUTF-8且它必须出现在任何包含中文的内容之前。如果页面是静态 HTML把这两点改掉九成能解决。如果是从数据库渲染的页面那还要检查服务端返回的响应头里Content-Type的 charset 配置。8.2 图片不显示直接裂开先看路径。打开的页面地址如果是https://a.com/demo/index.html页面里写srcimages/logo.png浏览器会去https://a.com/demo/images/logo.png找文件如果实际文件在https://a.com/images/logo.png在根目录下就得改成src/images/logo.png。如果网络图片跨域了有时加crossorigin属性可以解决但不保证所有服务器都支持返回正确响应头。在对图片进行调试时建议先在浏览器地址栏直接访问图片 URL能打开说明路径没问题不能打开就检查目录结构和文件名的大小写——一些服务器是区分大小写的。8.3 a 标签点击没反应最常见原因是href里少了https://前缀被当成相对路径处理。其次可能是 href 里面写了javascript:void(0);但没有绑定点击事件。还有一种情况是target_blank被浏览器的弹窗拦截策略拦了——通过脚本触发的跳转window.open()才容易被拦截原生a target_blank一般不会但如果是通过 JS 模拟点击事件触发的就要留意浏览器策略了。8.4 表单校验不生效先看 input 的type和required写没写对。required是布尔属性直接写required就好不用写requiredtrue。另外浏览器只在表单提交时才会执行原生校验如果你用 JSsubmit()方法提交也会触发校验但如果是在 JS 里用 fetch 异步提交而不带表单的 submit 事件原生校验就不对有效路径执行了。这种情况可以调用form.checkValidity()手动触发校验。8.5 audio 和 video 不自动播放这里是浏览器策略的硬限制。桌面 Chrome 和移动端微信都要求“有用户交互后才能播放带声音的媒体”常见解法是autoplay muted组合静音自动播放会被放行或者把playsinline属性加上iOS Safari 才不强制全屏播放。真要在用户点击后才播放再解除静音的话可以监听点击事件再调用 play() 方法。8.6 表格的边框为什么总是对不齐或者出现双线旧版 HTML 里给 table 直接写border1浏览器默认渲染的是双线边框。现在推荐做法是在 CSS 里设置table { border-collapse: collapse; }border-collapse: collapse会把相邻单元格的边框合并成一条线整个表格看起来干净利落。这个属性新人不熟悉很常见属于“知道一个值少折腾半小时”的 CSS 知识点。8.7 H5 页面在微信里打开样式错乱优先检查meta nameviewport有没有写。没写的话手机上会用默认的 980px 宽度渲染页面整体会显得特别小看起来像缩放了。其次留意 iOS 上input的默认外观需要加-webkit-appearance: none来去除系统默认样式否则 iOS 的 input 会有一层灰色背景跟设计稿对不上。做 H5 页面时这两条我几乎每条都写在项目的全局样式里。9. 我的一点实操体会写 HTML 标签这件事看起来是谁都会的基本功但在实际项目里我发现真正决定页面质量上限的往往不是“会不会某个标签”而是“能不能选择那个语义上最贴切的标签”。同一个视觉效果用 div 套娃能实现用 header、article、footer 结构化也能实现。前者写着爽三个月后自己回来看都要花时间捋层级关系后者清晰得像书目录哪怕团队里的新人接手也能秒懂页面结构。我刚入行那会儿总觉得学了 CSS 才能做页面HTML 只是一个壳。后来做了越来越多页面、接了几次别人写的页面以后才意识到扎实的标签功底才是前端的“卧室里的床”其他一切都是在这张床上往上搭。现在每次写页面我仍然会在开始动手前花两分钟想清楚整个页面的信息层级哪些区域是独立的文章哪些只是装饰容器导航要不要用 nav图片说明要不要用 figure这些思考成本极低但回报贯穿整个开发流程。HTML 的东西不难但它特别琐碎。一张长文讲不完也不该指望看一遍就全记住。更现实的做法是把这篇博客收藏起来当作一个随时可以翻的工具页哪天遇到一个标签忘了怎么用回来查一眼遇到一个属性不确定打开浏览器的开发者工具实测一下。标签这个东西用一次记住一次用十次想忘都忘不掉。这篇我会持续更新后面遇到更多值得记录的 HTML 和 H5 细节比如响应式图片的 srcset、开放图谱 meta、更多新表单控件的踩坑案例我会陆续往里面补充。也建议你自己维护一份类似的“标签笔记”哪怕只有几行字积少成多以后就是你最顺手的前端参考书。