【HTML 中 33 个全局属性(global attributes)的图文详解 】

全局属性

  • [全局属性(global attributes)](#全局属性(global attributes))
    • [基本的全局属性 (表格)](#基本的全局属性 (表格))
    • [1. accesskey 属性:键盘快捷键 ⇒ 聚焦元素上、激活元素(属性值:单个键盘字符;容易和浏览器、系统的快捷键冲突)](#1. accesskey 属性:键盘快捷键 ⇒ 聚焦元素上、激活元素(属性值:单个键盘字符;容易和浏览器、系统的快捷键冲突))
    • [2. autocapitalize 属性:字母的自动大写(用于:移动设备的虚拟键盘;属性值:不自动大写:off、none;句子的首字母大写:on、sentences;单词的首字母大写:words;所有字母大写:characters;Safari 桌面端不支持)](#2. autocapitalize 属性:字母的自动大写(用于:移动设备的虚拟键盘;属性值:不自动大写:off、none;句子的首字母大写:on、sentences;单词的首字母大写:words;所有字母大写:characters;Safari 桌面端不支持))
    • [3. autocorrect 属性:自动更正 ⇒ 单词自动纠错 (枚举属性;移动端虚拟键盘;属性值:启用自动更正:on;禁用自动更正:off;仅 Safari、Firefox 支持)](#3. autocorrect 属性:自动更正 ⇒ 单词自动纠错 (枚举属性;移动端虚拟键盘;属性值:启用自动更正:on;禁用自动更正:off;仅 Safari、Firefox 支持))
    • [4. autofocus 属性:自动聚焦⇒ 直接开始输入、无需手动聚焦(布尔属性)](#4. autofocus 属性:自动聚焦⇒ 直接开始输入、无需手动聚焦(布尔属性))
    • [5. class 属性: 元素的类名、可多元素共享的标识符(多值:空格分隔;CSS:多元素 相同样式、一个元素多个样式)](#5. class 属性: 元素的类名、可多元素共享的标识符(多值:空格分隔;CSS:多元素 相同样式、一个元素多个样式))
    • [6. contenteditable 属性:元素是否可被编辑 ⇒ 直接与页面内容交互 (枚举属性;属性值:可被编辑: true;不可被编辑:false;纯文本可被编辑、富文本格式被禁用:plaintext-only)](#6. contenteditable 属性:元素是否可被编辑 ⇒ 直接与页面内容交互 (枚举属性;属性值:可被编辑: true;不可被编辑:false;纯文本可被编辑、富文本格式被禁用:plaintext-only))
    • [7. data-* 属性:嵌入"自定义数据"(命名:全小写字母、连字符分隔;不存隐私信息;HTML → JavaScript:烤串变驼峰,data-*→ dataset.小大大大...首字母大写)](#7. data-* 属性:嵌入“自定义数据”(命名:全小写字母、连字符分隔;不存隐私信息;HTML → JavaScript:烤串变驼峰,data-*→ dataset.小大大大...首字母大写))
    • [8. dir 属性:设置文本的方向 ⇒ 文本的排列起点、方向(枚举属性;属性值:从左到右:ltr;从右到左:rtl;浏览器自动决定/ 第一个强方向字符:auto;多语言网站)](#8. dir 属性:设置文本的方向 ⇒ 文本的排列起点、方向(枚举属性;属性值:从左到右:ltr;从右到左:rtl;浏览器自动决定/ 第一个强方向字符:auto;多语言网站))
    • [9. draggable 属性:设置元素是否"可拖拽" (枚举属性;可拖动:true;不可拖动:false;浏览器默认行为/默认值:auto;默认可拖动,图链选中文)](#9. draggable 属性:设置元素是否“可拖拽” (枚举属性;可拖动:true;不可拖动:false;浏览器默认行为/默认值:auto;默认可拖动,图链选中文))
    • [10. enterkeyhint 属性:给移动设备"虚拟键盘"⇒ "回车键"提供一个视觉提示 只改样式、不改功能;属性值:插入新行(回车键):enter;关闭虚拟键盘(完成、√):done;跳转:go;下一个输入框(下一步):next;上一个输入框:previous;看搜索结果(搜索):search;发送:send;](#10. enterkeyhint 属性:给移动设备“虚拟键盘”⇒ “回车键”提供一个视觉提示 [只改样式、不改功能;属性值:插入新行(回车键):enter;关闭虚拟键盘(完成、√):done;跳转:go;下一个输入框(下一步):next;上一个输入框:previous;看搜索结果(搜索):search;发送:send;])
    • [11. exportparts 属性: 导出 part 的名称、允许外部访问 "内部 shadow 的指定 part" ⇒ 给 "影子树内部 嵌套的影子树"的元素 设置样式(属性值:影子树的 part 属性值,逗号分隔;用于:多层 shadow DOM)](#11. exportparts 属性: 导出 part 的名称、允许外部访问 “内部 shadow 的指定 part” ⇒ 给 “影子树内部 嵌套的影子树”的元素 设置样式(属性值:影子树的 part 属性值,逗号分隔;用于:多层 shadow DOM))
    • [12. hidden 属性:隐藏元素 ⇒ 不显示内容(枚举属性;隐藏不显示:hidden、空值、无效值、无值/仅属性名;hidden="hidden" ⇔ display: none ;不参与布局;查访时才显示内容/内外边距等不隐藏:until-found; hidden="until-found" ⇔ content-visibility: hidden;参与布局)](#12. hidden 属性:隐藏元素 ⇒ 不显示内容(枚举属性;隐藏不显示:hidden、空值、无效值、无值/仅属性名;hidden="hidden" ⇔ display: none ;不参与布局;查访时才显示内容/内外边距等不隐藏:until-found; hidden="until-found" ⇔ content-visibility: hidden;参与布局))
    • [13. id 属性:元素在文档中"唯一的标识符"、身份证号 ⇒ 找到唯一对应的元素(属性值:命名建议 ⇒ 字数连下划,字母开头语义化,见文知其意)](#13. id 属性:元素在文档中“唯一的标识符”、身份证号 ⇒ 找到唯一对应的元素(属性值:命名建议 ⇒ 字数连下划,字母开头语义化,见文知其意))
    • [14. inert 属性:彻底冻结整个区域、完全不可交互 ⇒ 禁用元素及其所有子元素 ⇒ 不参与"任何用户交互" ⇒ 无法选中/点击/聚焦/搜索到、无法被 tab 键访问、屏幕阅读器不朗读(布尔属性;默认无样式,设置不透明度 opacity 提示被禁用)](#14. inert 属性:彻底冻结整个区域、完全不可交互 ⇒ 禁用元素及其所有子元素 ⇒ 不参与“任何用户交互” ⇒ 无法选中/点击/聚焦/搜索到、无法被 tab 键访问、屏幕阅读器不朗读(布尔属性;默认无样式,设置不透明度 opacity 提示被禁用))
    • [15. inputmode 属性: 提示输入的数据类型(输入模式) ⇒ 显示对应的"虚拟键盘"、优化输入体验(枚举属性;移动端有效;仅改键盘显示、不限数据类型)](#15. inputmode 属性: 提示输入的数据类型(输入模式) ⇒ 显示对应的“虚拟键盘”、优化输入体验(枚举属性;移动端有效;仅改键盘显示、不限数据类型))
    • [16. is 属性:"自定义内置元素"⇒ 让普通 HTML 标签拥有"自定义元素的功能、样式" (Safari 不支持;is="自定义元素的名称";代码复用)](#16. is 属性:“自定义内置元素”⇒ 让普通 HTML 标签拥有“自定义元素的功能、样式” (Safari 不支持;is="自定义元素的名称";代码复用))
    • [17. itemid 属性:微数据项的"全球唯一的标识符"(3属性搭配、全球唯一:必须同时设置 itemscope、itemtype 指明数据项的作用范围、具体类型;单独设置无效 ;属性值:itemid="url / urn 统一资源名称")](#17. itemid 属性:微数据项的“全球唯一的标识符”(3属性搭配、全球唯一:必须同时设置 itemscope、itemtype 指明数据项的作用范围、具体类型;单独设置无效 ;属性值:itemid="url / urn 统一资源名称"))
      • [结构化数据:schema.org 术语表词典、微数据 、JSON-LD(关联数据/链接数据:机器看的"数据说明书")](#结构化数据:schema.org 术语表词典、微数据 、JSON-LD(关联数据/链接数据:机器看的“数据说明书”))
    • [18. itemprop 属性:属性名/标准词汇名称、贴标签、数据项的"具体属性"⇒ "名称-值"对的名称( itemprop 属性值="Schema.org 的标准词汇"= 根据 itemtype 具体类型;值 = 字符串、url;父元素中:必须有 itemscope、itemtype ⇒ 指明数据项范围、具体类型)](#18. itemprop 属性:属性名/标准词汇名称、贴标签、数据项的“具体属性”⇒ “名称-值”对的名称( itemprop 属性值=“Schema.org 的标准词汇”= 根据 itemtype 具体类型;值 = 字符串、url;父元素中:必须有 itemscope、itemtype ⇒ 指明数据项范围、具体类型))
    • [19. itemref 属性:被点名的元素 也是我的属性 ⇒ 引用元素 id、关联"外部属性" ⇒ 同一个数据项的多个属性,不必放在一个父元素下(微数据;属性值:itemref="id 值/ 多值空格分隔";必须搭配:itemscope、itemtype )](#19. itemref 属性:被点名的元素 也是我的属性 ⇒ 引用元素 id、关联“外部属性” ⇒ 同一个数据项的多个属性,不必放在一个父元素下(微数据;属性值:itemref="id 值/ 多值空格分隔";必须搭配:itemscope、itemtype ))
    • [20. itemscope 属性: 数据项的作用范围 ⇒ 该标签内的内容是"一个数据项",包括后代(布尔属性)](#20. itemscope 属性: 数据项的作用范围 ⇒ 该标签内的内容是“一个数据项”,包括后代(布尔属性))
    • [21. itemtype 属性:数据项类型 = "词汇表的url" (属性值:itemtype = "schema.org 词汇表的具体类型 URL";搭配 itemscope、itemprop 使用)](#21. itemtype 属性:数据项类型 = “词汇表的url” (属性值:itemtype = "schema.org 词汇表的具体类型 URL";搭配 itemscope、itemprop 使用))
    • [22. lang 属性:指定元素内容的语言 (设置页面语言:设置 在 html 标签上;属性值:lang="语言-地区/可选"; zh-CN、en-US;语言小写地区大, 连字符号中间挂)](#22. lang 属性:指定元素内容的语言 (设置页面语言:设置 在 html 标签上;属性值:lang="语言-地区/可选"; zh-CN、en-US;语言小写地区大, 连字符号中间挂))
    • [23. nonce 属性:内容安全策略 CSP 的"白名单" ⇒ 一次性的加密数字/字符串 = 一次性通行证 ⇒ 允许"特定的内联脚本、样式"执行( nonce="服务器生成的随机数";使用占位符→ 服务器生成后注入)](#23. nonce 属性:内容安全策略 CSP 的“白名单” ⇒ 一次性的加密数字/字符串 = 一次性通行证 ⇒ 允许“特定的内联脚本、样式”执行( nonce="服务器生成的随机数";使用占位符→ 服务器生成后注入))
    • [24. part 属性:shadow 内部元素"穿透 shadow 边界"→ 暴露特定元素 → 外部 css 可以设置样式、被外部 CSS 用 ::part() 选中(使用方式:双冒part 圆括号 → ::part(part属性值))](#24. part 属性:shadow 内部元素“穿透 shadow 边界”→ 暴露特定元素 → 外部 css 可以设置样式、被外部 CSS 用 ::part() 选中(使用方式:双冒part 圆括号 → ::part(part属性值)))
    • [25. popover 属性:我是隐藏的弹窗元素⇒ 将任意元素设置为"弹窗元素"→ 默认隐藏、按钮 或 js 控制"显示/隐藏" (枚举属性;属性值:popover = auto/ manual/ hint;轻关闭/手动关闭;配套属性:控制哪个弹窗元素 → popovertarget="popover 元素的 id";怎么控制 → popovertargetaction= toggle/ show/ hide;)](#25. popover 属性:我是隐藏的弹窗元素⇒ 将任意元素设置为“弹窗元素”→ 默认隐藏、按钮 或 js 控制“显示/隐藏” (枚举属性;属性值:popover = auto/ manual/ hint;轻关闭/手动关闭;配套属性:控制哪个弹窗元素 → popovertarget="popover 元素的 id";怎么控制 → popovertargetaction= toggle/ show/ hide;))
    • [26. slot 属性:把内容插入到"指定名称的插槽"中 → 内容插入到"指定 name 的 slot 标签"中⇒ slot 属性值 → 对应 slot 标签的 name 属性值 (属性值:slot="slot.name";插槽分配:无 slot 放无名,有 slot 找有名)](#26. slot 属性:把内容插入到“指定名称的插槽”中 → 内容插入到“指定 name 的 slot 标签”中⇒ slot 属性值 → 对应 slot 标签的 name 属性值 (属性值:slot="slot.name";插槽分配:无 slot 放无名,有 slot 找有名))
    • [27. spellcheck 属性:对"可编辑元素"进行"拼写检查" ⇒ 用"红色波浪下划线" 标注"错误单词"(枚举属性;开启/ 关闭拼写检查:spellcheck="true/ false";非正常拼写词汇/代码、隐私信息:显式禁用拼写检查,避免误报、避免泄露隐私给第三方)](#27. spellcheck 属性:对“可编辑元素”进行“拼写检查” ⇒ 用“红色波浪下划线” 标注“错误单词”(枚举属性;开启/ 关闭拼写检查:spellcheck="true/ false";非正常拼写词汇/代码、隐私信息:显式禁用拼写检查,避免误报、避免泄露隐私给第三方))
    • [28. style 属性:给单个元素设置样式 ⇒ 仅对当前元素生效的"内联样式"(属性值:style="CSS属性名: 值; CSS 属性名: 值;" ;冒号分名值,分号分属性)](#28. style 属性:给单个元素设置样式 ⇒ 仅对当前元素生效的“内联样式”(属性值:style="CSS属性名: 值; CSS 属性名: 值;" ;冒号分名值,分号分属性))
    • [29. tabindex 属性:控制元素是否可以被 tab 键聚焦、聚焦顺序(属性值:整数值。0、-1、正整数;零可Tab,负JS焦,正数千万别乱标,跑完正数跑自然,特殊情况才需要)](#29. tabindex 属性:控制元素是否可以被 tab 键聚焦、聚焦顺序(属性值:整数值。0、-1、正整数;零可Tab,负JS焦,正数千万别乱标,跑完正数跑自然,特殊情况才需要))
    • [30. title 属性:悬停提示、添加一段"附加说明、提示文字",鼠标悬停时显示(属性值:title="提示文本、说明信息、备用样式表名称、iframe 辅助标签";可多行:换行、空格被保留;基础用法:悬停提示非关键,移动端上看不见)](#30. title 属性:悬停提示、添加一段“附加说明、提示文字”,鼠标悬停时显示(属性值:title="提示文本、说明信息、备用样式表名称、iframe 辅助标签";可多行:换行、空格被保留;基础用法:悬停提示非关键,移动端上看不见))
    • [31. translate 属性:是否允许翻译⇒ 不想翻译设置 no (枚举属性:translate="yes/ no";默认可翻,不翻no;代码、品牌常用no,子承父业一起no)](#31. translate 属性:是否允许翻译⇒ 不想翻译设置 no (枚举属性:translate="yes/ no";默认可翻,不翻no;代码、品牌常用no,子承父业一起no))
    • [32. virtualkeyboardpolicy 属性:控制虚拟键盘的弹出行为→ 显示 or 隐藏⇒ 默认auto自动弹,manual 手动才显现(实验属性:Safari、Firefox 暂不支持;属性值:virtualkeyboardpolicy ="auto/ manual";手动显示虚拟键盘:聚焦 focus() + 显示虚拟键盘 navigator.virtualKeyboard.show())](#32. virtualkeyboardpolicy 属性:控制虚拟键盘的弹出行为→ 显示 or 隐藏⇒ 默认auto自动弹,manual 手动才显现(实验属性:Safari、Firefox 暂不支持;属性值:virtualkeyboardpolicy ="auto/ manual";手动显示虚拟键盘:聚焦 focus() + 显示虚拟键盘 navigator.virtualKeyboard.show()))
    • [33. writingsuggestions 属性:是否启动浏览器提供的"写作建议" (枚举属性;writingsuggestions="true/ false";Firefox 不支持)](#33. writingsuggestions 属性:是否启动浏览器提供的“写作建议” (枚举属性;writingsuggestions="true/ false";Firefox 不支持))
  • [全局事件属性 (简介表格)](#全局事件属性 (简介表格))
    • [⑴ 窗口事件 (Window Events)](#⑴ 窗口事件 (Window Events))
    • [⑵ 表单事件 (Form Events)](#⑵ 表单事件 (Form Events))
    • [⑶ 键盘事件 (Keyboard Events)](#⑶ 键盘事件 (Keyboard Events))
    • [⑷ 鼠标事件 (Mouse Events)](#⑷ 鼠标事件 (Mouse Events))
    • [⑸ 拖拽事件 (Drag Events)](#⑸ 拖拽事件 (Drag Events))
    • [⑹ 剪贴板事件 (Clipboard Events)](#⑹ 剪贴板事件 (Clipboard Events))
    • [⑺ 多媒体事件 (Media Events)](#⑺ 多媒体事件 (Media Events))
    • [⑻ 其他事件 (Misc Events)](#⑻ 其他事件 (Misc Events))
  • [♣ 结束语 和 友情链接](#♣ 结束语 和 友情链接)

全局属性(global attributes)

  • 全局属性所有 HTML 元素 共有的属性。全局属性可以用于所有元素,但在某些元素上可能不起作用。

全局属性的基本分类


基本的全局属性 (表格)

以下是 HTML 全局属性的表格,包含属性名、用途和属性值:

  • 虽然这些属性是全局的,但某些属性对特定元素可能没有明显效果。
  • data-* 属性:在现代前端开发中非常常用,用于在 HTML 和 JavaScript 之间传递数据
  • rolearia-* 属性:对于提升网站的无障碍访问能力至关重要。
属性名 用途 属性值
1. accesskey 属性 键盘快捷键 ⇒ 聚焦元素上、激活元素 属性值:单个键盘字符 ; 注:容易和浏览器、系统的快捷键冲突。
2. autocapitalize 属性 字母的自动大写 用于:移动设备的虚拟键盘 枚举属性; ❶ 不自动大写:offnone; ❷ 句子首字母大写:onsentences; ❸ 单词首字母大写:words; ❹ 所有字母大写:characters; 注:Safari 桌面端不支持。
3. autocorrect 属性 自动更正 ⇒ 单词自动纠错 枚举属性; ❶ 启用自动更正:on; ❷ 禁用自动更正:off; 注:仅 Safari、Firefox 支持。
4. autofocus 属性 自动聚焦⇒ 直接开始输入、无需手动聚焦 布尔属性
5. class 属性 元素的类名 class="字符串"。 多值(多个类名):空格分隔
6. contenteditable 属性 元素是否可被编辑 ⇒ 直接与页面内容交互 枚举属性; ❶ 可被编辑: contenteditable="true"; ❷ 不可被编辑:contenteditable="false"; ❸ 纯文本可被编辑、富文本格式被禁用:contenteditable="plaintext-only"
7. data-* 属性 嵌入"自定义数据" 命名规则(小连) :全小写字母、连字符分隔; 注:不能存隐私信息; HTML → JavaScript:烤串变驼峰
8. dir 属性 设置文本的方向 ⇒ 文本的排列起点、方向 用于:多语言网站 枚举属性; ❶ 从左到右:ltr; ❷ 从右到左:rtl; ❸ 浏览器自动决定/ 第一个强方向字符:auto
9. draggable 属性 设置元素是否"可拖拽" 。 默认可拖动:图链选中文(图片、链接、选中文本)。 枚举属性; ❶ 可拖动:true; ❷ 不可拖动:false; ❸ 浏览器默认行为/默认值:auto
10. enterkeyhint 属性 "回车键"的视觉提示 用于:移动设备的"虚拟键盘"上 。 ❶ 插入新行(回车键):enter; ❷ 关闭虚拟键盘(完成、√):done; ❸ 跳转(前往、→ ):go; ❹ 下一个输入框(下一步):next; ❺ 上一个输入框:previous; ❻ 看搜索结果(搜索):search; ❼ 发送:send
11. exportparts 属性 导出 part 的名称 ⇒ 给 "影子树内部 嵌套的影子树"的元素 设置样式 属性值:影子树的 part 属性值,逗号分隔; 用于:多层 shadow DOM。
12. hidden 属性 隐藏元素 ⇒ 不显示内容 枚举属性; ❶ 隐藏不显示:hidden、无效值、空值、无值/仅属性名; hidden="hidden"display: none ;不参与布局; ❷ 默认不显示、可在被查找和访问时显示:until-foundhidden="until-found"content-visibility: hidden参与布局。
13. id 属性 元素在文档中"唯一的标识符"、身份证号 ⇒ 找到唯一对应的元素 id="字符串"; 命名建议 : 字数连下划,字母开头语义化
14. inert 属性 禁用整个区域 ⇒ 禁用元素及其所有子元素 ⇒ 不参与"任何用户交互" ⇒ 无法选中、无法点击、无法聚焦、无法被 tab 键访问、屏幕阅读器不朗读、搜索不到 布尔属性; 默认无样式,可设置不透明度 opacity 提示被禁用
15. inputmode 属性 (虚拟键盘)输入模式 : 提示输入的数据类型 ⇒ 显示对应的"虚拟键盘"、优化输入体验 枚举属性;移动端有效。 ❶ 无键盘模式:none; ❷ 标准文本键盘:text; ❸ 小数键盘:decimal; ❹ 数字键盘:numeric; ❺ 电话键盘:tel; ❻ 搜索键盘:search; ❼ 邮箱键盘:email; ❽ 网址键盘:url
16. is 属性 "自定义内置元素" ⇒ 让普通 HTML 标签拥有"自定义元素的功能、样式" ; 注:Safari 不支持; is="自定义元素的名称";代码复用
17. itemid 属性 微数据项的全球唯一的标识符 id " 。 注:必须同时设置 itemscopeitemtype 指明数据项的作用范围、具体类型;单独设置无效 ; itemid="url / urn 统一资源名称" 结构化数据:schema.org 术语表词典、微数据 、JSON-LD(关联数据:机器看的"数据说明书")
18. itemprop 属性 机器可读的属性名 、数据项的"具体属性" ⇒ "名称-值"对⇒ 让搜索引擎读懂"网页内容的含义"; 名称 = itemprop 属性值="Schema.org 的标准词汇 "= 根据 itemtype 具体类型; 值 = 字符串、url; 父元素中:必须有 itemscopeitemtype ⇒ 指明数据项范围、具体类型)
19. itemref 属性 被点名的元素 也是我的属性引用元素 id、关联"外部的数据项属性" ⇒ 把数据项"外部的元素里的属性",关联到"当前的数据项" ⇒ 同一个数据项的多个属性,不必放在一个父元素下 itemref="id 值/ 多值空格分隔"; 必须搭配:itemscopeitemtype
20. itemscope 属性 数据项的"作用范围" ⇒ 该标签内的内容是"一个数据项",包括后代 布尔属性
21. itemtype 属性 数据项"类型" = "词汇表的url" itemtype = "schema.org 词汇表的具体类型 URL"; 搭配 itemscopeitemprop 使用
22. lang 属性 语言 :指定元素内容的语言设置页面语言 :设置 在 html 标签上; lang="语言-地区/可选"简记 :语言小写地区大, 连字符号中间挂(en-USzh-CN
23. nonce 属性 内容安全策略 CSP 的"白名单" ⇒ 一次性的加密数字 = 一次性通行证 ⇒ 允许"特定的内联脚本、样式"执行 nonce="服务器生成的随机数"; 使用占位符→ 服务器生成后注入
24. part 属性 shadow 内部元素"穿透 shadow 边界"→ 暴露特定元素 → 外部 css 可以设置样式、被外部 CSS 用 ::part() 选中; 使用方式:双冒part 圆括号 → ::part(part属性值) part="字符串"
25. popover 属性 存在 = 我是弹窗元素 ;(谁是弹窗元素?哪种弹窗元素?) ⇒ 将任意元素设置为"弹窗元素" → 默认隐藏:用按钮 或 js 控制"显示/隐藏" 枚举属性; 属性值:popover = auto/ manual/ hint(轻关闭、手动关闭); 配套属性: 控制哪个弹窗元素 → popovertarget="popover 元素的 id"; 怎么 控制(切换、显示、隐藏) → popovertargetaction= toggle/ show/ hide
26. slot 属性 内容插入到"指定 nameslot 标签"中slot 属性值 → 对应 slot 标签的 name 属性值 → 把内容插入到 "指定名称的插槽" 属性值:slot="slot.name"简记 :无 slot 放无名,有 slot 找有名
27. spellcheck 属性 对"可编辑元素"进行"拼写检查" ⇒ 用"红色波浪下划线" 标注"错误单词" 枚举属性; 开启/ 关闭拼写检查:spellcheck="true/ false"非正常拼写词汇/代码、隐私信息 : 显式禁用拼写检查,避免误报、避免泄露隐私给第三方
28. style 属性 内联样式:给单个元素设置样式 ⇒ 仅对当前元素生效的"内联样式" style="CSS属性名: 值; CSS属性名: 值;"简记:冒号分名值,分号分属性
29. tabindex 属性 tab 聚焦和顺序:控制元素是否可以被 tab 键聚焦、聚焦顺序 tabindex="整数值"。 0、-1、正整数; 简记 :零可Tab,负JS焦,正数千万别乱标, 跑完正数跑自然,特殊情况才需要。
30. title 属性 提示文本(附加说明):给元素添加一段"附加说明、提示文字",鼠标悬停时显示 title="提示文本、说明信息、备用样式表名称、iframe 辅助标签"可多行 :换行、空格被保留; 基础用法:悬停提示非关键,移动端上看不见
31. translate 属性 是否允许翻译 ⇒ 不想翻译设置 no 枚举属性: translate="yes/ no"; 默认可翻,不翻 no; 代码、品牌常用no,子承父业一起no
32. virtualkeyboardpolicy(实验) 虚拟键盘的弹出策略 ⇒ 默认auto自动弹,manual 手动才显现 实验属性:Safari、Firefox 暂不支持; virtualkeyboardpolicy ="auto/ manual"; 手动显示虚拟键盘:聚焦 focus() + 显示虚拟键盘 navigator.virtualKeyboard.show()
33. writingsuggestions 属性(实验) 写作建议 :是否启动浏览器提供的"写作建议" ; 默认启用写作建议。 枚举属性; writingsuggestions="true/ false"; 注:Firefox 不支持


1. accesskey 属性:键盘快捷键 ⇒ 聚焦元素上、激活元素(属性值:单个键盘字符;容易和浏览器、系统的快捷键冲突)

  • accesskey 属性accesskey 允许我们为一个 HTML 元素(如 链接、按钮、输入框等)指定一个键盘快捷键 。当用户在浏览器中按下特定的组合键时,浏览器的焦点会自动移动到该元素上(聚焦),或者激活该元素。

  • 设计初衷 :是为了提高网页的操作效率和可访问性,特别是为那些无法或不方便使用鼠标的用户(如 肢体障碍者、重度键盘使用者、屏幕阅读器用户)提供一个快速导航的途径

  • accesskey 属性值:必须由单个可打印字符组成(其中包括键盘可以生成的重音字符和其他字符)。

  • 激活 accesskey 的方式:取决于浏览器及其平台

  • 使用率:accesskey 的使用率非常低,并且现代 Web 开发实践中明确不推荐使用。 它更像是一个因存在诸多问题而被弃用的"历史遗留"特性。

下面是几个核心原因,解释了为什么它不受欢迎:

  1. 严重的快捷键冲突问题 这是最主要的原因。我们为网页元素定义的accesskey(比如 Alt + S)很容易与浏览器自身或操作系统的快捷键"撞车"
  • 浏览器占用 :例如,许多浏览器使用 Ctrl + T 打开新标签页,Ctrl + W 关闭当前标签页。如果设置了同样的组合,浏览器会"抢走"控制权,导致网页功能失效。
  • 操作系统占用:一些组合键是操作系统级的,同样会产生冲突。
  1. 用户几乎不知道它的存在 大多数普通用户并不知道网页还有accesskey这个功能,更不知道应该按哪个键来激活它。因为缺乏提示,这个属性即使设置了,也往往形同虚设,无法给用户带来预期的便利。所以,如果设置了,一定要有明确的提示。

  2. 组合键因浏览器和操作系统而异

  • 激活accesskey需要的按键组合非常不统一,这给开发者带来了很大的困扰。
  • 这种不一致性让开发者很难通过简单的提示(如下划线)清晰地告诉用户到底该按什么。
浏览器/操作系统 组合键示例
Windows Alt + 设定的键
macOS (Chrome, Safari) Control + Option + 设定的键
Firefox (Windows/Linux) Alt + Shift + 设定的键
  1. 替代方案更成熟可靠
  • 现代 Web 开发中,我们有更好的方法来提升键盘操作的可访问性和效率:
  • ✔️ 自然的 Tab 键导航 :用户可以通过Tab键在链接、按钮和表单之间按顺序移动焦点,这是最基础也是最通用的键盘交互方式。
  • ✔️ 语义化的 HTML 元素 :使用原生的<button><a>等元素,它们本身就内置了良好的键盘支持和交互预期。
  • ✔️ tabindex属性 :可以精细地控制一个元素是否能被Tab键聚焦,以及它的顺序。

总结 :总的来说,accesskey由于存在严重的快捷键冲突、用户认知度低以及组合键不统一 等固有问题,其使用率极低。MDN Web Docs 等权威技术文档也明确指出,不建议在通用网站和 Web 应用中使用accesskey属性。

  • : 使用键盘快捷键聚焦元素、激活元素。
html 复制代码
    <h1>全局属性</h1>
    <h2>1.accesskey 属性:设置键盘快捷键</h2>
    <h3>1.1 按键盘快捷键聚焦到用户名的输入框,可以直接打字</h3>
    <label for="name"> 用户名:</label>
    <input type="text" name="name" id="name" accesskey="n">
    <br>
    <small><b>提示</b>:谷歌按 Alt + n、火狐按 Alt + Shift + n 、mac 按 Control + Alt + n 可聚焦到用户名的输入框</small>
    <br>
    <h3>1.2 按键盘快捷键直接打开链接,跳转到 MDN 教程</h3>
    <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Global_attributes/accesskey" accesskey="a">accesskey
        属性的 MDN 教程</a>
    <br>
    <small><b>提示</b>:谷歌按 Alt + a、火狐按 Alt + Shift + a 、mac 按 Control + Alt + a 可直接跳转到 MDN 教程</small>

    <h3>1.3 按键盘快捷键直接激活按钮 = 点击按钮</h3>
    <button type="button" onclick="alert('Hello world!')" accesskey="b">点击弹出一个对话框</button>
    <br>
    <small><b>提示</b>:谷歌按 Alt + b、火狐按 Alt + Shift + b 、mac 按 Control + Alt + b 可直接激活按钮,弹出对话框</small>

 

演示结果

  • 谷歌浏览器中,不使用鼠标,使用 Alt + 字母 的键盘快捷键方式聚焦输入框、打开链接、点击按钮。

2. autocapitalize 属性:字母的自动大写(用于:移动设备的虚拟键盘;属性值:不自动大写:off、none;句子的首字母大写:on、sentences;单词的首字母大写:words;所有字母大写:characters;Safari 桌面端不支持)

autocapitalize 属性:用于控制用户在输入文本时,浏览器是否把字母大写,以及如何大写。

  • 用于 :专用于移动设备上的触摸屏的虚拟键盘 ,目的是提升移动端用户的输入效率、用户体验。
    • 一个实现自动大写的虚拟键盘, 可能会在即将输入应自动大写的字母时 自动切换到显示大写字母(但允许用户切换回小写
    • 桌面端的物理键盘 通常忽略此属性,autocapitalize 属性不会影响物理键盘的行为,如在电脑端浏览器,直接用键盘打字输入一般无任何影响。
  • 自动大写的无效范围autocapitalize 属性永远不会 为带有 type 属性,其值为 url(网址)、 email (邮箱)、 password(密码) 的 <input> 元素启用自动大写。因为网址、邮箱、密码(网邮密)一般是不需要大写的,自动大写只会干扰用户的输入。
  • autocapitalize 属性值
作用 典型应用场景
default 用户代理和输入法 应自行决定是否启用自动大写
offnone 禁用自动大写,所有字母应默认为小写。 输入密码、验证码、邮箱地址、代码片段。
onsentences 每个句子的首字母自动大写。 每个句子的首字母 应默认为大写字母;其他所有字母应默认为小写字母。 聊天输入框、发帖框、长文本输入。
words 每个单词的首字母自动大写。 每个单词的首字母 应默认为大写字母;其他所有字母应默认为小写字母。 输入姓名、地名、标题。
characters 所有输入的字母都自动大写。 所有字母 应默认为大写。 输入车牌号、产品代码(要求全大写)。
  • : 设置字母大写。
html 复制代码
    <h2>2. autocapitalize 属性:设置自动大写(针对移动设备的虚拟键盘)</h2>
    <h3>2.1 每个句子首字母大写</h3>
    <label for="message">输入消息:</label>
    <input type="text" name="message" id="message" autocapitalize="sentences">
    <h3>2.2 每个单词首字母大写</h3>
    <label for="username">名字:</label>
    <input type="text" name="username" id="username" autocapitalize="words">
    <h3>2.3 所有字母都大写</h3>
    <label for="code">验证码:</label>
    <input type="text" name="code" id="code" autocapitalize="characters">
    
    <h3>2.4 禁用字母大写</h3>
    <label for="email">邮箱:</label>
    <input type="email" name="email" id="email" autocapitalize="off">

演示结果

  • 手机浏览器中测试,点击所有字母都大写(autocapitalize="characters")的输入框,虚拟键盘上的所有字母自动大写
  • 移动端简单的测试:传送到微信,点击文件,用其他应用打开,选择谷歌浏览器、系统自带浏览器、UC 浏览器等手机浏览器中打开,输入时会出现虚拟键盘。如果某个浏览器无法成功打开,换一个浏览器。


3. autocorrect 属性:自动更正 ⇒ 单词自动纠错 (枚举属性;移动端虚拟键盘;属性值:启用自动更正:on;禁用自动更正:off;仅 Safari、Firefox 支持)

  • 浏览器兼容性:仅 Safari、Firefox 支持

autocorrect 全局属性 :是一种枚举属性,控制输入内容是否被浏览器自动修正 。可以把它理解为网页输入框的"自动纠错"开关

  • 具体的自动更正行为,包括替换哪些词语,取决于用户代理和底层设备提供的服务 。设计初衷是提示虚拟键盘在用户输入时是否进行自动更正

  • 主要服务对象是:移动端(iOS/Android)和触摸屏设备上的虚拟键盘。在桌面端基本无效。

  • 适用范围 :自动更正与以下可编辑文本元素相关:

    • <input> 元素,除了 password(密码)、email(邮箱) 和 url (网址)类型以外(网邮密不自动更正:密码、邮箱、网址的类型不支持自动更正)。
    • <textarea> 元素。
    • ❸ 任何具有 contenteditable 属性的元素。
    • 可编辑元素默认情况下启用自动更正 ,除了在 <form> 内的元素以外,默认值可能从表单中继承
    • 明确设置 该属性会覆盖默认行为
  • autocorrect 属性值

    • on""(空字符串):启用拼写和标点符号的自动更正。
    • off:禁用可编辑文字的自动更正。
  • 不支持自动更正的 <input> 元素类型passwordemailurl始终处于 off 状态。

  • 对于所有其他可编辑元素 :设置上述值以外的任何其他值 都会被视为 on

  • 未嵌套在 <form> 内的元素 :默认值为 on

  • 嵌套在 <form> 中时,如果已经设置了 autocorrect ,则以下元素将从表单中 继承其默认值

    • <button><fieldset><input><output><select><textarea>

: 给一个多行文本输入框 设置单词自动更正的功能。

html 复制代码
    <h2>3. autocorrect 属性:自动更正</h2>
    <h3>开启自动更正功能</h3>
    <label for="bio">个人简介</label>
    <br>
    <textarea name="bio" id="bio" cols="50" rows="10" placeholder="请简单介绍下您自己..." autocorrect="on"></textarea>

演示结果

  • 桌面端的效果区分:以下拼写检查的错误提示 ↓ ,不是自动更正。

    • 自动更正会自动更正单词,依赖于手机端提供的服务,不只是检查错误。
  • 问题和解决方案:如果 Firefox 浏览器中测试无反应,设置 → 搜索"拼写",第一,把拼写检查打开,第二,"翻译"里下载一个英语语言包,这样一般就可以了,不行的话,浏览器重开一下,再把语言设置为英语,输入英文单词时就会检查单词的拼写了。

  • Safari 中,一般会自动更正错误单词。


4. autofocus 属性:自动聚焦⇒ 直接开始输入、无需手动聚焦(布尔属性)

autofocus 属性 :是一个布尔属性 ,它告诉浏览器:当页面加载完成后或 所属的 <dialog> 显示时,自动将 光标(焦点) 放到设置了该属性的元素上,使用户可以直接开始输入 ,而无需手动聚焦主元素。

  • :当 autofocus 属性指定在 dialog 元素内部的元素或 popover 属性被设置的 HTML 元素上时,当对话框或弹出框显示时,它将被聚焦。
  • 立即生效 :页面加载完成 即自动聚焦。
  • 无需 JavaScript纯 HTML 实现
  • ❸ 页面中只能有一个元素拥有"自动聚焦 autofocus"属性
    • 如果多个元素都设置了 autofocus,只有一个会生效,所以发现自己设置无效时,可能是设置上有冲突。
    • 如果设置了多个 autofocus,一般是第一个元素(即最先出现在 HTML 代码中的那个)将会获得焦点。

autofocus 常用于 :任何以输入为主要目的的页面 ,如 搜索页面、登录/注册页面、对话框/弹窗中的输入框,自动聚焦后,方便用户直接输入。

不适用

  • 内容阅读型网站(新闻、博客):不需要自动聚焦到任何地方,会干扰阅读。
  • 有屏幕阅读器用户的页面:自动移动焦点可能让视障用户迷失。
  • 移动端页面:自动聚焦会弹出键盘,可能遮挡页面内容。

: 搜索的输入框自动聚焦。

  • 一打开页面,光标已经在搜索框里闪烁,可以直接输入关键词,无需点击搜索框
html 复制代码
    <h2>4. autofocus 属性:自动聚焦</h2>
    <label for="search">搜索关键词:</label>
    <input type="search" id="search" name="q" placeholder="请输入搜索关键词" autofocus>

5. class 属性: 元素的类名、可多元素共享的标识符(多值:空格分隔;CSS:多元素 相同样式、一个元素多个样式)

class 属性:是 HTML 中的全局属性,意味着它几乎可以被用在所有的 HTML 元素上。

  • 核心作用:是为元素提供一个 非唯一的标识符 (即类名 )。与 id(一次只能赋给一个元素)不同,同一个 class 可以被任意多个元素共享 ,同时一个元素也可以拥有多个 class (注:多个类名用空格 分隔)。
    • CSS:可以通过类名 选择特定元素、设置样式。
    • Javascript :可以通过 DOM 方法 (如 document.getElementsByClassName) 来访问特定的元素。
    • 样式复用(多元素 统一样式) :多个元素 使用同一个类名时,可以通过 CSS 将相同的样式 赋予不同的元素
    • 行为绑定:通过 JavaScript 批量操作具有相同类名的元素。
    • 组合能力 :一个元素有多个类名时,允许一个元素同时拥有多种样式
      • 可以将样式规则拆分成更小的、可复用的"零件"

: 使用类名 在 CSS 中设置样式,在 JavaScript 中设置行为。

html 复制代码
	<style>
        /*紧急内容的样式*/
        .urgent {
            color: red;
            font-weight: bold;
        }

        /*普通内容的样式*/
        .normal {
            font-weight: bold;
        }
	</style>

    <h2>5. class 属性:元素的类名(不唯一)</h2>
    <h3>5.1 样式复用:用于 CSS 选择元素,使用相同的类名选择多个元素,并设置可复用的样式</h3>
    <p class="urgent">紧急通知:临时更改会议时间,今晚 8:00 召开紧急会议。</p>
    <p class="urgent">紧急通知:全体人员都应到场。</p>
    <p class="normal">通知:本周末会议仍照旧。</p>

    <h3>5.2 行为绑定:为 JavaScript 提供"钩子",使用类名查找和操作元素</h3>

    <div class="hint-message">
        <b>提示信息:</b>
        <p>会议地点:三楼 302 会议室。</p>
    </div>
    <button type="button" class="hide-btn">隐藏提示</button>
    <script>
        // 通过类名找到按钮 
        const hideButton = document.querySelector(".hide-btn");
        // 通过类名找到需要被隐藏的元素
        const hintMsg = document.querySelector(".hint-message");

        hideButton.addEventListener("click",function(){
            hintMsg.style.display = "none"; //隐藏元素
        });
        
    </script>

6. contenteditable 属性:元素是否可被编辑 ⇒ 直接与页面内容交互 (枚举属性;属性值:可被编辑: true;不可被编辑:false;纯文本可被编辑、富文本格式被禁用:plaintext-only)

contenteditable 属性:是一个枚举属性,表示元素是否可被用户编辑。如果可以,浏览器会修改元素的组件以允许编辑。

  • 核心用途:将静态页面转化为动态画布,让用户可以直接与页面内容交互
  • 属性值
    • 可被编辑true""(空字符串)、无值(仅属性名)
    • 不可被编辑false
    • 只保留纯文本(富文本格式被禁用)plaintext-only
      • 允许用户编辑文本,但禁止粘贴富文本格式 。如果用户从某个网页复制了一段带颜色和加粗的文字粘贴进去,所有格式都会被自动剥离,只保留纯文本。不希望用户破坏页面样式时使用。
    • 继承 :如果没设置该属性或设置了无效的属性值,则其默认值 继承自父元素:即,如果父元素可编辑,该子元素也可以被编辑。

: 使无序列表变成可编辑的区域。

html 复制代码
    <h2>6. contenteditable 属性:元素可编辑</h2>
    <h3>可编辑的计划列表(点击文字可修改,保留粘贴字体的格式,如 可粘贴加粗字体)</h3>
    <!-- 用户点击某个事项,光标出现,可以直接修改文字,修改后内容依然保留在页面上。 -->
    <ul contenteditable="true">
        <li>学习英语</li>
        <li>跳绳</li>
        <li>喝牛奶</li>
    </ul>

    <h3>可编辑的计划列表(点击文字可修改,不保留粘贴字体的格式)</h3>
    <!-- 用户点击某个事项,光标出现,可以直接修改文字,修改后内容依然保留在页面上。 -->
    <ul contenteditable="plaintext-only">
        <li>学习英语</li>
        <li>跳绳</li>
        <li>喝牛奶</li>
    </ul>

演示结果


7. data-* 属性:嵌入"自定义数据"(命名:全小写字母、连字符分隔;不存隐私信息;HTML → JavaScript:烤串变驼峰,data-*→ dataset.小大大大...首字母大写)

data-*(自定义数据属性) :是在 HTML 元素上存储额外的"自定义信息" ,这些信息不会影响页面的呈现 (若不搭配 CSS),但可以被 JavaScript 轻松访问和操作。可以通过脚本在 HTML 与 DOM 之间进行专有数据的交换

访问自定义数据属性 :可以通过所属元素的 HTMLElement 接口来访问。

  • HTMLElement.dataset 属性:通过该属性,可以访问自定义数据属性。

data-* 中的*的命名 :任何名称,但需要遵循 XML 名称的命名规则。

  • 名称不应以 xml 开头(不区分大小写) ,因为它是为未来的 XML 规范保留的。
  • 名称不应包含任何冒号字符(: ,因为 XML 会赋予此类名称意义。
  • 名称都应该是小写字母,不应包含任何大写字母,因为 XML 都是小写字母。
  • :以上都是建议,如果不遵循这些命名建议,不会发生错误,比如 在 CSS 的属性选择器和 JavaScript HTMLElement.dataset 属性中 仍能识别,但强烈建议不要违法规则。

  • 自定义属性的命名 和 在 JavaScript 中的使用
    • 在 JavaScript 中使用 HTMLElement.dataset访问,那么属性名中 data- 后面的部分只能包含 JavaScript 属性名允许使用的字符(以及连字符,连字符将被删除)
    • 属性名 dataset 会去掉"data-"前缀(相当于 dataset = data- ),并将名称的剩下部分**从烤串命名法(连字符) → 转换为驼峰命名法。
    • 烤串变驼峰data-*dataset.小大大大...(首字母大写)。第一个连字符后的字母 纯小写,从第二个连字符开始,连字符后的字符串 首字母大写。
  • HTML 和 JavaScript 中的名称转换
    • data-testelement.getAttribute("data-test") 等同于 element.dataset.test
    • data-test-abcHTMLElement.dataset.testAbc(或 HTMLElement.dataset["testAbc"])的形式访问。
    • 连字符后应该是字母字符 ,避免连字符后跟非字母字符,如 data-test-1data--test,因为 HTMLElement.dataset 无法识别这些字符。

建议命名方法

  • ✔️ 全部"小写字母",用"连字符"分隔 :遵循 data- + 小写字母+连字符- + 小写字母的格式。
    • data-user-name,而不是 data-userNamedata_user_name
    • data-user-name 对应 element.dataset.userName
    • data-user-id 对应 element.dataset.userId
  • 好处 :在 JavaScript 中通过 dataset 属性读取时,"连字符命名"会自动转换为"驼峰"格式,方便对自定义数据的访问和操作。

注意事项

  • 命名规范全小写字母+连字符,JS 中自动用驼峰格式读取。
  • 数据类型的转换 :从 dataset 属性读取的任何值都是字符串 。如果存的是data-count="8",需要用 parseInt() 转换为数字后再进行运算。
  • 存放"小数据" :自定义数据属性 最适合存储 ID、状态名、简短配置等轻量级数据。复杂的对象或数组应该放在 JavaScript 变量中管理,避免 DOM 解析开销和性能问题。
  • 不存"敏感信息":绝不存储 token、密码等敏感信息,源代码中会泄露隐私。

: 使用自定义数据属性存储商品信息。

html 复制代码
    <h2>data-* 属性:嵌入自定义数据</h2>
    <h3>存储商品的数据</h3>
    <small>注:按 F12,"控制台"菜单项可见商品 ID、类别、价格的数据</small>
    <!-- 优势:不需要在JavaScript中维护商品ID和元素的对应关系,数据就在元素上,随拿随用。 -->
    <div class="product-card" data-product-id="1" data-category="headphones" data-price="100">
        <h4>无线耳机</h4>
        <img src="images/headphones.png" alt="无线耳机">
        <button type="button">加入购物车</button>
    </div>
    <div class="product-card" data-product-id="2" data-category="mouses" data-price="200">
        <h4>鼠标</h4>
        <img src="images/mouse.png" alt="无线鼠标">
        <button type="button">加入购物车</button>
    </div>

    <script>
        // 获取所有的商品卡片
        document.querySelectorAll(".product-card").forEach(card => {
            card.addEventListener("click", function () {
                // 通过 dataset 读取自定义属性
                const productId = this.dataset.productId;
                const category = this.dataset.category;
                const price = this.dataset.price;
                //控制台输出商品信息
                console.log(`商品 ID:${productId},商品类别:${category},商品价格:${price}`)

            });
        });

    </script>

搭配自定义属性,设置 CSS 样式

html 复制代码
    <style>
        /*类名和自定义属性结合,限制范围,只在特定区域查找*/
        .product-card[data-category="headphones"]
        {
            color: #0f723c;
        }
    </style>

8. dir 属性:设置文本的方向 ⇒ 文本的排列起点、方向(枚举属性;属性值:从左到右:ltr;从右到左:rtl;浏览器自动决定/ 第一个强方向字符:auto;多语言网站)

dir 属性 :全局属性,枚举属性,用来设置元素的文本方向 。告诉浏览器文字应该从哪边开始读、往哪边排列

  • 用于:多语言网站。构建支持不同语言的网站,特别是阿拉伯语、希伯来语等从右至左书写的语言来说,是必不可少的。
  • 文本方向 :影响文字的对齐方式(排列起点、排列方向) ,影响标点符号的位置<table> 的列顺序。

dir 属性值

  • ltr (Left-to-Right)文本方向 从左向右 。适用于中文、英文、法文等大多数语言。
    • 从左到右(ltr) = 左对齐(从左边界开始,向右排列)
  • rtl (Right-to-Left)文本方向 从右向左 。适用于阿拉伯语、希伯来语、波斯语等。
    • 从右向左(rtl) = 右对齐(从右边界开始,向左排列)
  • auto显式指定,让浏览器根据内容自动判断方向
    • 适用于内容不确定的场景,比如用户评论或搜索框,浏览器会查看内容里第一个强方向性的字符来决定。
  • dir 属性的缺失值、无效值 :默认都是 Undefined 状态。
  • 属性值覆盖dir 属性可以被 CSS 属性 directionunicode-bidi 覆盖。
    • :文本方向与语义相关 而非外观,因此,推荐 优先使用 dir 属性,而非 CSS 相关属性。在不支持 CSS 或禁用 CSS 的浏览器中,文本也会正常显示。

例 1 : 基础用法 (ltrrtl),设置文本的方向 dir

html 复制代码
    <h2>dir 属性:设置文本的方向</h2>
    <h3>设置文本方向:从左到右(默认方向,中文、英文等的书写方向)</h3>
    <p dir="ltr">Hello,world!</p>
    <p dir="ltr">你好,世界!</p>
    
    <h3>设置文本方向:从右到左(阿拉伯语、希伯来语等的书写方向)</h3>
    <p dir="rtl">Hello,world!</p>
    <p dir="rtl">你好,世界!</p>
    <p dir="rtl">مرحبا بالعالم</p>
    <p dir="rtl">שלום עולם</p>
    <p dir="rtl">阿拉伯语:مرحبا بالعالم</p>
    <p dir="rtl">希伯来语:שלום עולם</p>

演示效果

文本方向 dir 影响标点符号的位置 :如上 感叹号!,跟随ltrrtl的规则变化。在最右边 或 最左边。


例 2dir 改变表格的列的顺序。

html 复制代码
    <h3>dir 属性影响表格的列的顺序</h3>
    <h4>表格列的默认顺序:未设置 dir 属性</h4>
    <table class="table-dir">
        <tr>
            <th>1.年级</th>
            <th>2.性别</th>
            <th>3.人数</th>
        </tr>
        <tr>
            <td>一年级</td>
            <td>男</td>
            <td>55</td>
        </tr>
        <tr>
            <td>二年级</td>
            <td>女</td>
            <td>33</td>
        </tr>
    </table>
    <h4>表格设置 dir="rtl" 后的顺序:表格的列从右往左排列</h4>
    <table class="table-dir" dir="rtl">
        <tr>
            <th>1.年级</th>
            <th>2.性别</th>
            <th>3.人数</th>
        </tr>
        <tr>
            <td>一年级</td>
            <td>男</td>
            <td>55</td>
        </tr>
        <tr>
            <td>二年级</td>
            <td>女</td>
            <td>33</td>
        </tr>
    </table>

演示结果


例 3 : 使用 auto 自动判断文本的方向。

  • 不确定内容的语言时,dir="auto" 会很有用。
  • 浏览器会查看元素内的第一个字符来自哪种文字系统,并以此决定方向。
html 复制代码
<h3>浏览器自动决定文本的方向:dir="auto"</h3>
<!-- 内容以英文开头,浏览器会判断为 ltr -->
<p dir="auto">Hello, world! 这是一段中英文混合的文本。</p>

<!-- 内容以阿拉伯语开头,浏览器会判断为 rtl -->
<p dir="auto">مرحبا بالعالم 这是一段阿拉伯语和中文混合的文本。</p>

<!-- 未显式指定 dir="auto" -->
<p>مرحبا بالعالم 这是一段阿拉伯语和中文混合的文本。</p>

演示结果

dir 全局属性主要用于:

  1. 支持多语言: 为从右向左书写的语言 提供正确的排版。
  2. 改变布局流向: 影响文本、表格、Flex/Grid 布局的方向。
  3. 处理动态内容 : 使用 auto 值自动适应不确定来源的文本方向。

9. draggable 属性:设置元素是否"可拖拽" (枚举属性;可拖动:true;不可拖动:false;浏览器默认行为/默认值:auto;默认可拖动,图链选中文)

draggable 属性 :是一个 HTML 全局属性,枚举属性,它本身并不能直接让元素被拖拽后产生效果,而是作为整个拖放功能的开关和起点 。它和拖放 API(Drag and Drop API)中的一系列事件(如 dragstart, dragover, drop 等)配合,才能实现完整的拖放交互。

  • draggable 的作用:告诉浏览器 "这个元素可以(或不可以)被鼠标拖动。"
  • 默认可拖动的元素 :在 HTML 中,默认只有图片img)、链接a)、被选中的文本 可以拖动 (简记:默认可拖动,图链选中文)。

draggable 的属性值 :枚举,truefalse

  • :一个枚举属性 ,不是布尔值,必须写成 draggable="true"draggable="false" 这样的形式,不能简写(仅属性名)
属性值 用途 说明
true 元素 可以被拖动 这是最常用的值,用于将一个非默认可拖动的元素 (如<div><p>)变为可拖动。
false 元素 不可以被拖动 用于覆盖元素的默认行为 。 例如,默认可拖动的图片和链接,如果不想让用户拖动它们,就可以设置此值。
auto 使用浏览器的默认行为draggable 属性的缺失值、无效值的默认值:都是auto 这是未设置该属性时的默认值 。 对于大多数元素(如<div>),默认行为是不可拖动的; 对于<img><a>,默认行为是可拖动的。

: 把一个段落设置为可拖拽的。

  • HTML 中,段落(p)默认是不可拖动的,如果想让一个普通的<p>段落也能被拖动,就需要将它的draggable属性设置为true
html 复制代码
    <h2>draggable 属性:设置元素是否可拖拽</h2>
    <h3>让默认不可拖拽的段落变得可拖拽</h3>
    <p>我是不可拖拽的段落,只有选中文字后才能拖拽。</p>
    <p draggable="true">我是可拖拽的段落,不必选中文字,按住鼠标左键就可以拖拽。</p>

演示效果

  • 按住鼠标左键,并拖动,会看到元素的内容变得半透明跟随鼠标移动。不过,只是这样设置,松开鼠标后不会发生任何事,因为我们还没有定义"放置"的逻辑。

使用注意

  • 必须配合 JavaScript :单纯设置draggable="true",只能让元素"看起来"能被拖动,但松开鼠标后不会有任何数据交换或位置变化。要实现有意义的拖放(如排序、移动、复制),必须处理 dragstartdragoverdrop等事件。
  • 可拖动→ 无法选中 :当一个元素被设置为draggable="true"(可拖动)后,其内部的文本 将无法再通过常规的点击并拖动鼠标 的方式来选中,这个行为成了拖动行为。在 Firefox 浏览器中,用户需要按住Alt键才能用鼠标选择文本。

10. enterkeyhint 属性:给移动设备"虚拟键盘"⇒ "回车键"提供一个视觉提示 只改样式、不改功能;属性值:插入新行(回车键):enter;关闭虚拟键盘(完成、√):done;跳转:go;下一个输入框(下一步):next;上一个输入框:previous;看搜索结果(搜索):search;发送:send;

enterkeyhint 属性 :枚举属性,是给移动端虚拟键盘 上的"回车键 "提供一个视觉提示 (= 操作标签 或 图标,(例如 显示"搜索"、"下一步"、"发送"等),让用户更清楚地了解:点击这个键会触发什么操作

  • 不是用来实现核心功能的,而是用来提升用户体验的 。因此,它并非每个表单或输入框的必需属性,但在追求精致体验的移动端页面或 Web App 中,使用率会相对更高。
  • :需要记住一点:它只是一个"提示" 。它只改变键盘 Enter 按键的显示样式 ,并不会改变按键的实际功能
    • 例如,即使设置了 enterkeyhint="search",也必须通过 <form> 包裹或 JavaScript 监听事件,才能真正实现"搜索"的逻辑 。应该始终确保核心功能不依赖于此属性。
  • :移动端的虚拟键盘专用,在 PC 的物理键盘上无效。

enterkeyhint 的属性值

  • 插入新行(回车键):enter;关闭虚拟键盘(完成、√):done;跳转:go;下一个输入框(下一步):next;上一个输入框:previous;看搜索结果(搜索):search;发送:send;
  • 相关代码在表格下方。
  • 测试设备:安卓手机,搜狗输入法。
键盘显示效果(示意图) 属性值 典型用途
或 换行符 enter 插入新行 :多行文本输入(如 <textarea>、评论框),表示插入新行
完成 或 ✅ done 关闭键盘(输入法) :没有其他输入内容,输入法编辑器将关闭(IME:input method editor)。 表单填写完毕、关闭键盘、保存设置。
前往 或 → go 跳转到目标位置:地址栏输入网址、确认跳转、打开链接。
下一步 或 ➡️ next 下一个输入框:表单中填写完当前字段后,跳到下一个输入框。
上一步 或 ⬅️ previous 上一个输入框 :表单中返回上一个输入框(较少用,通常与 next 配合)。
搜索 或 🔍 search 看搜索结果:搜索框、查找功能 。
发送 或 📤 send 发送:消息发送、评论提交、邮件发送。
回车 或 (默认值,不设置时) 默认行为 ,通常为提交表单或换行(取决于输入类型)。

补充说明:

  • 不同操作系统(iOS/Android)和不同输入法 对同一属性值的图标渲染可能略有差异,但语义保持一致。
  • 如果不设置 enterkeyhint,键盘默认显示"回车"图标。
  • 该属性仅影响虚拟键盘 的视觉表现,实际功能仍需通过 JavaScript 或 <form> 实现。

: 改变移动设备的虚拟键盘 Enter 键的视觉提示

html 复制代码
    <h2>enterkeyhint 属性:虚拟键盘的 Enter 键的视觉提示</h2>
    <h3>Enter 键 = 搜索相关 search</h3>
    <label for="search-keywords">搜索关键词:</label>
    <input type="search" name="search" id="search-keywords" placeholder="请输入搜索内容..." enterkeyhint="search">
    <h3>Enter 键 = 插入新行 enter</h3>
    <textarea name="comments" id="comments" cols="30" rows="10" placeholder="请输入评论..." aria-label="评论区"
              enterkeyhint="enter"></textarea>

    <h3>Enter 键 = 输入完成,关闭键盘(输入法) done </h3>
    <input type="text" name="done" id="done" enterkeyhint="done" aria-label="done">
    <h3>Enter 键 = 跳转到目标位置 go</h3>
    <input type="text" name="go" id="go" enterkeyhint="go" aria-label="go">

    <h3>Enter 键 = 下一个输入框 next</h3>
    <input type="text" name="next" id="next" enterkeyhint="next" aria-label="next">
    <h3>Enter 键 = 上一个输入框 previous</h3>
    <input type="text" name="previous" id="previous" enterkeyhint="previous" aria-label="previous">
    <h3>Enter 键 = 发送 send</h3>
    <input type="text" name="send" id="send" enterkeyhint="send" aria-label="send">
  • 演示效果:见上方表格。

11. exportparts 属性: 导出 part 的名称、允许外部访问 "内部 shadow 的指定 part" ⇒ 给 "影子树内部 嵌套的影子树"的元素 设置样式(属性值:影子树的 part 属性值,逗号分隔;用于:多层 shadow DOM)

exportparts 属性 :专为 Web Components 设计的 ,使用 exportparts 可以通过导出 part 的名称 ,来选择、样式化 "嵌套在影子树中的 影子树的元素"

  • 核心用途 : 在 Web Components 的 Shadow DOM 中,将内部嵌套的影子树 将 part 名称 暴露给外部 CSS, 进行 样式定制
    • 例:<card-wrapper> 有自己的 Shadow DOM,它的 Shadow DOM 内部又使用了 <card-component>(另一个 Shadow DOM),在 <card-component> 上使用 exportparts 实现了跨两层 Shadow DOM 的样式穿透。
  • 问题 :影子树是一个隔离的结构 ,其中标识符、类和样式无法通过 属于常规 DOM 的选择器或查询来访问,外部 CSS 无法直接修改"内部元素的样式"
  • 解决问题 :如果想允许外部 CSS 调整影子树元素的样式,有两个 HTML 属性可以应用于影子树元素,从而实现从外部设置影子树的 CSS 样式part 属性 和 exportparts 属性 。
    • part 全局属性 : 可使影子元素对"父级 DOM" 可见
      • part 属性值 = ::part() 伪元素的参数。 可以从影子树外部为其中的元素应用 CSS 样式。
    • exportparts 全局属性 :因为,::part() 伪元素仅对父级 DOM 可见。这意味着当影子树中有"嵌套影子树"时 ,除了直接父级 之外,对直接父级以外的任何祖先 都不可见exportparts 属性解决了这一限制,使嵌套的影子树内部元素,对其他祖先也可见。
    • exportparts 就像在组件墙上打开一扇小窗户,让我们可以指定哪些内部嵌套的元素 允许外部调整样式
    • exportparts 属性使影子树的某些部分 能够在影子 DOM 外部可见 。这一概念被称为"导出"。
    • exportparts 属性应用于:元素的影子宿主(= 影子树所附着的元素 = 内部嵌套的影子树上)。
    • 例: <card-wrapper>(一层) 内部嵌套了 <card-component>(第二层),⇒ 则 exportparts 写在第二层的 子元素 <card-component>上(<card-component exportparts="base,header,body">)。

exportparts属性值 :为影子树中存在的 part 名称(= part 属性值) ,多个名称用逗号分隔 。这些名称将对当前结构外的 DOM 可用。

  • 别名 :导出一个 part 时,可以为该部分part 分配一个别名 ,用冒号 : 表示映射关系 ,省略别名,等同于"别名=原名 ",以原名导出
  • 以原名导出exportparts="part1, part2, part5"exportparts="part1:part1, part2:part2, part5:part5
  • 以别名导出exportparts="原名1:别名1, 原名2:别名2"(注:原名 = 影子树中 part 属性值
  1. exportparts 只在跨越 Shadow 边界时必需
  2. 边界数量 :每多一层 Shadow DOM,就需要一层 exportparts(或 part 属性)来暴露内部元素。
  3. 直接访问 :如果外部直接使用组件,不需要 exportparts,组件自己的 part 属性就足够。

: 组件的嵌套使用:card-wrapper内部使用了card-component,并通过插槽传递内容。

  1. Web Components:允许创建可复用的自定义 HTML 元素。
  2. Shadow DOM:封装组件的内部结构和样式,与主 DOM 隔离。
  3. <template>:定义可重用的 HTML 片段。
  4. 插槽(slot:允许在组件中插入外部内容。
  5. 自定义元素 :通过customElements.define()注册新元素。
html 复制代码
    <style>
        h3.card{
            background-color: #dedede;
        }
        card-wrapper,card-component{
            border: 1px solid green;
        }
        
        ::part(header){
            color: red;
        }
        
        ::part(body){
            color: green;
        }
        
        ::part(footer){
            color: blue;
        }
        

    </style>

    <h2>exportparts 属性:导出 part,使用外部 CSS ,对 web component 的 Shadow DOM 中嵌套的 Shadow DOM 设置样式</h2>

    <!-- 1. 第一个 HTML 模板: 基础卡片组件模板 -->
    <template id="card-component-template">
        <style>
            /*专门用于选择 Shadow DOM 的宿主元素(即自定义元素本身)*/
            :host {
                display: block; /* 设置宿主元素为块级显示,独占一行,能设置宽高、宽度= 父容器100%,有上下外边距*/
            }

        </style>
        <!-- part 属性:用于 ::part() 选择器,允许外部样式话内部元素 -->
        <div class="base" part="base">
            <!-- 头部区域:内有具名插槽 slot 元素 = 可插入内容的区域 -->
            <div part="header">
                <!-- 插槽 slot 元素:允许插入外部内容 -->
                <slot name="header-slot"></slot>
            </div>
            <!-- 主体区域:内有具名插槽= 可插入内容的区域 -->
            <div part="body">
                <slot name="body-slot"></slot>
            </div>
            <!-- 底部区域:内有具名插槽= 可插入内容的区域 -->
            <div part="footer">
                <slot name="footer-slot"></slot>
            </div>
        </div>
    </template>

    <!-- 2. 第二个 HTML 模板:卡片的包装器 <card-wrapper>,内部使用了 <card-component>,但只导出了头部和主体供外部样式修改 -->
    <!-- 正常情况下,Shadow DOM 内部的元素对外部 CSS 是完全隔离的。exportparts 可以有选择地将内部元素的 part 属性暴露出去,这里只导出了 base、header、body,没有导出 footer,所以外部 CSS 的 ::part(footer) 无法作用于包装器(card-wrapper)内部的卡片(card-component)-->
    <template id="card-wrapper">
        <style>
            :host {
                display: block; /* 宿主元素显示为块级元素*/
            }
        </style>
        <!-- 自定义元素 card-component,导出部分元素的 part 名,让外部 CSS 可以对其设置样式 -->
        <!-- 只导出了 base、header 和 body 这三个部分,没有导出 footer。 -->
        <card-component exportparts="base,header,body">
            <!-- 内有 3个具名插槽 slot 元素 = 可插入内容的区域,同时具有 slot 属性 = 本身内容应插入到哪个插槽 = 插入到上一个模板的 slot 元素中-->

            <!-- slot.name="H":接收 slot="H" 的元素的内容;slot="header-slot":自身内容 插入到name = "header-slot" 的 slot 元素中-->
            <slot name="H" slot="header-slot"></slot>
            <slot name="B" slot="body-slot"></slot>
            <slot name="F" slot="footer-slot"></slot>
        </card-component>
    </template>

    <!-- 3.自定义组件部分 -->
    <h3 class="card">卡片包装器</h3>
    <!-- 自定义元素 -->
    <card-wrapper>
        <!-- slot="H":元素的内容插入到 slot.name="H" 的 slot 元素中-->
        <p slot="H">包装器头部</p>
        <p slot="B">包装器主体</p>
        <p slot="F">包装器底部</p>
    </card-wrapper>

    <h3 class="card">卡片组件</h3>
    <!-- 自定义元素 -->
    <card-component>
        <!-- slot="header-slot":元素的内容插入到 slot.name="header-slot" 的 slot 元素中-->
        <p slot="header-slot">卡片头部</p>
        <p slot="body-slot">卡片主体</p>
        <p slot="footer-slot">卡片底部</p>
    </card-component>

    <script>
        <!-- 定义 card-component 自定义元素,通过 customElements.define() 注册新元素  -->
        customElements.define(
            "card-component", //元素名称,必须含连字符
            class extends HTMLElement { //继承自 HTMLElement
                constructor() {
                    super();
                    //  获取模板元素
                    const template = document.getElementById("card-component-template");
                    //创建 Shadow DOM,封装组件的内部结构和样式,与主 DOM 隔离
                    const shadowRoot = this.attachShadow({
                        mode: "open",//可以通过 js 访问
                    });
                    // 克隆模板 card-component-template 的内容,并添加到 Shadow DOM
                    shadowRoot.appendChild(document.importNode(template.content, true));
                }
            }
        );

        // 定义 card-wrapper 自定义元素
        customElements.define(
            "card-wrapper",
            class extends HTMLElement {
                constructor() {
                    super();

                    // 获取第二个模板
                    const template = document.getElementById("card-wrapper");

                    // 创建Shadow DOM
                    const shadowRoot = this.attachShadow({
                        mode: "open",
                    });

                    // 克隆模板 card-wrapper 的内容,并添加到 Shadow DOM
                    shadowRoot.appendChild(document.importNode(template.content, true));
                }
            },
        );
    </script>

演示效果

  • 问题: 设置头部、主体、底部的文字颜色。为什么 包装器头部、包装器主体、包装器底部 中"包装器底部"的字体颜色没变,而卡片头部、卡片主体、卡片底部的字体颜色都变了?
  • CSS 选择器的作用域 :主文档中的 ::part(header)::part(body)::part(footer) 只能作用于直接暴露的 part
  • <card-component exportparts="base, header, body">
    • exportparts 控制哪些 part 可以被外部访问
    • 这里只导出了<card-wrapp>的内部 shadow (<card-component>)的 baseheaderbody 这三个部分,没有导出<card-component>footer,所以,对于内部嵌套的 shadow 而言,part="footer" 这部分无法被外部访问,设置的样式就无法起效。

✔️ 直接的 ::part() 访问 vs 跨 Shadow 边界访问

  • 一层 Shadow DOM ⇒ 直接的 ::part() 访问 : 有 part 属性即可,不需要exportparts 属性。
    • 访问顺序:主文档 → <card-component>
    • 自定义元素 <card-component> 的 Shadow DOM 直接暴露了 headerbodyfooter 这些 part
    • 主文档是直接访问这些 part,没有中间层的 Shadow DOM 阻隔。
    • 这是 一层 Shadow DOM 的情况:主文档 → card-component
  • 两层 Shadow DOM ⇒ 需要exportparts 属性。
    • 访问顺序:主文档 → <card-wrapper><card-component>
    • <card-wrapper> 的 Shadow DOM 像一堵墙,阻隔了主文档对 <card-component> 内部 part 的直接访问。
    • 通过 exportparts 告诉浏览器:"允许外部访问 内部 shadow (<card-component>) 的这些 part"。
  • exportparts 只在跨越 Shadow 边界时必需
    • 边界数量 :每多一层 Shadow DOM,就需要一层 exportparts(或 part 属性)来暴露内部元素。
  1. slot 属性 :由内容提供方使用,告诉浏览器这个内容应该 "插入到哪个插槽(内容放哪、传给谁)"
  2. <slot> 元素 :由组件定义方使用,标记可被替换的区域
  3. 默认插槽 :不带 name 属性的 <slot>,接收 所有没有指定 slot 属性的内容
  4. 具名插槽 :带 name 属性的 <slot>,只接收 指定了对应 slot 属性的内容
  5. 后备内容<slot> 标签内的内容是默认显示内容 ,当没有内容插入时显示

12. hidden 属性:隐藏元素 ⇒ 不显示内容(枚举属性;隐藏不显示:hidden、空值、无效值、无值/仅属性名;hidden="hidden" ⇔ display: none ;不参与布局;查访时才显示内容/内外边距等不隐藏:until-found; hidden="until-found" ⇔ content-visibility: hidden;参与布局)

hidden 属性 :全局属性,一个枚举属性 ,可以应用于任何元素,并有效地隐藏元素 ,指示浏览器不应该呈现元素的内容(= 不显示内容) 。类似于 CSS 中的 display: none

hidden 的属性值

  • 隐藏不显示hidden、空值、无值(仅属性名)、无效值(简记:等同 空无效 )。
    • ✔️ hidden="hidden" = display: none (hh→ dn)。
    • ⚠️元素将不会参与页面布局
    • 优先级:displayhiddendisplay属性 覆盖 hidden 的隐藏状态
      • 即使存在 hidden 属性,CSS 样式为 display: block 的元素也会被显示。
    • 不再直接相关 :该元素尚未或不再与页面的当前状态直接相关,或者它被用来声明内容供页面的其他部分重用 ,而不是被用户直接访问。用户代理不应渲染处于"隐藏"状态的元素,即"不显示"
  • 查访时 才显示内容、内外边距等不隐藏(默认不显示、可在被查找和访问时显示)until-found。元素的内容将可被页面查找和片段导航访问。
    • ✔️ hidden="until-found" = content-visibility: hidden (huf→ cvh,内容可见性:隐藏)。
    • ⚠️元素会生成框参与页面布局内容不显,其他显 。默认内容不显示,但外边距(margin)、边框(border)、内边距(padding)和背景(background都会被渲染
    • 元素默认是隐藏的,但其内容将可被浏览器的 "在页面中查找"功能或片段导航访问,查找到、访问时,就会显示。
    • 用途 :可以折叠内容的一部分,同时仍然允许用户通过搜索或导航找到它
      • 浏览器处理过程 :❶ 在隐藏元素上触发 beforematch 事件 → ❷ 从元素中移除 hidden 属性 → ❸ 滚动到元素的内容。
      • hidden="until-found" ,但元素具有 display 值为 nonecontentsinline ,那么该元素将不会被"页面查找"或片段导航所显示。

注意事项

  • ❶ 无hidden属性,默认显示。有该属性,无论属性值如何,都默认隐藏元素、不显示。
  • ❷ ⚠️ hidden 属性不得"仅用于隐藏内容" 。如果某内容被标记为隐藏,它将隐藏于所有呈现方式 ,包括例如屏幕阅读器
  • 引用隐藏的描述 :可以使用 ARIA aria-describedby 属性来引用"隐藏的描述" 。虽然隐藏描述意味着它们本身可能没有用,但在这种方式下引用时,它们可以提供有用的上下文
  • ❹ 隐藏元素(有 hidden的元素)的后代元素仍然是活动的 ,这意味着脚本元素仍然可以执行,表单元素仍然可以提交。

: 各种情况下的隐藏元素。

html 复制代码
    <h2>hidden 属性:隐藏元素、不显示内容</h2>
    <p hidden="hidden">我是被隐藏的段落,我的内容不会被显示。</p>
    <p hidden="">我是被隐藏的段落,我的内容不会被显示。</p>
    <p hidden>我是被隐藏的段落,我的内容不会被显示。</p>
    <p>我是正常显示的段落,在几个被隐藏段落的下方。</p>
    <p hidden="hidden" style="display: block">我是被隐藏的段落,但同时设置了 display: block;我的内容会被显示出来。</p>
    <p hidden="until-found" id="hidden-nav1"
       style="border: 1px solid black;padding: 5px 10px;background-color: #0cc988">
        我是被隐藏的段落,我的背景色、内边距等会显示,但我的内容不会被显示,直到通过搜索或导航找到它,就会显示。</p>
    <p hidden="until-found" id="hidden-nav2"
       style="border: 1px solid black;padding: 5px 10px;background-color: #0cc988;display: none">
        我是被隐藏的段落,我的背景色、内边距等会显示,但我的内容不会被显示,通过搜索或导航也找不到它,也不会显示,因为设置了
        display:none。</p>
    <p>我是正常显示的段落,在被隐藏段落的下方。</p>
    <a href="#hidden-nav1">点击我,可以导航到被隐藏的段落,并让它显示出来。</a>
    <br>
    <a href="#hidden-nav2">点击我,无法导航到被隐藏的段落,或让它显示出来,因为 hidden="until-found" 上设置了display: none
        。</a>

    <div hidden="hidden">
        <p>我是隐藏元素 div 的后代 p 元素的内容, 我不会显示。</p>
        <script>
            // alert("我是隐藏元素 div 的后代 script 中的代码,我仍然会被执行");
        </script>
        <form action="#">
            <input type="text" aria-label="测试 hidden 属性使用">
            <button type="submit">提交</button>
        </form>
    </div>

演示效果

情景 效果
默认显示
搜索隐藏内容里的关键词(针对until-found
导航访问(针对until-found
隐藏元素的后代是活动的(后代能执行脚本、提交表单)

13. id 属性:元素在文档中"唯一的标识符"、身份证号 ⇒ 找到唯一对应的元素(属性值:命名建议 ⇒ 字数连下划,字母开头语义化,见文知其意)

id 全局属性 :定义了一个标识符 (an identifier,ID), 在整个文档中必须唯一的标识符(ID)。

  • id 是 HTML 元素的唯一标识 ,相当于给元素分配 "身份证号 ",核心作用是「精准定位 + 专属操作」。
  • id 属性的用途 :识别单个元素,通过 id 能直接找到唯一对应的元素,无需遍历筛选,效率更高。

id 核心用途

  • 锚点链接定位:使用片段标识符、页面内锚点跳转。
  • 脚本 :使用 JavaScript 操作元素。
    • 通过 id 可以快速获取页面元素(如 document.getElementById("id属性值");),进行修改内容、样式、绑定事件等操作,是 JS 操作 DOM 最常用的方式之一。
  • 设置 CSS 样式 :使用 CSS 的 id 选择器,精准样式化元素。
    • id 选择器:#id, 通过 id 可以为特定元素"设置专属样式" ,优先级高于类选择器(class)。
  • 表单标签关联 :表单 label 绑定时 识别单个元素。

id 属性值

  • 不能包含 ASCII 空白字符id 的值不得包含空格、制表符等空白字符。
    • :浏览器会将不符合规范的 ID 中的空白字符 视为 ID 的一部分
  • id = 单个唯一值(不允许多值)class 允许多个值(空格分隔),但元素只能有一个单一的 ID 值,就像人的身份证号,每个人唯一一个身份证号,不能和别人重复。
  • 命名要求有效的 CSS 标识符
    • id 属性值本身要求低,不含空白字符即可,但实际使用中,限制比较大,至少应该是有效的 CSS 标识符 。这样,id 作为 CSS 选择器时不需要转义,在 js 中使用也更方便,比如 不能使用点. ,因为. 是 CSS 中类选择器
  • ✔️ 建议命名简记字数连下划,字母开头语义化
    • ❶ 使用 ASCII 字母、数字 、下划线 _ 和 连字符 -,并且 id 属性的值应该 以字母开头
    • 使用"语义化命名"(见文知其意) :如 id="header"id="submit-btn",避免无意义的命名,如 id="a1"

注意事项

  • 唯一性 :同一个页面中,不能有相同的id值。

  • 命名规则:不能以数字开头,不能包含空格。

  • 区分大小写id="username"id="UserName" 是不同的。

  • 语义化命名 :建议使用有意义的名称,如 headermain-content 等,见文知其意,方便使用。


: 页面内锚点导航,快读跳转到定位的内容。

  • 不需要滚动页面,点击导航,直接跳转到目标区域。适合长文档。
  • id 可以作为 页面内部 链接的定位点
  • 关联关系a.href="#id"跳转到指定 id 的元素(位置)
html 复制代码
<body id="document-start" style="width: 80%;margin: 0 auto;">
    <!-- div 占位使用 -->
	<div style="height: 1000px;background-color: #91b7a2">我是文档开始处,最下方有文字。</div>

    <h2>id 属性:元素的唯一标识符,身份证号</h2>
    <h3>页面内锚点导航</h3>
    <!-- id="document-start" 写在 body 上 -->
    <a href="#document-start">跳转到文档的开始处</a>
</body>

演示效果

  • 点击链接后,跳转到文档的开始处。

: 使用 id 选择器(#id)给特定元素设置专属样式

html 复制代码
    </style>
        /* #id:使用 id 选择器,给特殊元素设置专属样式 */
        #special-p {
            color: #0f723c; /* 绿色文字 */
            font-weight: bold; /* 文字加粗 */
        }
    </style>

    <p id="special-p">我是特殊的一段文字,需要特殊的样式。</p>
    <p>我是普通的段落。</p>

演示结果


: js 中通过 id (gebi:getElementById())获取元素、操作元素。

html 复制代码
    <h3>js 中通过 id 获取元素、操作元素</h3>
    <p id="origin-p">原内容:我是默认的段落内容。</p>
    <label for="user-input">请输入内容,替换上方内容:</label>
    <br>
    <textarea name="user-input" id="user-input" cols="30" rows="10" placeholder="请输入修改内容..."></textarea>
    <button type="button" onclick="changeText()">替换段落内容</button>
    <script>
        function changeText() {
            // 通过 id 获取元素
            const originPara = document.getElementById("origin-p");
            const newContent = document.getElementById("user-input");
            originPara.textContent = newContent.value;
            originPara.style.color = "green";
        }
    </script>

演示结果


: 通过 id,进行表单标签关联。

  • 关联 label 标签和 input 标签label.for="id"
html 复制代码
    <h3>表单标签关联:label.for = "id",点击 label 标签内容,元素自动聚焦。</h3>
    <label for="nickname">昵称:</label>
    <input type="text" id="nickname" name="nickname">

演示结果

  • 增大可点击区域:点击"昵称"两字,输入框自动聚焦。

14. inert 属性:彻底冻结整个区域、完全不可交互 ⇒ 禁用元素及其所有子元素 ⇒ 不参与"任何用户交互" ⇒ 无法选中/点击/聚焦/搜索到、无法被 tab 键访问、屏幕阅读器不朗读(布尔属性;默认无样式,设置不透明度 opacity 提示被禁用)

inert美/ɪˈnɜːrt/,无效的,惰性的 属性 :全局属性、布尔属性,让一个元素及其所有子元素变得"惰性"或"不可交互 ",等于告诉浏览器:"这块区域暂时不参与"任何用户交互",请忽略它"。

  • 核心功能整个区域彻底冻结 ⇒ 全体禁用、不可交互

    • 让元素及其所有子元素变成 不可交互:不可点击、不可聚焦、不可选中、不可被屏幕阅读器读取、无法搜索的状态。
    • 全体禁用 :当元素 设置 inert 时,该元素以及该元素的所有子元素(包括 可交互的元素如链接、按钮、表单控件)都会被禁用,全都无法接收焦点、无法被点击、无法被 tab 键访问。
  • 不会触发点击(click)、聚焦(focus) 事件 :浏览器会自动跳过该元素内的所有可交互元素(如按钮、链接、输入框),不会响应鼠标或键盘事件

  • 相当于给元素加了"屏蔽罩",视觉上可能还在,但功能上完全"失效"。

    • 设置 inert 属性 无默认样式 :视觉上无区别,可设置不透明度 opacity 从视觉上表明是禁用状态。
  • ⚠️ inert 属性 和 特别的 <dialog>

    • :祖先设置了inert 属性,内部的后代 <dialog> 元素仍然可以通过 showModal() 显示出来,并且可正常交互,它们不会继承祖先的 inert 禁用属性。但,仅 <dialog> 元素比较特别,其他后代元素都会被禁用(继承 inert)。
    • 如果要禁用 <dialog> 元素及其后代 :可以在 <dialog> 元素自身上 显式设置 inert 属性。

disabled 属性和 inert 属性的区别

  • inert全局属性,谁都能禁、彻底冻结 。 用于一整块区域 (如整个 <div>、整个侧边栏),可以应用于任何元素,但它通常用于内容部分。
  • disabled非全局属性,仅单个表单元素、能读能搜到 。用于单个表单控件 (如 <input><button>)。禁用单个表单元素,使用 disabled 属性,并结合 CSS :disabled 设置样式。
对比维度 disabled 属性 inert 属性
适用元素 仅限于表单控件 。 (如 <input><button><select><textarea> 以及 <fieldset>)。 所有 HTML 元素 。 (全局属性 ,可用于 <div><section><body> 等任何元素)。
作用范围 仅作用于自身特例 :如果用在 <fieldset> 上,可以禁用其内部的所有表单控件。 作用于自身及其所有子元素 。 具有彻底的继承性,子元素无法覆盖。 特例 :内部的后代 <dialog> 元素仍然可以通过 showModal() 显示出来,并且可正常交互。
交互影响 阻止编辑和提交 。 • 无法聚焦:不能输入内容; • 按钮无法点击 • 表单提交时不会包含该字段的数据 彻底冻结区域 。 • 无法聚焦:不能输入文本; • 无法点击任何元素 • 无法选中内容
焦点管理 无法通过鼠标或 Tab 键聚焦 。 浏览器通常会对禁用控件跳过焦点 无法通过任何方式聚焦 (包括鼠标、Tab 键或 JavaScript 的 .focus() 方法)。
屏幕阅读器 会朗读但提示已禁用 。 屏幕阅读器通常会说"按钮,变灰"或"输入框,不可用",让用户知道这里有个东西但不能用。 完全忽略、屏幕阅读器不朗读 。 该区域就像不存在一样,屏幕阅读器会直接跳过,不会朗读里面的内容。
页面查找 (Ctrl+F) 可以搜到。浏览器查找功能可以定位到被禁用控件里的文字。 搜不到 。浏览器查找功能会完全忽略 inert 区域内的文本。
视觉表现 有默认样式 。 浏览器通常会自动给禁用控件套用灰色效果(例如 按钮变灰)。 无默认样式 。 完全保留原有视觉外观,需要开发者自己添加 CSS(如 opacity)来提示用户。
主要用途 控制表单交互 。 例如:表单未填写完整时禁用提交按钮;根据用户选项动态禁用某些输入项。 管理页面区域 。 例如:模态框打开时"冻结"背景内容;实现翻页组件时禁用当前不可见的页面。

使用方案

  • 如果只想让一个按钮不能点 ,或者一个输入框不能填 ,就用 disabled
  • 如果想屏蔽/禁用 一整块区域 (比如 让整个侧边栏或整个页面背景消失),就用 inert

例 1: 禁用整个区域里的内容,完全不可交互、不可点击、不可聚焦、不可选中、不可被搜索到。

html 复制代码
    <style>
        .inert-test-container {
            border: 1px solid black;
            margin: 10px 0;
            padding: 10px 5px;
        }

        [inert] {
            opacity: 0.5; /* 设置不透明度,视觉提示元素不可用,值越小,越透明 */
        }
    </style>

    <h2>inert 属性:禁用整片区域,不可聚焦、不可点击、不可选中、不可被搜索、不可被屏幕阅读器朗读</h2>
    <!-- 未加 inert 的正常区域 -->
    <div class="inert-test-container">
        <h3>可交互区域:未被 inert 禁用</h3>
        <button type="button" onclick="alert('可点击区域!')">可点击按钮</button>
        <a href="https://www.baidu.com">可跳转链接(百度)</a>
        <input type="text" placeholder="请输入内容..." aria-label="测试输入内容">
    </div>
    <!-- 加 inert 的禁用区域 -->
    <div inert class="inert-test-container">
        <h3>不可交互区域的禁用区域:被 inert 禁用,禁用元素以及所有子元素</h3>
        <button type="button" onclick="alert('不可点击区域!不该显示!')">可点击按钮</button>
        <a href="https://www.baidu.com">不可跳转链接(百度)</a>
        <input type="text" placeholder="请输入内容..." aria-label="测试输入内容">

        <!-- 默认不显示的对话框,可通过 js 的 showModal() 显示,祖先元素的 inert 属性无法阻止弹出。 -->
        <dialog id="hobby-dialog" style="background-color: #91b7a2">
        <!-- ↓ 显示禁用 dialog 整个区域,直接给 dialog 设置 inert,不通过继承 -->
        <!-- <dialog inert id="hobby-dialog" style="background-color: #91b7a2"> -->
            <form action="#"><label for="hobby">您的喜好:</label>
                <select name="hobby" id="hobby">
                    <option value="滑雪">滑雪</option>
                    <option value="冲浪">冲浪</option>
                    <option value="阅读">阅读</option>
                </select>
                <label for="custom-hobby">自定义喜好:</label>
                <input type="text" aria-label="custom-hobby" name="custom-hobby" id="custom-hobby">
                <button type="submit">提交</button>
                <button type="button" id="close-btn" onclick="document.getElementById('hobby-dialog').close();">关闭对话框
                </button>
            </form>
        </dialog>
    </div>
    <button type="button" id="open-btn" onclick="document.getElementById('hobby-dialog').showModal();">打开对话框
    </button>

演示效果

  • 第二个容器加了inert后,里面的按钮无法点击、链接无法跳转、输入框无法输入。
  • Tab 键切换焦点 时,会直接跳过这个区域的所有元素;
  • 屏幕阅读器也不会读取这个区域的内容。
演示效果
样式 无默认样式
交互 被禁用区域:完全无法交互
特别的 dialog 元素 外部的按钮,可以通过showModal()<dialog> 正常显示,<dialog>不继承 inert 属性。
显式禁用 <dialog>整个区域 直接给 <dialog >设置 inert,不通过继承。
文字无法被搜索到

例 2 : 打开自定义对话框时,形成遮罩,禁用背景页面的交互,让用户专注眼前对话框,避免用户误操作。

  • 相比传统的"手动禁用所有按钮/链接",inert更简洁,只需给父元素加 inert 属性,即可批量禁用所有子元素。
html 复制代码
    <h3>打开自定义弹窗时:禁用其他区域;关闭弹窗时,取消禁用</h3>
    <div id="bg-section" style="height: 300px;background-color: #cecece">
        <p>我是背景区域</p>
        <button onclick="alert('Hi,我是弹窗里的内容!')">弹出窗口</button>
    </div>
    <div id="custom-dialog" style="display: none;border: 1px solid black;padding: 10px;background-color:#91b7a2;">
        <p>我是自定义的对话框区域,默认隐藏</p>
        <button type="button" id="close-dialog-btn">关闭对话框</button>

    </div>
    <button type="button" id="open-dialog-btn">打开对话框</button>
    <script>
        // 通过 id 获取元素
        const bgSection = document.getElementById('bg-section');
        const customDialog = document.getElementById('custom-dialog');

        // 打开对话框,显示对话框元素,设置 禁用属性 inert,设置不透明度 0.5 辅助提示元素已禁用
        function openDialog() {
            customDialog.style.display = 'block';
            bgSection.setAttribute('inert', '');
            bgSection.style.opacity = '0.5';
        }

        // 关闭对话框,隐藏对话框元素,移除 inert 属性,重置不透明度为 1
        function closeDialog() {
            customDialog.style.display = "none";
            bgSection.removeAttribute('inert');
            bgSection.style.opacity = '1';

        }

        // 在打开和关闭按钮上 监听点击事件
        document.getElementById("close-dialog-btn").addEventListener("click", closeDialog);
        document.getElementById("open-dialog-btn").addEventListener("click", openDialog);
    </script>

演示效果

  • 点击"打开对话框"后,给背景区域设置 inert 属性,背景区域的按钮、文字等都会被inert禁用,无法点击、无法选中、无法交互;
  • 只有自定义对话框内的内容可交互;
  • 关闭对话框后,背景区域的inert被移除,恢复正常交互。

15. inputmode 属性: 提示输入的数据类型(输入模式) ⇒ 显示对应的"虚拟键盘"、优化输入体验(枚举属性;移动端有效;仅改键盘显示、不限数据类型)

inputmode 属性 :是 HTML 全局属性,枚举属性,用于提示浏览器根据输入场景(数据类型)显示 "合适的虚拟键盘"

  • 用在移动端(如手机、平板):为"虚拟键盘的显示布局"的提供一个提示 。即,当用户点击输入框时,手机会弹出什么样的键盘(是字母键盘、数字键盘还是带符号的键盘),inputmode 可以独立于 type 存在,专门用来指挥虚拟键盘的样式
  • 核心作用 :提示用户可能输入的数据类型 ⇒ 让浏览器显示对应的"虚拟键盘" ⇒ 优化用户的输入体验
  • 注 1 :仅作用于移动端虚拟键盘桌面端无效果
    • 无需改变 input 标签的 type 属性,就能优化移动端输入体验 (桌面端通常无影响),核心价值是减少用户"切换键盘"的操作,提升输入效率和准确性。
  • 注 2仅针对虚拟键盘的显示,无有效性要求。
    • inputmode 属性仅针对虚拟键盘的显示,不会强制执行任何输入的有效性要求。
    • 如果要求输入符合特定的数据类型,应该选择适当的 <input> 元素的类型 type、正则表达式 pattern 属性。

inputmode 适用"可编辑元素":需要用户输入的地方,这样才需要使用虚拟键盘。

  • <input> 元素。
  • ❷ 设置了 contenteditable 属性的元素 ⇒ 用户可编辑内容的元素。

注意事项

  1. inputmode 属性不是"表单验证"inputmode 只是改变了键盘样式,并不能 限制用户输入的内容。如果用户连接了实体键盘,或者在电脑上浏览,inputmode 不会起任何作用。
  2. 配合 pattern 使用 :如果想在 PC 端也限制输入内容,建议同时配合 pattern 属性使用。
  3. type 的关系inputmode 可以覆盖 type 属性带来的键盘样式,通常写法是两者都写上 (例如 type="text" inputmode="numeric"),既保证了语义,又精准控制了键盘。

inputmode 属性值及其对应的键盘信息

属性值 键盘名称 键盘样式 用途(适用场景)
none 无键盘模式 不显示虚拟键盘 适用于不需要文本输入的控件, 如日期选择器、自定义滑动输入等。 设备会保留物理键盘输入的可能, 但不会弹出虚拟键盘。
text 标准文本键盘 默认的字母键盘, 通常带空格键、回车键和基本的标点符号。 通用文本输入, 如姓名、地址、评论等。 这是大多数文本输入框的默认模式。
decimal美/ˈdesɪm(ə)l/ 小数数字键盘 数字键盘 + 小数点(.),部分设备可能包含负号(-)。 需要输入带小数点的数字, 如商品价格(19.99)、测量尺寸(1.5米)、 百分比(12.5%)等。
numeric美/nuːˈmerɪk/ 纯数字键盘 只有 0-9 的数字,没有小数点或其他符号。 需要输入纯数字的场景, 如验证码(123456)、PIN码(0000)、 数量(3件)、邮政编码等。
tel 电话键盘 大按键的数字键盘 + 星号(*)和井号(#)。 输入电话号码、手机号、客服热线等。 布局与传统电话拨号盘一致。
search 搜索键盘 标准字母键盘, 但右下角的回车键变为"搜索"、"前往"或放大镜图标,通常为蓝色。 站内搜索框、搜索引擎输入框。 给用户明确的动作提示,表示点击后会执行搜索。
email 邮箱键盘 标准字母键盘 + 便捷的 @ 和点号(.), 长按点号通常会出现 .com.org 等后缀选项。 输入电子邮件地址。 方便用户快速输入邮箱常用的符号和域名后缀。
url 网址键盘 标准字母键盘 + 便捷的 / 键、点号(.)键 , 长按点号可选择 .com.org 等域名后缀。 输入网址、网站链接、域名等。 键盘布局考虑了 URL 的常用符号。

补充说明

  1. 关于 none 的特别说明:这个属性值在特定场景下非常有用,比如在自定义的日期选择器或数字调节器中,可以避免不必要的键盘弹出干扰用户操作。

  2. 关于 decimalnumeric 的区别

    • numeric:严格意义上的纯数字,没有小数点。
    • decimal:包含小数点的数字键盘,适合需要精确数值的场景。
  3. 关于 text :如果不设置 inputmode,或者设置了浏览器不支持的值,默认行为就是 text,即标准文本键盘

  4. 使用建议 :在移动端开发中,建议同时设置 typeinputmode 属性。例如:<input type="number" inputmode="numeric">,这样可以同时获得语义化标签的好处和精确的键盘控制。


: 测试 inputmode 8 个属性值对应的虚拟键盘的样式。

html 复制代码
  <h2>inputmode 属性:根据输入的数据类型提示,显示对应的虚拟键盘</h2>
    <h3>1. 无虚拟键盘(inputmode="none"):通过自定义交互控件输入,不希望用户使用键盘输入。</h3>
    <br>
    <input type="text" inputmode="none" aria-label="单行文本" placeholder="type 为 text,inputmode 为 none">
    <h4>数字调节器:加减按钮(未同时设置 readonly,输入框可输入)</h4>
    <label for="number1">购买数量:</label>
    <button type="button" id="decrease-btn1">-</button>
    <!-- 设置初始值 value 为1 -->
    <input type="number" name="number" id="number1" inputmode="none" value="1">
    <button type="button" id="increase-btn1" onclick="increase()">+</button>
    <h4>数字调节器:加减按钮(同时设置 readonly,防止用户输入)</h4>
    <label for="number2">购买数量:</label>
    <button type="button" id="decrease-btn2">-</button>
    <input type="number" name="number" id="number2" inputmode="none" readonly value="1">
    <button type="button" id="increase-btn2">+</button>

    <script>
        //获取元素
        const number1 = document.getElementById("number1");
        const number2 = document.getElementById("number2");

        // 两个按钮的加法
        function increaseNumber1() {
            // 转换数据类型,运算,赋值
            number1.value = parseInt(number1.value) + 1;
        }

        function increaseNumber2() {
            number2.value = parseInt(number2.value) + 1;
        }

        // 两个按钮的减法,大于1时才能减去1
        function decreaseNumber1() {
            const number1Value = parseInt(number1.value);
            if (number1Value > 1) {
                number1.value = parseInt(number1.value) - 1;
            }
        }
        function decreaseNumber2() {
            const number2Value = parseInt(number2.value);
            if (number2Value > 1) {
                number2.value = parseInt(number2.value) - 1;
            }

        }


        // 给加减按钮添加监听事件,监听点击事件
        document.getElementById("increase-btn1").addEventListener("click", increaseNumber1);
        document.getElementById("increase-btn2").addEventListener("click", increaseNumber2);
        document.getElementById("decrease-btn1").addEventListener("click", decreaseNumber1);
        document.getElementById("decrease-btn2").addEventListener("click", decreaseNumber2);

    </script>

    <h3>2. 标准文本键盘(inputmode="text"):字母、空格、回车、标点等</h3>
    <textarea name="comment" id="comment1" cols="30" rows="10"  inputmode="text" placeholder="inputmode 为 text" aria-label="请输入评论"></textarea>
    <textarea name="comment" id="comment2" cols="30" rows="10"   placeholder="未使用 inputmode" aria-label="请输入评论"></textarea>
    <br>
    <input type="text" placeholder="type 为 text,无 inputmode" aria-label="单行文本输入">
    <br>
    <input type="text" inputmode="text" placeholder="type、inputmode 都为 text" aria-label="单行文本输入">

    <h3>3. 纯数字键盘(inputmode="numeric"):1-9 纯数字键盘,无小数点、无字母,适合验证码、PIN 码</h3>
    <label for="phone-code">请输入6位手机验证码:</label>
    <input type="text" id="phone-code" name="phone-code" inputmode="numeric" pattern="\d{6}">

    <h3>4. 带小数点的数字键盘(inputmode="decimal"):带小数的数字,如 数学运算、金额</h3>
    <label for="price">价格:</label>
    <input type="number" name="price" id="price" inputmode="decimal" placeholder="type 等于 number,请输入价格,如 19.99">
    <input type="text" name="price" id="price2" aria-label="价格" inputmode="decimal" placeholder="type 等于 text,请输入价格,如 19.99">

    <h3>5. 电话键盘(inputmode="tel"):数字、*、# ,方便快速拨号</h3>
    <input type="tel" name="phone" id="phone1" aria-label="电话号码" placeholder="type 为 tel,无 inputmode">
    <br>
    <input type="text" name="phone" id="phone2"  inputmode="tel" aria-label="电话号码" placeholder="type 为 text,inputmode 为 tel">
    <br>
    <input type="tel" name="phone" id="phone3"  inputmode="tel" aria-label="电话号码" placeholder="type、inputmode 都为 tel">

    <h3>6. 邮箱键盘(inputmode="email"):字母、@、.com和点号 .</h3>
    <input type="email" name="email" id="email1" aria-label="邮箱" placeholder="type 为 email,无 inputmode">
    <br>
    <input type="text" name="email" id="email2"  inputmode="email" aria-label="邮箱" placeholder="type 为 text,inputmode 为 email">
    <br>
    <input type="email" name="email" id="email3"  inputmode="email" aria-label="邮箱" placeholder="type、inputmode 都为 email">

    <h3>7. 搜索键盘(inputmode="search"):虚拟键盘回车键 可能变为"搜索"、"前往"或放大镜</h3>
    <input type="search" name="search" id="search1" aria-label="搜索" placeholder="type 为 search,无 inputmode">
    <br>
    <input type="text" name="search" id="search2"  inputmode="search" aria-label="搜索" placeholder="type 为 text,inputmode 为 search">
    <br>
    <input type="search" name="search" id="search3"  inputmode="search" aria-label="搜索" placeholder="type、inputmode 都为 search">

    <h3>8. 网址键盘(inputmode="url"):虚拟键盘含 / 、 . 和 .com,方便输入网址 </h3>
    <input type="url" name="url" id="url1" aria-label="搜索" placeholder="type 为 url,无 inputmode">
    <br>
    <input type="text" name="url" id="url2"  inputmode="url" aria-label="网址" placeholder="type 为 text,inputmode 为 url">
    <br>
    <input type="url" name="url" id="url3"  inputmode="url" aria-label="网址" placeholder="type、inputmode 都为 url">

演示效果

虚拟键盘
无虚拟键盘(none 实测type="text" 时不弹出虚拟键盘,type="number" 时弹出虚拟的数字键盘,同时设置 readonly 不再弹出虚拟键盘。
标准文本键盘(text 默认的键盘,标点符号、数字等都有。
纯数字键盘
带小数点的数字键盘
电话键盘
邮箱键盘
搜索键盘
网址键盘

16. is 属性:"自定义内置元素"⇒ 让普通 HTML 标签拥有"自定义元素的功能、样式" (Safari 不支持;is="自定义元素的名称";代码复用)

is 属性 :一个 HTML 全局属性,最核心的作用是:让普通的 HTML 标签摇身一变,成为自定义的"Web 组件"

  • 自定义内置元素 :比如,可以创建一个自定义的"超级按钮",带有特殊功能和样式 ,然后, 在普通按钮 <button> 标签上 通过 is="自定义元素名称" 属性激活,普通按钮就会表现得像"超级按钮",拥有赋予的超能力,在 Web 开发中,这被称为自定义内置元素 (customized built-in element)。
    • 它与创建全新的 HTML 标签( autonomous custom elements,独立 自定义元素 ,如 <my-button>)是两种不同的自定义元素方式。
  • is 属性值is="自定义元素的名称",有 is 属性,普通 HTML 元素 会当作"自定义元素"实例化,拥有自定义元素的功能、样式。

is 属性的主要用途

  1. 代码复用 :将一组通用的逻辑(比如点击追踪、特殊样式、防抖处理)封装在一个组件里,然后通过 is 属性在任何需要的地方"激活"它。
  2. 渐进增强 :即使用户的浏览器不支持 Web Components,使用了 is 属性的元素(如 <button is="my-button">)仍然是一个功能正常的普通按钮,保证了基础可用性。
  3. 语义化(基于 HTML 标签扩展功能) :无需创造 <super-button> 这样搜索引擎不认识的标签,而是基于 <button> 这个语义本身就非常明确的标签来扩展功能,这对 SEO 和可访问性更友好。

工作原理和步骤

  1. 定义一个类 :创建一个 JavaScript 类 ,它必须继承自 想要扩展的 HTML 元素的原生类 (比如 HTMLButtonElement 对应 <button>HTMLDivElement 对应 <div>)。
  2. 定义生命周期 :在这个类里,可以添加 connectedCallback()(当元素被添加到文档时 触发)等生命周期函数,来添加想要的特殊功能
  3. 注册这个类 :使用 window.customElements.define() 方法来注册刚刚创建的类,并给它一个名字(比如 "fancy-button")。这个名字就是将要用在 is 属性里的值
  4. 在 HTML 中使用(普通 HTML 元素,被当作"自定义元素"实例化) :在 HTML 里,写一个普通的 <button> 标签,然后加上 is="fancy-button" 属性。这时,浏览器就会把这个"普通的按钮",当作定义的那个"超级按钮"来实例化,让普通标签具有"自定义元素的功能和样式"。

: 让普通元素具有"自定义元素的功能和样式"。

html 复制代码
    <h2>is 属性:让普通 HTML 元素拥有"自定义元素的功能、样式"</h2>
    <!-- 普通按钮,无特殊功能、样式 -->
    <button>普通按钮</button>
    <!-- 有特别功能和样式,因为使用了 is="fancy-button",普通按钮被当成自定义按钮实例化-->
    <!-- 即使 js 加载失败,它本身仍然是一个普通按钮,和 完全自定义的元素,如标签名 my-button 不同 -->
    <br>
    <br>
    <button is="fancy-button">我有自定义按钮 fancy-button 的功能、样式</button>
    <br/>
    <br>
    <button is="fancy-button">我也有自定义按钮 fancy-button 的功能、样式</button>

    <script>
        // 定义一个类,名为 FancyButton,继承自 HTMLButtonElement
        // 拥有原生按钮 <button> 的所有功能
        class FancyButton extends HTMLButtonElement {
            // 构造函数,创建这个类的新实例时自动调用
            constructor() {
                // 先调用 super(),正确继承父类(HTMLButtonElement)的属性方法,相当于执行父类的构造函数
                super();
                // 将 handleClick 方法绑定到当前实例的 this 上下文,让 内部的 this 总是指向当前按钮的实例
                this.handleClick = this.handleClick.bind(this);

            }

            // 定义一个方法,名为 handleClick,处理点击事件,该方法被添加到事件监听器中

            handleClick() {
                alert("我是自定义按钮的弹窗!");
            }

            // 生命周期回调函数:元素被成功插入到 DOM 树中时 自动调用
            // web components 规范中定义的 标准生命周期方法
            connectedCallback() {
                // 给当前按钮添加"点击事件的监听器",this.handleClick 作为回调函数
                this.addEventListener("click", this.handleClick);

                // 添加自定义样式
                this.style.border = "2px solid green"; // 设置边框:宽度2px、实线、绿色
                this.style.padding = "10px 20px";// 设置内边距:上下 10px,左右20px
                this.style.backgroundColor = "#e0e0e0";// 设置背景色为浅灰色
                this.style.cursor = "pointer"; // 设置鼠标悬停的样式 为手指样式

                // 弹出提示框,告知用户按钮已被激活
                // alert('自定义按钮已激活!');
                //控制台日志,告知按钮已被激活
                console.log('自定义按钮已激活!')

            }

            // 生命周期回调函数:元素从 DOM 树中移除时 自动调用
            // 用于清理工作,避免内存泄露,让程序使用的内存,在使用完毕后及时释放,避免占内存位置,导致程序变慢、卡顿
            disconnectedCallback() {
                //弹出提示框,告知按钮被移除
                alert("自定义按钮已被移出");
                // 移除事件监听器,断开对按钮的引用,如果不移除监听,引用一直在,回收机制就不能回收
                // 注:必须与添加事件监听时完全一样的函数引用
                this.removeEventListener("click", this.handleClick);
            }

        }

        // 注册"自定义元素":将自定义的类 FancyButton 注册为 自定义元素
        // 参数1:自定义元素的标签名(必须含连字符) fancy-button;
        // 参数2:对应的类 FancyButton
        //参数3:配置对象,这个类扩展自 <button> 元素 {extends:"button"}

        customElements.define("fancy-button", FancyButton, {extends: "button"});


    </script>

效果说明:

  • ❶ 页面加载后,浏览器的控制台会输出"自定义按钮已激活!",

    • ❷ 带有 is="fancy-button" 的两个按钮:会自动拥有 JavaScript 中定义的绿色边框、内边距和背景色,当按钮被点击时,弹出一个提示框,"我是自定义按钮的弹窗!"。
  • ❸ 第一个没有 is 属性的普通按钮:不会有这些外观、日志、弹窗。

    • 如果加上 is="fancy-button" 属性,也会有一样的功能和样式。

总结is 属性就像是一个"激活器"。预先定义好一套增强功能和样式 (自定义元素),然后通过在普通的 HTML 标签上写 is="自定义元素名称",来告诉浏览器:"请把这个普通的标签,按照我的自定义元素(fancy-button)来升级一下。" 如此,就能写出更干净、更具语义、又能复用的代码。


关键概念补充说明:

  1. 继承关系extends HTMLButtonElement 意味着这个类获得了原生按钮的所有能力,比如可以参与表单提交、可以被 disabled 属性禁用等。

  2. 生命周期

    • constructor创建实例 ):实例创建时,此时元素还不存在于页面中。
    • connectedCallback添加元素 ):元素被添加到页面时,添加功能、样式、添加事件监听。
    • disconnectedCallback移除元素 ):元素从页面移除时,移除事件监听。
  3. 事件监听的管理 :在 connectedCallback 中添加监听,在 disconnectedCallback 中移除监听,这是一种良好的编程习惯,可以防止内存泄漏。

  4. 绑定 this.bind(this) 确保了事件处理函数中的 this 始终指向按钮实例,而不是触发事件的那个元素(在某些情况下可能不同)。

  5. 注册元素customElements.define 告诉浏览器有一个名为 fancy-button 的自定义元素类型存在,并且它是对原生按钮的扩展。


17. itemid 属性:微数据项的"全球唯一的标识符"(3属性搭配、全球唯一:必须同时设置 itemscope、itemtype 指明数据项的作用范围、具体类型;单独设置无效 ;属性值:itemid="url / urn 统一资源名称")

itemid 属性 :全局属性,为 HTML 中的结构化数据(微数据 )提供一个全球唯一的标识符。相当于一个"身份证号",用于告诉搜索引擎:页面上这个"东西"(比如一本书、一部电影)就是那个全球公认的"东西"。

  • 关键词 :标识符、全球唯一、整个互联网唯一、url/urn、识别为同一事物、3个属性搭配

  • 核心用途 :给数据一个全球通用的"身份证",itemid的主要目的是消除歧义

    • 当不同页面描述同一个实体(例如,特定的书籍、电影、人物)时,itemid 就能让机器(如搜索引擎)准确地将它们识别为同一个事物,从而更智能地整合和展示信息。
  • itemid 属性值 = 必须是"全球标识符"itemid="url / urn"

    • 通常是一个 URL统一资源定位符 )或 URN统一资源名称 ),例如 一本书的 ISBN号(urn:isbn:0-374-22848-5),而不是一个任意的字符串 。这样做的目的是确保其全球唯一性

使用 itemid 时,必须遵守的严格规则:

  • 同时设置 3 个属性(必须配合使用)itemid 不能单独设置,必须同时设置了 itemscopeitemtype 属性,才有效。目的是给这个微数据的唯一 id 指定具体范围、类型 ,是谁的唯一 id ?书?人?。
    • itemscope(范围:谁是数据项) :创建一个数据域 = 指定数据项的范围 (Scope),写在某个div里,则代表这个div是一个数据项。
    • itemtype(类型:什么类型的数据项) :给这个域指定类型(Type),人?电影?评论?定义它能拥有哪些属性。
    • itemid(数据项id:全球唯一标识):给这个特定类型、特定范围内的实体赋予全球唯一的标识符(ID)。
    • 一个层层递进的依赖关系itemscope(指明是独立的微数据实体,指明微数据开始和范围 = 该标签是一个数据项) → itemtype(当前实体的具体类型, 一个标准词汇表,如 schema.org,人、书、电影等)→ itemid (当前类型中唯一的 id,全球唯一的身份证号,如书籍的 ISBN 号)。
    • :普通 id 只在当前网页内唯一,itemid 必须在"整个互联网上唯一",用来精准标识一个标准化实体。
  • 单独使用→ 无效的 itemid
    • 如果把 itemid 单独使用,或者只放在 itemscope 而不放 itemtype 上,语法上就是错误的。 浏览器解析时会直接忽略 itemid,因为它无法判断这个 ID 到底是指向一本书、一个人,还是一个毫无意义的随机字符串。
    • itemid 可选 :不写 itemid 完全没问题,必须写的只有:itemscope(声明这是"微数据实体") + itemtype(实体的具体类型)。

微数据的核心用处schema.org 术语表 + 微数据 → 开发者给 HTML 添加额外语义信息搜索引擎理解"具体含义" → 优化"搜索结果 " → 用户找到"正确网页"。

  • schema.org 词汇表与 微数据 microdata 结合起来使用,为 HTML 内容添加额外信息 ,让搜索引擎 能理解它的具体含义
  • 例如:"英雄"这个词,是具体的词汇,还是电影名《英雄》?人可以理解,搜索引擎如何区分?如果是电影名,则可以专门指明是"电影"类型( <div itemscope itemtype="https://schema.org/Movie">),搜索引擎就可以精准区分它的含义了,搜索引擎都会依据这些标记来优化搜索结果 ,让人们更容易找到正确的网页
  • Schema.org 中文站Schema.org.cn美/ˈskiːmə/schema.org 的中文站点。
  • :如果想打开 schema.org 原站,一般需要科学上网(且代理可能需要开全局模式 global)。

: 用微数据标记一本书,让搜索引擎更容易理解。

  • 创建了一个描述列表(<dl>)来展示一本书的详细信息:
  • itemscope:指定范围,声明此处开始一个微数据条目,<dl>是一个微数据项。
  • itemtype="https://schema.org/Book":指定这个数据项的类型是一本书。
  • urn:isbn:9787010009254" :为这本书赋予全球唯一的标识符------它的 ISBN 号。这告诉搜索引擎,无论在哪里遇到这个 itemid,指的都是同一本书。
  • 内部的 itemprop 属性:用来定义这本书的具体属性 ,如标题(title)、作者(author)和出版日期(datePublished)。
html 复制代码
    <h2>itemid 属性:微数据实体、具体类型的"全球唯一身份证号 id(搜索引擎可读、用户不可见、源代码可见)</h2>
    <h3>创建一个描述列表,展示一本书的详细信息</h3>
    <dl itemscope itemtype="https://schema.org/Book" itemid="urn:isbn:9787010009254">
        <dt>书名</dt>
        <dd itemprop="title">《毛泽东选集》</dd>
        <dt>作者</dt>
        <dd itemprop="author">毛泽东</dd>
        <dt>出版时间</dt>
        <dd itemprop="datePublished">1951年10月12日</dd>
    </dl>

演示效果

:虽然 itemid 在概念上很清晰,但在现代Web开发中,它的使用率非常低。主要原因在于,有一种更先进、更简洁的替代方案被广泛采用:JSON-LD (JavaScript Object Notation for Linked Data ,直译为"用于链接数据的 JavaScript 对象表示法")。

JSON-LD :通过一个独立的 <script> 标签 来定义结构化数据,实现了内容与数据的完全分离。例如,用 JSON-LD 实现上面同样的书籍标记,代码会更加清晰易读:

html 复制代码
<!-- 这是用户实际看到的 HTML 内容,保持简洁 -->

    <dl>
        <dt>书名</dt>
        <dd>《毛泽东选集》</dd>
        <dt>作者</dt>
        <dd>毛泽东</dd>
        <dt>出版时间</dt>
        <dd>1951年10月12日</dd>
    </dl>


<!-- 这是为机器准备的结构化数据,独立存在 -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",// 使用的术语表:我要用的是 schema.org 这本词典
  "@type": "Book",// 类型:这是一个"书"类型的事物
  "@id": "urn:isbn:9787010009254",// id 标识:这本书的全球唯一 ID 是它的 ISBN 号
  "name": "《毛泽东选集》",// 属性:书名
  "author": {// 属性:作者(作者本身又是一个人类型的事物,所以,里面可以再嵌套一个 @type)
    "@type": "Person",
    "name": "毛泽东"
  },
  "datePublished": "1951-10-12"// 属性:出版日期
}
</script>
  • 总结 :❶ 术语表 url(@context)、❷ 类型(@type)、❸ 标签id 或 全球唯一id (@id)、❹ 属性 (属性名、无@

  • 注 1 :JSON-LD 中的 @id 就对应了 HTML 中 itemid 的角色。

    • @id 值的两种含义:
    • @id = 标签 id#id)。值是 "#review-123" 这种带 # 的格式时,它就是在引用 HTML 标签的 id 值。
    • @id = itemid(全球唯一idurn/ url)。值是 "urn:isbn:..." 或 "https://..." 这种格式时,就是在给实体一个全球唯一的身份证号(itemid 属性值)。
  • 注 2 :鉴于Google 等主流搜索引擎明确推荐使用 JSON-LD ,如果为了SEO(搜索引擎优化)而学习结构化数据,建议直接学习 JSON-LD。itemid 现在更多地是作为一个需要了解的技术概念,除非你在维护一些使用了微数据(Microdata)的老项目,否则在实际开发中几乎用不到它。

  • 注3:很多网站中,微数据 和 JSON-LD 是一起使用的,如 哔哩哔哩网站。


结构化数据:schema.org 术语表词典、微数据 、JSON-LD(关联数据/链接数据:机器看的"数据说明书")

结构化数据 :是一种提供标准化格式 、用于标记页面内容 ,以便搜索引擎等机器更好理解的数据。

  • 核心目标(服务用户、快速找到相关结果) :开发者给网页内容添加语义 → 搜索引擎能理解语义、优化搜索结果 → 用户能快速找到"正确的结果"

一个生活中的类比: 去图书馆找书。

  • 如果图书馆只是把所有书堆成一座山(就像普通的、非结构化的网页),需要一本本翻看才能找到想要的书。
  • 一个好的图书馆,会把书按照标准化的规则 (如 分类法)放在特定位置 (如文学区、科技区),并且给每本书贴上标签(如书名、作者、ISBN号)。这样,就能快速定位到目标。
  • 结构化数据 ,就是给网页内容贴上的、机器能读懂的标准标签 ,并把它们放进搜索引擎这个"大图书馆"的特定区域里。

结构化数据的核心价值:

  • 关键词:添加语义、理解内容、展示丰富结果、提升点击率
  • 对机器友好 :给网页内容 添加语义帮助搜索引擎 (以及 AI 搜索,如 ChatGPT Search)准确"理解页面的内容"是什么(是一篇文章、一个产品、还是一个活动?)。
  • 展示更丰富 :如果标注了页面的内容(这个数字是价格,那个数字是评分),让网页在搜索结果中能显示丰富摘要 ,比如:
    • 产品的价格、库存、评分
    • 文章的作者、发布时间、封面图
    • 活动的时间、地点
  • 提升点击率:更吸引人的搜索结果,通常能带来更高的点击率。

如何实现结构化数据?

  • 实现结构化数据,主要分三步走。

第一步:选择一个"语法"(你用什么格式写)

需要一种方式把数据告诉机器。目前主流的语法有三种,它们的关系就像用不同语言写同一篇文章:

语法格式 实现方式 优点 现状
JSON-LD 使用 <script> 标签,在页面任何位置(如 <head><body>)单独放置一段数据代码。 与 HTML 内容分离,代码干净,易于维护,是 Google 官方推荐的格式。 目前最主流、最推荐
微数据 直接在 HTML 标签内添加 itemscopeitemtypeitempropitemid属性。 数据和展示耦合在一起。 使用率低,通常只在维护老项目时遇到
RDFa 类似微数据,也是通过 HTML 属性来实现。 功能更强大,但语法更复杂。 使用率较低

第二步:选用一个"词典"(用什么词汇描述)

  • 确定了语法后,需要一套标准的词汇来描述网页的内容。这就用到了 Schema.org
  • Schema.org 是百度、谷歌、微软等主流搜索引擎共同维护的一个词汇表网站 。它定义了所有能想到的事物的"标准名称 "。比如:
    • 文章用 Article
    • 产品用 Product
    • 人物用 Person
    • 书的属性用 name(书名)、author(作者)、isbn(ISBN号)

总结JSON-LD / 微数据格式Schema.org词汇 。比如,用 JSON-LD 这种格式,把从 Schema.org 里查到的词汇组合起来,放进网页的代码里,就形成了完整的结构化数据。

第三步:动手实现 :参见上 itemid 属性小节中的示例。

第四步:验证代码

  • 写完代码后,使用搜索引擎提供的免费工具验证:
  • 开发时校验(JSON-LD 语法检查)JSON-LD Playground
  • 上线前终审(Google 官方工具)

: 在"富结果测试"工具中的效果。

html 复制代码
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "无线降噪耳机 X100",
  "image": "headphone.jpg",
  "offers": {
    "@type": "Offer",
    "price": "599",
    "priceCurrency": "CNY",
    "availability": "https://schema.org/InStock"
  },
  "review": {
    "@type": "Review",
    "reviewRating": "4.5",
    "author": "李四"
  }
}
</script>
  • 结构化数据 = 目标(让机器理解网页内容,并展示丰富结果)
  • 实现方法 = 语法 + 词汇
  • 当前最佳实践 = JSON-LD (语法) + Schema.org (词汇)

Schema.org 是搜索引擎们(Google、Bing、百度等)共同维护的"词典" ,它定义了所有事物应该叫什么名字。比如,书应该叫 Book,作者应该叫 author,书名应该叫 name

  • 共同点 :微数据(itemscopeitemtypeitemiditemprop)、JSON-LD 都是从 schema.org 这个术语表词典里抄词汇,抄到自己网页的代码里 → 让搜索引擎理解网页内容 → 优化搜索结果 → 用户搜索到想要的内容。
  • schema.org 术语表词典:提供词汇、划分类型。
  • 微数据、JSON-LD :把词汇写进网页的代码里,进行关联 (如 "简爱",是一个人名,还是在在说某个书名?说的是人,还是书?)
  • 搜索引擎:根据网页代码里的词汇表,进一步理解网页的内容,优化搜索结果。

JSON-LD :全称是 JavaScript Object Notation for Linked Data ,中文可以翻译为"基于 JSON 表示关联数据 "。简单来说,它是一种使用 JSON 格式来在网络上传输"结构化数据"的方法。

  1. JSON-LD ,是 "给机器看的 数据说明书"
  • HTML 是给人看的,负责页面样式和内容。
  • JSON-LD 是给机器(主要是 搜索引擎)看的,它藏在 HTML 的 <script> 标签里,用一种标准化的格式告诉搜索引擎:"这个页面上有一本书,书名是XXX,作者是YYY,ISBN 是ZZZ。"
  • 优点 :它实现了内容与数据的分离 。页面上正常展示给用户看的内容,和藏在 <script> 标签里喂给搜索引擎的数据,可以互不干扰,这使得代码更干净,也更容易维护。

  1. 它如何与 Schema.org 协同工作?
  • Schema.org 是搜索引擎们(Google、Bing、百度等)共同维护的"词典" ,它定义了所有事物应该叫什么名字。比如,书应该叫 Book,作者应该叫 author,书名应该叫 name

  • JSON-LD 则是书写这本"词典"的"语法"和"纸张"。按照 JSON-LD 的语法规则,把从 Schema.org 里查到的词汇写下来,就形成了一段搜索引擎能看懂的"结构化数据"


  1. 为什么 JSON-LD 如此流行? 相比之前我们聊过的、需要把属性直接写在 HTML 标签里的"微数据"方式,JSON-LD 有两个巨大的优势:
  2. 维护简单 :所有结构化数据集中在一个 <script> 标签里,不需要改动页面的核心 HTML 结构。
  3. 搜索引擎官方推荐 :Google 等主流搜索引擎明确表示,优先推荐使用 JSON-LD 来实现结构化数据。因为它最稳定、最不容易出错,也最容易解析。
  • 总结一下: JSON-LD 就是写给搜索引擎看的、关于网页内容的一份标准格式的数据摘要 。而这份摘要所用的词汇,都来自 Schema.org。如果是为了做 SEO(搜索引擎优化)而学习结构化数据,直接学习 JSON-LD 就是当下最正确、最高效的选择。

18. itemprop 属性:属性名/标准词汇名称、贴标签、数据项的"具体属性"⇒ "名称-值"对的名称( itemprop 属性值="Schema.org 的标准词汇"= 根据 itemtype 具体类型;值 = 字符串、url;父元素中:必须有 itemscope、itemtype ⇒ 指明数据项范围、具体类型)

itemprop 属性 :全局属性,用于向项目"添加属性"每个 HTML 元素 都可以指定一个 itemprop 属性,而每个 itemprop"名称-值"对组成。

  • 关系 :一个HTML 元素 → 对应 一个 itemprop 属性 → 对应 一个"名称-值"对。
    • 每个"名称-值"对= 称为一个属性(property ),一个或多个属性 = 形成一个项目(item)。
    • 数据项里嵌套数据项时 ,值可以是:多个"名称-值"对(一个项目),itemprop 同时搭配 itemscopeitemtype
  • 核心用途itemprop 为 HTML 元素添加机器可读的属性名 ,形成「名称-值」语义对。
  • ① "名称 ":itemprop的属性值 (= "Schema.org 的标准词汇") ;
  • :字符串、url
    • a. 普通文本标签 :取 "元素的文本内容" 作为值(如 spanph1);

    • b. 链接/资源标签取"对应属性值"

      • <a><area><link> :取 href值,链接地址。
      • <time>:取 datetime值,时间值。
      • <meter>:取 value值,当前值。
      • <data>:取value 值,数据值。
      • audiovideotrackembediframeimgsource:值 = 取 src 值,资源地址。
      • <object>data值,资源地址。
      • 数据项嵌套 :值 = 一个数据项(多个"名称-值"对)。一个元素中,同时设置 itempropitemscopeitemtype属性:数据项嵌套 ⇒ 值 = 一个数据项(可能多个"名称-值"对)。
      • <meta>itemprop 设置在<meta>上,值 = content 值。
    • :同个数据项,内部可以有多个属性值相同的itemprop属性 ,分别对应"相同的名称、不同的值"。


  • itemprop解决的需求

  • 关键词:添加语义、Schema.org、标准词汇、纯语义标记

    • 网页内容"语义化" :让机器明确"这段文字是什么" 。让搜索引擎、爬虫、辅助工具读懂内容含义,而非单纯识别文本。(比如"这是一个价格""这是作者的名字")。
    • 结构化数据:实现 HTML 与结构化数据的紧密绑定, 零散文本打包成规范数据。
    • 提升搜索结果的展示效果:提升 SEO 展示效果(星级、价格、时效等)、适配搜索富结果展示。
  • itemprop 不能单独使用,必须与 itemscopeitemtype 配合,这三者共同构成 微数据 语法。即,需要指定微数据的作用范围、具体的类型,然后才能指定该类型下的一个个属性,比如某个日期,是生日的日期?还是发布日期?需要先指定具体的类型。

    • itemprop 必须在 含有 itemscope 父元素内部,否则无语义效果。
  • itemprop 属性值中的"名称" :优先使用 Schema.org的标准词汇,避免自定义名称,确保搜索引擎识别。

  • itemprop 不改变页面布局和样式,纯语义标记,兼容所有现代浏览器。

属性 作用
itemscope 创建一个"数据项"(布尔属性),表示一个新的条目开始
itemtype 指明数据项的类型(URL),例如某个 Schema 定义
itemprop 定义数据项中的具体属性 ,如 nameprice
  • 简记口诀

微数据有三宝,

scope 圈地盘,

type 定身份,

prop 贴标签。

搜索靠它懂内容,

富摘要里显神通。

内联标注最精准,

维护旧项目立大功。


微数据标记口诀

父级先加 itemscope 和 itemtype,

属性绑定 用 itemprop;

类型认准 Schema 标,

机器可读语义好;

文本取值看内容,

链接资源取属性;

不扰样式纯语义,

SEO 提升靠它记。


口诀 对应知识点
微数据有三宝 itemscopeitemtypeitemprop 必须配合使用
scope 圈地盘 itemscope 定义数据项的边界范围
type 定身份 itemtype 指明类型,如 https://schema.org/Movie
prop 贴标签 itemprop 给具体内容标注属性名,如 nameprice
搜索靠它懂内容 让搜索引擎理解"这是什么"而不是"这显示什么"
富摘要里显神通 搜索结果可显示星级、价格、时效等增强样式
内联标注最精准 直接在 HTML 元素上标注,数据与显示严格绑定
维护旧项目立大功 老项目常使用微数据,而非 JSON-LD

一句话极简版

scope 圈地,type 定类,prop 贴标,嵌套再加 scope。


例 1:普通 HTML(只有显示效果)

  • 人能看到内容,但程序不知道《悬崖上的金鱼姬》是电影名,"宫崎骏"是导演。
html 复制代码
<div>
  <h1>《悬崖上的金鱼姬》</h1>
  <p>导演:宫崎骏</p>
  <p>上映时间:2008年7月19日</p>
</div>

例 2:使用 itemprop 添加语义,让机器能读懂内容的含义

html 复制代码
<div itemscope itemtype="https://schema.org/Movie">
  <h1 itemprop="name">《悬崖上的金鱼姬》</h1>
  <p>导演:<span itemprop="director">宫崎骏</span></p>
  <p>上映时间:<time itemprop="datePublished" datetime="2008-07-19">2008年7月19日</time></p>
</div>

效果说明:

  • 数据项的"范围" itemscope:告诉程序,这个 <div> 里是一个"数据项"。
  • 数据项的"具体类型" itemtype:指明这个数据项的类型是 Movie(遵循 schema.org 定义)
  • 数据项的"具体属性" itemprop
    • name 表示"名称"
    • director 表示"导演"
    • datePublished 表示"发布日期"

这样一来,搜索引擎抓取时,可以明确提取出

  • 电影名:《悬崖上的金鱼姬》
  • 导演:宫崎骏
  • 上映时间:2008-07-19

例 3: 嵌套的微数据(数据项),"商品"里的"售价+评价"。

  • 标注商品名称、价格、图片、评分,搜索引擎可直接展示富摘要。
html 复制代码
<div itemscope itemtype="https://schema.org/Product">
  <!-- 商品名称 -->
  <span itemprop="name">蓝牙耳机</span>
	<!-- 商品图片 -->
  <img src="headphones.jpg" itemprop="image">
	<!-- 商品价格 -->
  <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
    <span itemprop="price">399</span>
    <span itemprop="priceCurrency">CNY</span>
  </div>

  <div itemprop="review" itemscope itemtype="https://schema.org/Review">
    <!-- 商品的评分 -->
    <span itemprop="reviewRating">4.5</span> 星
     <!-- 用户名 -->
    <span itemprop="author">李女士</span>
  </div>
</div>

19. itemref 属性:被点名的元素 也是我的属性 ⇒ 引用元素 id、关联"外部属性" ⇒ 同一个数据项的多个属性,不必放在一个父元素下(微数据;属性值:itemref="id 值/ 多值空格分隔";必须搭配:itemscope、itemtype )

itemref 属性 :微数据(microdata),全局属性,把 itemscope 所在元素 外部的 HTML 元素关联到当前"微数据项" 中,让分散在页面任意位置的属性,归属于同一个数据项。

  • 核心作用 :当某个属性无法直接放在 itemscope 的容器内部时,可以通过 itemref 引用页面其他位置的元素 ,将这些元素"拉入"当前项目的属性集合中。
    • 即:被我点名( id) 的元素,也是我的属性
  • 微数据默认规则 :只有嵌套在 itemscope 元素内部的元素,才能作为它的属性(子元素使用 itemprop)。如果元素不在父元素内部(如 布局需要),就必须用 itemref 关联。
  • 解决需求 :允许跨 DOM 结构来组织微数据,不必把所有的 itemprop 都嵌套在同一个父元素下
    • 解决问题:属性不在父元素内部 → 无法归属"微数据项" 的问题。
  • :设置itemref 时, 必须同时设置itemscope (数据项的作用范围)、itemtype (数据项的具体类型),指明了微数据的作用范围、具体类型,再关联到"当前的数据项"才有意义。

核心用法 :❶ 添加 id + ❷ 引用 iditemref="id 值",空格分隔)。

  • 外部元素加 id属性,itemscope 所在元素用 itemref="id1 id2" 引用 id
  • :无显示效果,仅用于搜索引擎 / 机器解析"结构化数据"

itemref 简记口诀

复制代码
微数据里属性散,
itemref 来关联。
空格隔开多个 id,
天涯海角都能连。
itemscope 先声明,
itemtype 定类型。
属性分散不用愁,
一个引用全拉平。

逐句解析

口诀 说明
微数据里属性散 使用 Microdata 时,一个项目的属性可能分散在页面各处
itemref 来关联 itemref 的作用就是把分散的属性关联起来
空格隔开多个 id 多个被引用的元素用空格分隔它们的 id
天涯海角都能连 被引用的元素可以在 DOM 的任何位置,不受层级限制
itemscope 先声明 必须先有 itemscope 定义项目
itemtype 定类型 itemtype 指定项目类型(如 Schema.org
属性分散不用愁 属性写在其他地方也没关系
一个引用全拉平 itemref 一引用,所有属性都归入该数据项

更精简版(适合快速记忆)

itemscope 先立户,

itemtype 定身份。

属性分散别处放,

itemref 拉进门。

多个 id 空格分,

天涯若比邻。


例 1:不写在同一个父元素下时,外部的"数据项的属性"丢失。

  • 微数据只能读取 name 属性,另外的ageaddress 丢失。
html 复制代码
<!-- 微数据项:用户信息 -->
<div itemscope itemtype="https://schema.org/Person">
  <h3 itemprop="name">李四</h3>
  <!-- 年龄、城市 不在这个 div 内部,不属于该微数据项 -->
</div>

<!-- 这两个元素在外部,默认不归属上面的数据项 -->
<p itemprop="age">30</p>
<p itemprop="address">上海</p>

例 2 : ✔️ 设置 itemref,关联外部属性。

  • ❶ 设置id:给外部属性所在的元素设置 id
  • ❷ 引用id:数据项(itemscope所在元素上):设置 itemref → 引用id,关联外部的数据项的属性。
  • itemref 的值 = 外部元素的 id(多个 id空格分隔
  • 结果:nameageaddress 全部归属同一个用户微数据(数据项)。
html 复制代码
    <h2>itemref 属性:引用 id,关联外部的"数据项属性"</h2>
    <!-- 引用id:在 itemscope 所在元素上,用 itemref 引用 id,空格分隔多个 id-->
    <div itemscope itemtype="https://schema.org/Person" itemref="user-age user-city">
        <h3 itemprop="name">李四</h3>
    </div>

    <!-- 添加id:给外部属性元素添加id -->
    <p id="user-age" itemprop="age">30</p>
    <p id="user-city" itemprop="address">上海</p>

20. itemscope 属性: 数据项的作用范围 ⇒ 该标签内的内容是"一个数据项",包括后代(布尔属性)

itemscope 属性 : 是一个布尔属性,全局属性,Microdata(微数据) 格式中的一个核心属性,用于定义相关元数据的范围 。为元素指定 itemscope 属性,会创建一个新的项目 ,从而产生与元素关联的一系列"名称-值对"

  • 核心作用 :是定义一个"项目(数据项)"的范围 ,让机器理解网页的内容

    • 告诉浏览器或搜索引擎:"从这里便签的这里开始,标签内的内容描述的是一个特定类型的实体/ 数据项(比如一本书、一个人、一个产品)。"
  • itemscope 的作用范围:该标签的内部,该元素的开始标签 → 闭合标签,并且包含所有嵌套的子元素。

    • 注:内部嵌套的 itemscope 会创建独立的新作用域。
    • 嵌套规则: 子元素的 itemscope 创建独立作用域,属性不混用。
    • 父级影响: 父 itemscope 不能访问子 itemscope 内的属性。
  • 微数据的基本三件套

    • itemscope:声明一个数据项的范围(布尔属性)。
    • itemtype:指定这个数据项的类型(通常是 Schema.org 的 URL)。
    • itemprop:定义数据项的具体属性(Schema 标准词汇名称)。
    • 这三个属性配合使用,让网页中的 HTML 元素变得对机器可读 ,= 搜索引擎能"理解网页内容的具体含义",如"简爱"两个字,是某个人名字,还是指名为"简爱"的小说?
    • 简记口诀:数据项 item,scope 范围,type 类型,prop 属性。
  • 微数据对网站的好处机器 (搜索引擎、爬虫、AI助手)理解网页内容丰富搜索结果生成富摘要提升网站的点击率

  • :现代开发更推荐使用 JSON-LD 代替微数据

    • 结构分离 :JSON-LD 写在 <script> 标签中,与 HTML 分离,不污染 HTML 内容结构。
    • 集中管理、易于维护。
    • Google 官方推荐的实现方式,更容易通过 Google 结构化数据测试工具验证。
  • JSON-LD @id 的值:指明数据项的作用范围 (=itemscope)、或 指定数据项的全球唯一的身份证号 (=itemid

    • 作用范围 : 是 "#review-123" 这种带 # 的格式时,它就是在引用 HTML 标签的 id 值。
    • 全球唯一身份证号 :当它是 "urn:isbn:..." 或 "https://..." 这种格式时,就是在给实体一个全球唯一的身份证号(指向itemid 属性值)。

: 让搜索引擎能准确地理解:这个标签内容描述的是一个叫"张团团"的人,这个人是前端开发工程师,在某公司工作。

html 复制代码
   <h2>itemscope 属性:指定数据项的作用范围</h2>
    <!-- itemscope:数据项的作用范围,该标签内是一个数据项 -->
    <!-- itemtype:数据项的类型 = 人 -->
    <div itemscope itemtype="https://schema.org/Person">
        <!-- itemprop:标记出人的姓名 -->
        <h3 itemprop="name">张团团</h3>
        <!-- itemprop:标记出人的职位 -->
        <p>职位:<span itemprop="jobTitle">前端开发工程师</span></p>
        <!-- itemprop:标记出人的公司名称 -->
        <p>公司:<span itemprop="worksFor">某某科技有限公司</span></p>
    </div>

    <!-- json-ld 的写法 -->
    <script type="application/ld+json">
        {
            "@context": "https://schema.org",
            "@type": "Person",
            "name": "张团团",
            "jobTitle": "前端开发工程师",
            "worksFor": "某某科技有限公司"
        }
    </script>

演示结果

  • 机器可读,普通人不可见。

21. itemtype 属性:数据项类型 = "词汇表的url" (属性值:itemtype = "schema.org 词汇表的具体类型 URL";搭配 itemscope、itemprop 使用)

itemtype 属性 :全局属性,用于在数据结构中定义 itemprop (数据项的属性)的词汇表的 URL ,指明数据项的类型(人、电影、产品...?)。

  • 关键词:数据项类型、词汇表url
  • 词汇表:告诉搜索引擎"这块内容是什么 ",帮助搜索引擎更准确地理解和展示页面内容
    • 简单说,普通 HTML 只告诉浏览器"怎么显示" ,而 itemtype 告诉搜索引擎 "这是什么意思"。
  • 属性值itemtype = "schema.org 词汇表的具体类型 URL"
    • 谷歌和其他主要搜索引擎支持 schema.org 词汇表 用于结构化数据。该词汇表定义了一套标准的类型名称属性名称
  • 搭配属性itemscope 属性,指明该数据项类型的作用范围 ,指明了范围,才知道哪里到哪里 是我们所指的数据项类型
  • 好处 :添加机器可读的语义→ 搜索结果里显示更丰富的信息→ 增加网站的点击率

微数据的价值

  • 更好的搜索结果展示(提高点击率) :不在于技术本身,而在于 SEO 效果------让搜索引擎更好地理解网页的内容,从而获得更好的搜索展示
  • ❷ 它不直接影响前端显示------只是给机器看的数据,用户看不到任何视觉变化。
    • 但用户搜索该内容时,相关搜索结果的展示会更友好,视觉上的变化在这里。
  • ❸ 现代推荐用 JSON-LD,但原理相同,都是为页面提供结构化数据

例 1: 无结构化数据的一个产品页面。

html 复制代码
<!-- ❌ 没有结构化数据:搜索引擎只能靠猜 -->
<div>
  <h1>iPhone 15 Pro</h1>
  <p>5999元</p>
  <p>5星好评</p>
</div>

搜索引擎看到这段代码,只知道有标题、数字、文字,但不知道内容的具体含义

  • "5999元"是价格还是型号编号?
  • "5星"是评分还是等级?
  • 这是产品、文章还是其他东西?

例 2: 有结构化数据的产品页面。

html 复制代码
<!-- ✅ 使用 itemtype:明确告诉搜索引擎这是一个"产品" ,itemtype="https://schema.org/Product"-->
<div itemscope itemtype="https://schema.org/Product">
	<!--产品名叫 iPhone 15 Pro(itemprop="name")-->
  <h1 itemprop="name">iPhone 15 Pro</h1>
  <span itemprop="price">5999</span>元
  <div itemprop="review" itemscope itemtype="https://schema.org/Review">
    <span itemprop="reviewRating">5</span>星
  </div>
</div>

有结构化数据(此处是"微数据")的标注,现在搜索引擎能精确理解

  • itemtype="https://schema.org/Product":指明数据项类型,这是一个产品。
  • itemprop="name":产品名叫 iPhone 15 Pro
  • itemprop="price":价格是 5999 元
  • itemprop="reviewRating":有 5 星评价

可能的搜索结果对比

  • 普通搜索结果

    iPhone 15 Pro - 苹果官网
    www.apple.com/iphone-15-pro
    苹果公司最新款手机...

  • 添加微数据的富搜索结果,对用户更友好,提供的信息更多。

    ★★★★★ (128条评价) ← 评分星星
    iPhone 15 Pro
    ¥5999 - ¥7999 ← 价格区间
    苹果公司最新款手机...
    [库存状态] 有货 ← 实时库存


22. lang 属性:指定元素内容的语言 (设置页面语言:设置 在 html 标签上;属性值:lang="语言-地区/可选"; zh-CN、en-US;语言小写地区大, 连字符号中间挂)

lang 属性 :一个全局属性,可以在任何 HTML 元素上使用,用于指定元素内容的语言

  • 指定页面语言的好处
    • 屏幕阅读器:根据语言,选择正确的语音库和发音规则。
    • 搜索引擎优化: 帮助搜索引擎识别页面语言,精准定位目标用户。
    • 浏览器功能:影响翻译功能触发、默认字体、拼写检查等行为。

lang 的 属性值lang="语言-地区(可选)"

  • lang = "语言子标签" 或 "语言子标签-地区子标签"
    • 遵循 BCP 47 标准(国际标准),由 语言子标签 和可选的 地区子标签 组成,用连字符 - 连接。
    • 未知语言 :如果属性值为空字符串lang="" ),语言设置为未知(unknown);
    • 无效值 :如果语言标签不符合 BCP47,则设置为无效(invalid)。
  • 推荐写法语言+地区,更精确。

语言小写地区大, 连字符号中间挂。

zh 是中文,en 是英语,

CN 大陆,TW 台湾,US 美国,GB 英国。

标准写法要记牢, zh-CN、en-US 最常见。

最佳实践建议

  1. 始终在 <html> 上设置 lang:设置整个页面的语言。
  • 语言的继承 :如果一个元素没有 lang 属性,它将继承其父节点上设置的 lang 值,而父节点又可能从其父节点继承该值,以此类推。
  1. 尽量使用 语言-地区 的完整格式 (如 zh-CN 而非仅 zh)。

  2. 语言代码小写,地区代码大写

  3. 使用连字符 -,不要用下划线

  4. 页面内切换语言时,在对应元素上"单独标注"
    完全省略 lang 属性、不使用lang的后果:

  5. 可访问性问题(屏幕阅读器):用户可能听到错误的发音(例如用英文语音读中文)。

  6. SEO 损失:搜索引擎难以准确识别页面语言,影响国际搜索排名。

  7. 浏览器-用户体验问题

    • 翻译:浏览器可能错误地提示翻译页面。
    • 拼写检查:可能无法正确工作。

lang 属性虽然简单,但它连接了:

  • 技术:HTML、CSS、JavaScript。
  • 用户:可访问性需求(视障用户)。
  • 机器:搜索引擎、浏览器。
  • 体验:正确的发音、翻译、排版。

lang 属性的用处(简记口诀)

页面定语言,辅助识发音。

搜索懂区域,排版样式精。

缺了体验差,加上才安心。

lang 属性定语言, 屏幕阅读发音准。

搜索引擎认区域, 排版字体样式稳。

浏览器里防误译, 拼写检查也精准。

一行代码虽简单, 可访问性有灵魂。


例 1基础用法指定"整个页面的语言"

  • <html> 标签上设置,这个是页面的根元素。
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>我的网站</title>
</head>
<body>
    <p>这是一个中文网站。</p>
</body>
</html>

效果

  • 屏幕阅读器:会使用中文语音库朗读。
  • 浏览器:识别为简体中文页面。
  • 搜索引擎:将其索引为中文内容

html 复制代码
    <style>
        /* 根据 不同的 lang 属性值,设置不同的样式*/

        /*中文引号*/
        /* q:lang(zh) - 选择本身有 lang="zh" 属性的 <q> 元素*/
        /* :lang(zh) q - 选择在 lang="zh" 的元素内部的 <q> 元素*/
        q:lang(zh), :lang(zh) q {
            quotes: "「" "」" "『" "』";
        }

        /*英文引号*/
        q:lang(en), :lang(en) q {
            quotes: '"' '"' "'" "'";
        }
    </style>

例 2多语言混排,为不同段落指定语言。

  • 机器遇到不同的语言时,切换到不同处理方式,比如 屏幕阅读器,可能切换到三种语言,读以下的三个段落。
html 复制代码
    <h3>多语言混排:为不同段落指定不同的语言</h3>
    <p lang="zh">我是中文内容</p>
    <p lang="en">I'm the content in English</p>
    <p lang="fr">Je suis le contenu en français</p>

例 3CSS 根据不同的语言→ 应用不同的样式。

html 复制代码
    <h3>⑶ CSS 根据不同的语言应用不同的样式:中文使用「」引号,英文使用 "" 引号</h3>
    <p>金缨:<q lang="zh">日日行,不怕千万里。常常做,不怕千万事。</q></p>
    <br />
    <p>Eileen Gu:<q lang="en">Pain is temporary.</q></p>

例 4给语言添加"地区子标签"进行更精细的控制。

  • 简体中文:lang="zh-CN"
  • 繁体中文(台湾):lang="zh-TW"
  • 繁体中文(香港):lang="zh-HK"
  • 美式英语:lang="en-US"
  • 英式英语:lang="en-GB"

效果

  • 搜索引擎:能精确区分语言的地区版本
  • 屏幕阅读软件:zh-CNzh-TW会使用不同的中文语音库。

23. nonce 属性:内容安全策略 CSP 的"白名单" ⇒ 一次性的加密数字/字符串 = 一次性通行证 ⇒ 允许"特定的内联脚本、样式"执行( nonce="服务器生成的随机数";使用占位符→ 服务器生成后注入)

nonce(= Number used once,一次性数字) :一次性的加密数字/字符串 (a cryptographic美/ˌkrɪptəˈɡræfɪk/ nonce),主要用于内容安全策略 中,nonce的核心作用是:允许特定的内联脚本或样式执行,同时阻止所有未经授权的内联代码

  • 关键词:安全策略、一次性、加密、内联脚本/样式的执行、白名单、通行证

  • 简单来说,nonce 是一种"白名单机制 "------只有携带正确且唯一 nonce 值的脚本才能执行。

  • nonce 的本质 :是在严格的 CSP 策略中,为合法内联代码开一个"安全通道"。它完美解决了"既要防止 XSS,又要保证网站功能正常"的矛盾,是现代 Web 安全防御的核心技术之一。

  • nonce 属性有助于允许特定元素执行 ,比如 特定的内嵌脚本(<script>)或样式元素(<style>)。可以避免使用 CSP 的 unsafe inline 指令,这个指令允许列出所有内嵌脚本或样式

  • nonce 属性值nonce="服务器生成的随机数"

    • 注:出于安全考虑,nonce 属性值会被隐藏(返回空字符串 ),防止攻击者窃取 nonce 数据。
    • script.getAttribute("nonce"); //返回空字符串
    • 注:访问 noncenonce 属性是访问 nonce 的唯一方式。
      • script.nonce; // 返回 nonce 值
  • 使用场景nonce 主要用于内容安全策略CSPContent Security Policy) 中,以精确控制内联脚本和样式的执行。当我们需要允许特定内联脚本运行 ,但又不想完全放弃 CSP 保护时,nonce 是首选方案。

核心原则

  1. 唯一性(随机数) :每次服务器响应时,都必须生成一个全新的、不可预测的 nonce 值(必须使用加密安全的随机数生成器 ,如 crypto.randomBytes()secrets.token_urlsafe())。

  2. 关联性 :这个 nonce 值需要同时出现在 HTTP 响应头Content-Security-Policy 策略中和 HTML 页面内 <script> 标签的 nonce 属性里。

  3. 一次性(一次一个值)每次页面加载 都必须生成全新的 nonce 值,不可重复使用。浏览器在验证通过后,会忽略该 nonce,同一个页面加载过程中重复使用 将无法通过验证。

  4. 不存储nonce 值不需要在服务器端存储,只需在生成时 同时用于响应头和 HTML 即可

nonce 的工作流程

复制代码
用户访问页面
    ↓
服务器生成随机 nonce (如 "abc123xyz")
    ↓
┌─────────────────────────────────────┐
│ HTTP 响应头                          │
│ Content-Security-Policy:             │
│   script-src 'nonce-abc123xyz'       │
└─────────────────────────────────────┘
    ↓
┌─────────────────────────────────────┐
│ HTML 内容                            │
│ <script nonce="abc123xyz">           │
│    合法代码                          │
│ </script>                            │
│                                      │
│ <script>恶意代码</script>             │
│ <!-- 没有 nonce 属性 → 被阻止 -->      │
└─────────────────────────────────────┘
    ↓
浏览器验证:nonce 值匹配 → 执行
          nonce 值不匹配或无 nonce → 阻止

nonce 的简记口诀

  • 一次一值、随机生成、响应头配置、标签加属性、匹配才执行。

一次一值不重复

随机生成猜不出

响应头里写策略

脚本标签配属性

匹配通过才执行

恶意代码全拦住


口诀 含义
一次一值不重复 每次页面加载必须生成全新的 nonce,绝对不能重复使用。
随机生成猜不出 必须用加密安全的随机数生成器(如 secretscrypto)。
响应头里写策略 CSP 响应头中声明:script-src 'nonce-xxx'
脚本标签配属性 HTML 脚本标签添加:<script nonce="xxx">
匹配通过才执行 浏览器对比两个 nonce 值,一致才允许执行。
恶意代码全拦住 没有 noncenonce 错误的脚本全部被 CSP 阻止。

使用 Node.js 服务器测试 nonce 属性

第一步 :先安装 node.js(搜教程),如果已安装可忽略。

  • 打开 代码编辑器的终端,输入node -v,如果看到版本号,说明已经安装成功。

第二步 :创建一个 .html 文件,这里起名 global-attributes.html

  • 添加{``{NONCE}} 占位符 (双层花括号,大写):nonce="{``{NONCE}}"
    • 在 HTML 文件的<style><script>nonce 属性值中添加 {``{NONCE}} 占位符,写在 <style><script> 标签上(= 想执行的内联样式、脚本) ,让服务器可以动态注入 nonce
html 复制代码
 <!-- 在 style 标签中使用 nonce -->
    <style nonce="{{NONCE}}">
    css 代码...
    </style>

 <!-- 在 script 标签中使用 nonce -->
 <script nonce="{{NONCE}}">
 javascript 代码...
</script>

global-attributes.html 文件的代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试全局属性 nonce</title>
     <!-- 在 style 标签中使用 nonce -->
    <style nonce="{{NONCE}}">

    </style>
</head>
<body>
    <h2>nonce 属性:内容安全策略的白名单,一次性的加密数字(= 一次性通行证)</h2>
    <!-- <div id="users-comments"> -->
    <!--     &lt;!&ndash; 用户的留言:被直接渲染 &ndash;&gt; -->
    <!--     <div>用户1: 今天天气真好!</div> -->
    <!--     <div>用户2: <script>alert('XSS攻击!')</script></div> -->
    <!-- </div> -->

    <!-- &lt;!&ndash; 网站自己的内联脚本 &ndash;&gt; -->
    <!-- <script> -->
    <!--     console.log('页面加载完成'); -->
    <!--     document.getElementById('comments').style.backgroundColor = '#f0f0f0'; -->
    <!-- </script> -->

    <!-- 显示当前 nonce 值 -->
    <div class="test-area" id="nonce-info">
        <strong>当前 nonce 值:</strong>
        <code id="nonce-value">{{NONCE}}</code>
    </div>

    <!-- 测试1:对应带正确 nonce 的脚本(应该执行),脚本执行成功会替换文本 -->
    <div class="test-area">
        <h3> 测试1:带 nonce 的内联脚本(应该执行)</h3>
        <div id="test1-result">等待执行...</div>
    </div>

    <!--  测试2:不带 nonce 的脚本(应该被 CSP 阻止) -->
    <div class="test-area">
        <h3> 测试2:不带 nonce 的内联脚本(应该被 CSP 阻止)</h3>
        <div id="test2-result">等待执行...</div>
    </div>

    <!--  测试3:动态创建脚本(应该被阻止) -->
    <div class="test-area">
        <h3>测试3:动态创建脚本(应该被阻止)</h3>
        <button onclick="testDynamicScript()">尝试动态添加脚本</button>
        <div id="test3-result" style="margin-top: 10px;"></div>
    </div>

    <!--  测试4:eval() 函数(应该被阻止) -->
    <div class="test-area">
        <h3> 测试4:eval() 函数 (应该被阻止)</h3>
        <button onclick="testEval()">尝试执行 eval()</button>
        <div id="test4-result" style="margin-top: 10px;"></div>
    </div>

    <!--  测试5:内联事件处理器(应该被阻止) -->
    <div class="test-area">
        <h3> 测试5:内联事件处理器(应该被阻止)</h3>
        <button onclick="alert('这个弹窗应该被 CSP 阻止!')">点击测试内联事件</button>
        <p style="font-size: 14px; color: #666;">注意:这个按钮的 onclick 属性应该被 CSP 阻止</p>
    </div>

    <!-- ============ 测试1的脚本:带 nonce 的脚本区域 ============ -->
    <script nonce="{{NONCE}}">
        console.log('✅ 测试1:带 nonce 的脚本执行成功!');
        console.log('当前 nonce 值:', '{{NONCE}}');

        // 更新测试一的页面显示内容,提醒内联脚本执行成功

        const testResult1 = document.getElementById('test1-result');
        testResult1.innerHTML =
            ' 我是带 nonce 的脚本生成的内容,出现这段文字,说明我已执行成功!✅️<br>' +
            ' 控制台已输出 nonce 值,按 F12,查看[控制台]。';
        // 设置测试一的字体的颜色
        testResult1.style.color = 'green';

        // 改变背景色,如果证明脚本生效
        // document.body.style.backgroundColor = '#e8f5e9';

        // 显示 nonce 值
        document.getElementById('nonce-value').textContent = '{{NONCE}}';
    </script>

    <!-- ============ 测试2的脚本,不带 nonce 的脚本(应该被阻止) ============ -->
    <script>
        const testResult2 = document.getElementById('test2-result');
        console.log('⚠️ 这个内联脚本无 nonce,不应该被执行!如果出现在控制台,说明 CSP 未生效!');
        testResult2.innerHTML =
            '❌ 错误:不带 nonce 的脚本被执行了!CSP 可能未生效。';
        testResult2.style.color = 'red';
    </script>

    <!-- ============ 测试3、测试4的脚本,动态添加的脚本 script,测试函数(带 nonce) ============ -->
    <script nonce="{{NONCE}}">
        function testDynamicScript() {
            const testResult3 = document.getElementById('test3-result');
            try {
                const script = document.createElement('script');
                script.textContent = "alert('动态创建的脚本执行了!')";
                document.body.appendChild(script);
                testResult3.innerHTML =
                    '⚠️ 动态脚本已添加,但应该被 CSP 阻止(查看控制台)';
                testResult3.style.color = 'orange';
            } catch(e) {
                testResult3.innerHTML =
                    '❌ 错误: ' + e.message;
                testResult3.style.color = 'red';
            }
        }

        function testEval() {
            const testResult4 = document.getElementById('test4-result');
            try {
                eval('alert("eval() 执行了!")');
                testResult4.innerHTML =
                    '⚠️ eval() 执行了!这不应该发生';
                testResult4.style.color = 'red';
            } catch(e) {
                testResult4.innerHTML =
                    '✅ eval() 被 CSP 阻止了!<br>错误信息: ' + e.message;
                testResult4.style.color = 'green';
            }
        }

        console.log('所有测试函数已加载。');
    </script>

    <!-- 使用说明 -->
    <div class="test-area" style="background: #f0f7ff;">
        <h3>📖 使用说明</h3>
        <ul>
            <li><strong>按 F12</strong> 打开开发者工具,查看 Console 标签</li>
            <li><strong>刷新页面</strong>,观察 nonce 值是否每次都在变化</li>
            <li><strong>查看 Console 中的红色错误</strong>,了解哪些脚本被 CSP 阻止了</li>
            <li><strong>点击各个按钮</strong>,观察 CSP 如何阻止危险操作</li>
            <li><strong>切换到 Network 标签</strong>,查看响应头中的 CSP 策略</li>
        </ul>
    </div>
</body>
</html>

第三步 :创建 server.js 文件,和 html 文件放在一个文件夹里。

  • 把以下代码写进 server.js 文件。
javascript 复制代码
// ============================================
// 第1部分:导入 Node.js 内置模块
// ============================================

// 导入 http 模块:用于创建 Web 服务器
// Node.js 内置模块,不需要额外安装
const http = require('http');

// 导入 fs 模块:用于读取文件(File System)
// 可以读取硬盘上的 HTML、CSS、JS 等文件
const fs = require('fs');

// 导入 crypto 模块:用于生成加密的随机数
// 这里用来生成安全的 nonce 值
const crypto = require('crypto');

// 导入 path 模块:用于处理文件路径
// 可以跨平台(Windows/Linux/Mac)正确处理路径
const path = require('path');

// ============================================
// 第2部分:配置服务器参数
// ============================================

// 定义服务器监听的端口号
// 3000 是常用开发端口,你也可以改成 8000、8080 等
const PORT = 3000;

// ============================================
// 第3部分:创建 HTTP 服务器
// ============================================

// 创建服务器实例
// http.createServer() 接收一个回调函数
// 这个回调函数会在每次有请求时被调用
const server = http.createServer((req, res) => {
    // req (request):请求对象,包含浏览器发来的信息(URL、方法、头信息等)
    // res (response):响应对象,用来向浏览器返回数据(HTML、CSP头等)
    
    // 在控制台打印请求的 URL
    // 例如:访问 http://localhost:3000/ 会打印 "📡 请求: /"
    // 这样你可以看到浏览器请求了哪些文件
    console.log(`📡 请求: ${req.url}`);

    // ============================================
    // 第4部分:处理 HTML 页面请求(核心逻辑)
    // ============================================
    
    // 判断请求的 URL 是什么
    // req.url 是浏览器请求的路径
    // 例如:/ 表示根路径,/global-attributes.html 表示具体文件
    // 不管用户访问 / 还是 /global-attributes.html,我们都返回同一个 HTML 文件
    if (req.url === '/' || req.url === '/global-attributes.html' || req.url === '/index.html') {
        
        // 构建 HTML 文件的完整路径
        // __dirname 是当前文件(server.js)所在的目录
        // path.join 会把目录和文件名拼接成完整路径
        // 例如:/Users/你的用户名/HTML-demos/global-attributes.html
        const htmlPath = path.join(__dirname, 'global-attributes.html');

        // 读取 HTML 文件
        // fs.readFile 是异步函数,不会阻塞服务器
        // 参数1:文件路径
        // 参数2:编码格式 'utf8' 表示读取为文本(而不是二进制)
        // 参数3:回调函数,文件读取完成后执行
        fs.readFile(htmlPath, 'utf8', (err, html) => {
            // err:错误对象,如果读取失败(比如文件不存在)会有值
            // html:文件内容,如果读取成功就是一个字符串
            
            // 检查是否有错误(例如文件不存在)
            if (err) {
                // 在控制台打印错误信息,方便调试
                console.error('❌ 读取文件失败:', err);
                
                // 设置响应状态码为 404(Not Found)
                // writeHead 的第一个参数是状态码
                // 第二个参数是响应头对象,这里告诉浏览器返回的是 HTML
                res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
                
                // 返回错误页面给浏览器
                // 使用模板字符串(反引号)可以嵌入变量 ${__dirname}
                res.end(`
                    <h1>❌ 找不到文件</h1>
                    <p>请确保 global-attributes.html 文件存在于当前目录</p>
                    <p>当前目录: ${__dirname}</p>
                `);
                return;  // 结束函数执行,不再往下走
            }

            // ============================================
            // 第5部分:生成 nonce 值(核心中的核心)
            // ============================================
            
            // 生成随机 nonce 值
            // crypto.randomBytes(16):生成16个随机字节(128位)
            // .toString('base64'):把随机字节转换成 base64 字符串
            // 结果类似:'8tG7jK3mQ9wR2xY5'(每次请求都不同)
            const nonce = crypto.randomBytes(16).toString('base64');
            
            // 在控制台打印生成的 nonce,方便观察每次刷新是否变化
            console.log(`🔑 生成 nonce: ${nonce}`);

            // ============================================
            // 第6部分:把 nonce 注入到 HTML 中
            // ============================================
            
            // 替换 HTML 中的占位符 {{NONCE}} 为真正的 nonce 值
            // .replace(/\{\{NONCE\}\}/g, nonce) 的作用:
            //   - /\{\{NONCE\}\}/g 是一个正则表达式
            //   - {{NONCE}} 是字面意思,但花括号在正则中有特殊含义,所以需要转义 \{\{
            //   - g 表示全局替换(替换所有出现的,不只是第一个)
            // 例如:把所有的 {{NONCE}} 都替换成 "8tG7jK3mQ9wR2xY5"
            const modifiedHtml = html.replace(/\{\{NONCE\}\}/g, nonce);

            // ============================================
            // 第7部分:设置 CSP 响应头(最关键的安全配置)
            // ============================================
            
            // 设置响应头
            // writeHead 的第一个参数:200 表示成功(OK)
            // 第二个参数:响应头对象
            res.writeHead(200, {
                // 告诉浏览器返回的内容是 HTML,编码是 UTF-8
                'Content-Type': 'text/html; charset=utf-8',
                
                // 🔐 关键:Content-Security-Policy 响应头
                // 这个头告诉浏览器哪些脚本可以执行
                // script-src:指定脚本的来源策略
                // 'nonce-${nonce}':只允许 nonce 属性等于这个值的脚本执行
                // 'strict-dynamic':高级特性,允许通过合法脚本动态加载的其他脚本
                // 注意:nonce-${nonce} 中的 ${nonce} 会被替换成真正的 nonce 值
                // 最终效果类似:script-src 'nonce-8tG7jK3mQ9wR2xY5' 'strict-dynamic'
                'Content-Security-Policy': `script-src 'nonce-${nonce}' 'strict-dynamic'`
            });

            // ============================================
            // 第8部分:发送响应给浏览器
            // ============================================
            
            // 把修改后的 HTML 内容发送给浏览器
            // res.end() 结束响应,并把数据发送给客户端
            res.end(modifiedHtml);
            
            // 在控制台打印成功信息
            // nonce.substring(0, 10) 只显示 nonce 的前10个字符,避免太长
            console.log(`✅ 响应发送成功 (nonce: ${nonce.substring(0, 10)}...)`);
        });
    }
    // ============================================
    // 第9部分:处理静态资源请求(CSS、JS、图片等)
    // ============================================
    else {
        // 如果请求的不是 HTML 文件(比如 style.css、script.js、图片等)
        // 就进入这个分支
        
        // 构建请求文件的完整路径
        // 例如:请求 /style.css,就会去找 __dirname/style.css
        const filePath = path.join(__dirname, req.url);
        
        // 获取文件的扩展名
        // path.extname 返回文件后缀,如 '.css', '.js', '.png'
        const ext = path.extname(filePath);

        // 定义允许访问的文件类型白名单(安全考虑)
        // 只允许这些类型的文件被访问,防止恶意访问系统文件
        const allowedExts = ['.html', '.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg'];

        // 检查文件扩展名是否在白名单中
        if (!allowedExts.includes(ext)) {
            // 不在白名单中,返回 404 错误
            res.writeHead(404);
            res.end('Not found');
            return;  // 结束函数执行
        }

        // 读取文件
        fs.readFile(filePath, (err, data) => {
            // 如果读取失败(文件不存在),返回 404
            if (err) {
                res.writeHead(404);
                res.end('File not found');
                return;
            }

            // ============================================
            // 第10部分:根据文件类型设置正确的 Content-Type
            // ============================================
            
            // 声明变量,默认是纯文本
            let contentType = 'text/plain';
            
            // 根据扩展名设置对应的 MIME 类型
            // MIME 类型告诉浏览器如何解析文件
            switch (ext) {
                case '.html': 
                    contentType = 'text/html'; 
                    break;
                case '.css': 
                    contentType = 'text/css'; 
                    break;
                case '.js': 
                    contentType = 'application/javascript'; 
                    break;
                case '.png': 
                    contentType = 'image/png'; 
                    break;
                case '.jpg': 
                case '.jpeg': 
                    contentType = 'image/jpeg'; 
                    break;
            }

            // 发送响应
            // 注意:静态资源文件不需要设置 CSP 头,因为它们不包含脚本
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(data);  // data 是文件的二进制内容
        });
    }
});

// ============================================
// 第11部分:启动服务器,开始监听端口
// ============================================

// server.listen 启动服务器
// 参数1:监听的端口号(PORT)
// 参数2:启动成功后的回调函数
server.listen(PORT, () => {
    // 这个回调函数在服务器成功启动后执行
    // 打印美观的启动信息,让用户知道服务器已经准备好了
    
    console.log('\n🚀 ====================================');
    console.log(`✅ CSP nonce 测试服务器已启动`);
    console.log(`📍 访问地址: http://localhost:${PORT}`);
    console.log(`📄 测试文件: global-attributes.html`);
    console.log(`💡 按 Ctrl+C 停止服务器`);
    console.log('====================================\n');
});

// ============================================

// 补充说明:代码执行流程

// ============================================

/* 运行 node server.js 后:

  1. 服务器启动,等待请求(监听 3000 端口)
  2. 浏览器访问 http://localhost:3000/
  3. 服务器收到请求,进入回调函数
  4. 判断 req.url === '/' 成立,进入 HTML 处理分支
  5. 读取 global-attributes.html 文件
  6. 生成随机密码 nonce(例如:AbCd123XyZ...)
  7. 替换 HTML 中的 {{NONCE}} 为真正的 nonce
  8. 设置 CSP 响应头:script-src 'nonce-AbCd123XyZ...'
  9. 把处理后的 HTML 发送给浏览器
  10. 浏览器收到 HTML,看到 <script nonce="AbCd123XyZ...">
  11. 浏览器对比脚本的 nonce 和 CSP 头中的 nonce
  12. 匹配成功 → 执行脚本;不匹配 → 阻止脚本
    */
    // ============================================
    // 常见术语解释
    // ============================================

/*

  • reqrequest 的缩写,请求对象
  • resresponse 的缩写,响应对象
  • __dirname:当前文件所在的目录路径(Node.js 全局变量)
  • nonce:Number used once,一次性数字(一次性随机密码)
  • CSP:Content Security Policy,内容安全策略
  • MIME:告诉浏览器文件类型 (如 text/html 表示 HTML 文件)
  • callback:回调函数,异步操作完成后执行的函数
    */

第四步运行服务器

  • 打开终端(命令提示符/PowerShell),使用 cd 命令,进入项目目录server.js 所在文件夹)。
  • 运行服务器:node server.js

第五步在浏览器中测试。

打开浏览器(Chrome 或 Firefox)

访问:http://localhost:3000

F12 打开开发者工具

查看 Console(控制台) 标签

预期结果

  • 不能执行的内联脚本(无 nonce),会有红色错误提示

  • 点击各个按钮测试

    • 如果 动态生成的 nonce 生效,就只有 测试1会生效,其他的测试都无反应。

  • 查看响应头的 内容安全策略

  • 刷新页面,观察 nonce 值是否变化


24. part 属性:shadow 内部元素"穿透 shadow 边界"→ 暴露特定元素 → 外部 css 可以设置样式、被外部 CSS 用 ::part() 选中(使用方式:双冒part 圆括号 → ::part(part属性值))

part 属性 :允许Shadow DOM 内部的元素"主动暴露自己" ,让外部的 CSS 能够穿透 Shadow DOM 边界 进行样式定制

  • 关键词:完全隔离、选择性暴露、外部样式定制、只暴露一个层级

核心用处

  • 解决"封装过严"问题 :Shadow DOM 默认完全隔离外部样式part 提供了可控的"出口"
  • 保留封装性 :不是完全破坏隔离,而是有选择地暴露特定元素
  • 组件定制 :让组件库使用者能够自定义内部特定部分的样式

注意事项

  1. 不能穿透"嵌套 Shadow DOM" :无法使用 ::part(header)::part(title) 这样的链式选择器。
  2. 只暴露"一个层级":被暴露元素内部的 Shadow DOM 不会被暴露。
  3. 无法通过 part 选择子元素::part(header) span 无效。

简记口诀

  • 剖开影子露接口,样式穿透不乱走;多命名空隔 单值匹,链式嵌套都没有。
  1. 剖开影子露接口part 的唯一目的,就是让 Shadow DOM 内部的元素 能被外部 CSS 用 ::part() 选中
  2. 样式穿透不乱走 :它提供了受控的样式穿透,只暴露特定元素,不破坏整体的封装性。
  3. 多命名空隔单值匹 :一个元素可以设置多个 part 名(如 part="header large"),用空格隔开,外部选择器只要匹配其中任意一个名字就能选中它。
  4. 链式嵌套都没有 :使用上的两大限制 ------① 不能写 ::part(header)::part(button) 这种链式 ;② 不能写 ::part(header) span 这种嵌套子元素选择器

例 1 : 用外部样式给 shadow 内部的元素设置样式。

  • 使用语法双冒part 圆括号::part(part属性值)
    • 选中 part="content"::part(content)
html 复制代码
<style>
        /*外部样式定制 */
        /*定义样式,用于定制自定义组件的外观 -*/
        /* 选择器 "custom-card::part(header)" 意思是:
           选中 <custom-card> 组件内部,part 属性值为 "header" 的那个元素 */
        custom-card::part(header) {
            background: #056705; /* 将头部背景色设置为深绿色 */
            color: white; /* 文字颜色设置为白色 */
            font-weight: bold; /* 文字加粗 */
        }
        /*不生效,不能选中 part 的子元素*/
        custom-card::part(header) small {
            color: red;
        }

        /*生效,直接使用 part 名选中*/
        custom-card::part(small) {
            color: pink;
        }

        /*不生效,无法使用"链式选择器"*/
        custom-card::part(header)::part(small) {
            font-size: 1.2rem;
        }

        /*下面这段代码不会生效,因为 class="header"在阴影树的内部,
        要使用 ::part 来穿透阴影树才能在外部设置样式*/
        .header {
            background: red;
            padding: 12px;
        }

        /* 选中组件内部 part="content" 的元素(内容区域) */
        custom-card::part(content) {
            background: #ccc; /* 内容区背景色设置为浅灰色 */
            font-size: 16px; /* 文字大小设为16像素 */
            font-weight: bold; /* 文字加粗 */
        }

        /* 选中组件内部 part="footer" 的元素(页脚区域) */
        custom-card::part(footer) {
            background: #074c8f; /* 页脚背景色设置为深蓝色 */
            color: white; /* 文字颜色设置为白色 */
        }
        
    </style>



   <h2>part 属性:提供出口,让外部 CSS 穿透 shadow DOM 边界→ 可以使用外部样式设置样式</h2>

    <h3>⑴ 自定义元素内"无任何内容"(无空白换行):完全使用 shadow 中的默认内容</h3>
    <!-- 自定义组件内无内容:无空白和换行,会完全显示 shadow 中的内容 -->
    <custom-card></custom-card>
    <h3>⑵ 自定义元素内有注释(含空白、换行):使用 shadow 中的默认内容,但无 name 的 slot 标签内容不显示</h3>
    <custom-card>
        <!-- 这里应该完全空白,包括空格和换行都没有,此处不是完全空白,无 name 的slot 标签内容不显示 -->
        <!-- 如果不具名插槽不显示 slot 标签的默认标签内容:可能自定义元素 custom-card 是含有空格、换行,浏览器认为外部有内容(可能是空白文本节点),所以不显示插槽内部的默认内容。 -->

    </custom-card>

    <h3>⑶ 自定义元素中有"自定义内容":使用 slot 属性 → 替换指定的 name 的 slot 标签内容,无 slot 属性的标签 → 替换 "无
        name 属性的 slot 标签内容"</h3>
    <!-- 在页面中使用自定义组件 <custom-card> -->
    <custom-card>
        <!-- slot 属性:插入到哪里。这个 span 会被插入到组件内部 <slot name="header"> 的位置 -->
        <span slot="header">自定义标题:我的卡片,内容可随意替换</span>
        <!-- 这个 <p> 标签没有指定 slot,会进入默认的 <slot>(不带 name 的那个) -->
        <figure>
            <h4>自定义的内容区(不具名插槽的内容)</h4>
            <figcaption>波妞</figcaption>
            <img src="images/ponyo.png" alt="动漫《悬崖上的金鱼姬》里的波妞">
        </figure>
        <!-- 这个 div 会被插入到组件内部 <slot name="footer"> 的位置 -->
        <div slot="footer">
            <p>自定义页脚:我是页脚内容,可随意替换</p>
        </div>
    </custom-card>


    <script>
        // 定义一个类,继承自 HTMLElement,表示我们要创建一个自定义元素
        class CustomCard extends HTMLElement {
            // constructor 是类的构造方法,在每次创建 <custom-card> 实例时自动调用
            constructor() {
                super();    // 必须调用 super() 先执行父类的构造方法,才能使用 this

                // attachShadow 创建一个 Shadow DOM 树,mode: 'open' 表示外部可以通过 JS 访问这个 Shadow DOM
                this.attachShadow({mode: 'open'});
                this.shadowRoot.innerHTML = `
                <!-- 注意:这个 style 只作用于 Shadow DOM 内部,不会影响外部页面 -->
                <style>
                    .card {
                        border: 1px solid #ccc;    /* 灰色边框,1像素宽,实线 */
                        border-radius: 8px;         /* 圆角8像素 */
                        width: 80%;
                        margin: 0 auto; /* 居中 */
                    }
                    .header {
                        background: #f0f0f0;        /* 默认头部背景色为浅灰色 */
                        padding: 12px;              /* 内边距12像素 */
                    }
                    .content {
                        padding: 16px;              /* 内容区内边距16像素 */
                    }
                    .footer {
                        padding: 12px;              /* 页脚内边距12像素 */
                        border-top: 1px solid #ccc; /* 顶部边框,灰色,1像素 */
                    }
                </style>
                <!-- 卡片最外层容器 -->
                <div class="card">
                    <!-- 头部区域:part="header" 暴露给外部样式使用,class="header" 用于内部样式 -->
                    <div part="header" class="header">
                        <!-- slot 插槽:name="header" 允许外部用 slot="header" 的内容替换这里 -->
                        <slot name="header">shadow 中插槽的默认标题(具名插槽)</slot>
                    </div>

                    <!-- 内容区域:同样暴露 part="content" -->
                    <div part="content" class="content">
                        <!-- 默认插槽:没有 name 属性,外部未指定 slot 的内容会放到这里 -->
                        <slot>shadow 中插槽的默认内容区(无名插槽)</slot>
                    </div>

                    <!-- 页脚区域:暴露 part="footer" -->
                    <div part="footer" class="footer">
                        <!-- 具名插槽:name="footer",外部可用 slot="footer" 的内容替换 -->
                        <slot name="footer">shadow 中插槽默认的页脚内容(具名插槽)</slot>
                    </div>
                </div>
    `;
            }
        }

        //自定义元素的定义: 将 CustomCard 类注册为自定义元素,标签名:为 'custom-card'
        // 注意:自定义标签名必须包含短横线(-)
        customElements.define('custom-card', CustomCard);
    </script>

无外部样式,使用 shadow 中定义的默认样式。

外部有"自定义样式"

通过浏览器开发者工具查看"shadow DOM 的内容结构、插槽的实际内容"

  • 找到自定义元素,点击旁边的 #shadow-root 展开。

例 2:B站的评论区,用的自定义组件。


25. popover 属性:我是隐藏的弹窗元素⇒ 将任意元素设置为"弹窗元素"→ 默认隐藏、按钮 或 js 控制"显示/隐藏" (枚举属性;属性值:popover = auto/ manual/ hint;轻关闭/手动关闭;配套属性:控制哪个弹窗元素 → popovertarget="popover 元素的 id";怎么控制 → popovertargetaction= toggle/ show/ hide;)

popover 属性 :是 HTML5 新增的全局属性,用于将任意元素声明为 "弹窗元素"默认隐藏(display:none ,可通过按钮或 JS 控制显示 / 隐藏,自带顶层渲染、点击外部关闭、Esc 关闭等原生行为。

  • 关键词:弹窗元素、默认隐藏、元素都可用、顶层渲染、轻关闭、手动关闭、auto/ hint自互斥
  • 核心作用
    • 全局可用 :可用于 <div><section><p> 等任何元素。
    • 默认隐藏 :初始 display: none,不占布局空间。
    • 顶层渲染 :显示时自动进入 top-layer(最高层级),覆盖页面所有内容,且不会受到父元素 positionoverflow 样式的 影响。
    • 常用的两种模式auto(默认;支持"轻关闭")/ manual (手动关闭)
  • 显示"弹窗元素"
    • 通过 带有 popovertarget 属性的按钮 <button><input type="button"> )或 HTMLElement.showPopover() 调用来打开弹窗元素。

popover 属性值

属性值 作用
auto默认值 无值(仅属性名)= 空值 = auto值,三值相同(无空a:轻关闭)popover(无值) = popover="" (空值)= popover="auto"支持"轻关闭"(light dismissed) :可以点击弹窗外部 、按 ESC 键关闭弹窗。 支持"手动关闭弹窗" :通过按钮、js 关闭弹窗。 打开" auto 弹窗"时 :会关闭其他 auto 弹窗。内部嵌套auto除外:打开嵌套在 auto 弹窗内的 auto 弹窗时除外,外部的 auto 弹窗不会关闭。 即:除了内部嵌套的 auto 弹窗,一次只能在屏幕上显示一个 auto 弹窗------当已经显示一个弹出层时,再显示第二个将会隐藏第一个。 js 切换显示、隐藏弹窗 :可以使用 HTMLElement.togglePopover() 方法在显示和隐藏之间切换弹窗。
manual 只能"手动关闭"弹窗 :点击按钮关闭、js 关闭。 不支持"轻关闭" :无法通过点击弹窗外部 、按 ESC 键关闭弹窗。 打开 "manual 弹窗"时 :不关闭其他 manual 弹窗,多个 manual 可同时显示,互不干扰。
hint 注:safari 不支持 属性值 hint 支持"轻关闭" :可以点击弹窗外部 、按 ESC 键关闭弹窗。 支持"手动关闭弹窗" :通过按钮、js 关闭弹窗。 打开 "hint 弹窗"时 :关闭其他 hint 弹窗,不关闭其他 auto 弹窗。 注:由于点击行为相当于"轻关闭",所以实测中,在弹窗外部 点击按钮时,会关闭另一个,这是由于"点击"的"轻关闭",在弹窗内部 点击则不会关闭。 测试时,如果按钮在外部,用tab 键 触发,就不会关闭另一个。auto 和 hint 弹窗可以同时存在。

按钮控制"弹窗元素"的配套属性

  • popover谁是"弹窗元素"、哪种弹窗元素?写在哪个元素上,哪个元素就是"弹窗元素"。
  • popovertarget="弹窗元素的id":打开、关闭 哪个"弹窗元素"? 控制的弹窗元素 ID = popover 元素的 id。
  • popovertargetaction(可选):对"弹窗元素"执行什么操作?
    • toggle(默认):切换显示 / 隐藏 。→ 对应 togglePopover();
    • show:仅显示。→ 对应 showPopover();
    • hide:仅关闭。→ 对应 hidePopover();

autohint 的区别

  • auto(默认):主弹窗、独占型、会互斥
    → 用来做主界面弹窗 (菜单、面板、对话框),同一时间只允许一个 auto 存在 ,打开新的会关掉旧的 auto
  • hint辅助提示、叠加型、不打扰主弹窗
    → 用来做悬浮提示/ 气泡/ tooltip/ 预览不会关闭 auto ,但会关闭其他 hint

详细对比

特性 popover="auto"(默认) popover="hint"(实验性,2026-04 safari 不支持)
定位 主弹窗(菜单、面板、模态类) 辅助提示(气泡、悬停提示、预览)
互斥规则 打开新 auto关闭所有其他 auto 打开新 hint不关闭任何 auto ,但关闭其他 hint
轻关闭 支持(点外部、ESC) 支持(点外部、ESC)
设计意图 打断用户流、聚焦操作 不打断用户流、补充信息
典型触发 点击按钮打开 鼠标悬停、聚焦、滑动预览

总结

  • autohint 都支持"轻关闭"、跟自己互斥,跟别人不互斥不同时存在两个 auto 或 两个hint,可以同时存在autohint
  • manual 不支持轻关闭,跟谁都不互斥 ,可以同时出现两个 manual、也可以同时存在autohintmanual

popover 简记口诀

popover 变弹窗,默认隐藏按钮 js 显,

默认auto 轻关闭,点外 Esc 退出去,

manual 手动才关闭,控制按钮不少滴,

target 绑 ID 配对,toggle/show/hide 三位,

顶层渲染不被压,backdrop 遮罩可搭配 ,

JS 三方法常备,toggle/show/hide一一对,

auto/hint 自互斥,manual 跟谁都搭配。


: 把元素变为"弹窗元素",并测试不同属性值的效果。

html 复制代码
		<style>
        [popover]::backdrop{
            background-color: rgba(0,0,0,0.4); /* 顶层元素下面,设置半透明背景,提示被遮罩 */
        }
		</style>


    <h2>popover 属性:让任意元素变成一个"弹出层元素"、默认隐藏不显示。</h2>
    <!-- 触发按钮: 用 popovertarget 属性管理 popover 元素的 id -->
    <button popovertarget="my-popover1">打开弹窗1(auto)</button>
    <button popovertarget="my-popover2">打开弹窗2(auto)</button>
    <button popovertarget="my-popover3">打开弹窗3(manual)</button>
    <button popovertarget="my-popover4">打开弹窗4(manual)</button>
    <button popovertarget="my-popover5">打开弹窗5(hint)</button>
    <button popovertarget="my-popover6">打开弹窗6(hint)</button>
    <br/>
    <br/>
    <button popovertarget="my-popover7">打开弹窗7(auto 内部嵌套 auto 弹窗)</button>

    <br>
    <br>
    <!-- 默认值 toggle:在显示和隐藏之间切换,点击按钮,打开弹窗,再次点击按钮会关闭弹窗。 -->
    <button popovertarget="my-popover1" popovertargetaction="toggle">打开和关闭弹窗1(toggle/默认值)</button>
    <!-- 值打开弹窗,再次点击不会关闭弹窗 -->
    <button popovertarget="my-popover1" popovertargetaction="show">只打开弹窗1(show)</button>
    <!-- 只关闭,再次点击按钮不会显示弹窗 -->
    <button popovertarget="my-popover1" popovertargetaction="hide">只关闭弹窗1(hide)</button>
    <!-- 用js 代码控制"手动关闭的 manual 弹窗元素"。别在 auto 上设置,因为 auto 弹窗点击外部时会自动关闭,点击按钮时,就成了"关了又开",就是没关的状态 -->
    <button onclick="document.getElementById('my-popover3').togglePopover();">js 切换显示、隐藏(manual)</button>

    <br>
    <br>    
    <!-- auto 和 hint 弹窗的搭配使用 -->
    <button popovertarget="menu">打开菜单(auto 弹窗内部有 hint 弹窗,提供提示信息)</button>

    <!-- 把元素设置为弹出层:添加 popover 属性 、id-->
    <!-- <div id="my-popover1" popover> -->

    <div id="my-popover1" popover>
        <p>弹窗1(仅属性名,默认值 auto)</p>
        <p>提示:这是元素添加 popover 属性后创建的原生弹窗。</p>
        <p>关闭弹窗(可"轻关闭"):点击弹窗外部、按 ESC 键关闭弹窗、再次点击按钮关闭。</p>
        <p>打开 auto 弹窗时:会关闭其他 auto 弹窗。</p>
    </div>
    <div id="my-popover2" popover="auto">
        <p>弹窗2(auto)</p>
        <p>提示:这是元素添加 popover="auto" 属性后创建的原生弹窗。</p>
        <p>关闭弹窗(可"轻关闭"):再次点击按钮、点击弹窗外部、按 ESC 键关闭弹窗。打开 auto 弹窗时:会关闭其他 auto 弹窗</p>
    </div>
    <!-- 把元素设置为弹出层:添加 popover 属性 、id-->
    <div id="my-popover3" popover="manual">
        <p>弹窗3(manual)</p>
        <p>提示:这是元素添加 popover="manual" 属性后创建的原生弹窗。</p>
        <p>关闭弹窗:手动关闭弹窗,再次点击按钮关闭 /js 关闭。</p>
        <p>无"轻关闭":无法通过点击弹窗外部、按 ESC 键关闭弹窗。</p>
        <p>打开 manual 弹窗时:不关闭其他 manual 弹窗,多个 manual 可同时显示,互不干扰。</p>
    </div>

    <!-- 把元素设置为弹出层:添加 popover 属性 、id-->
    <div id="my-popover4" popover="manual">
        <p>弹窗4(manual)</p>
        <p>提示:这是元素添加 popover="manual" 属性后创建的原生弹窗。</p>
        <p>关闭弹窗:手动关闭弹窗,再次点击按钮关闭 /js 关闭。无"轻关闭":无法通过点击弹窗外部、按 ESC 键关闭弹窗。</p>
    </div>

    <!-- 把元素设置为弹出层:添加 popover 属性 、id-->
    <div id="my-popover5" popover="hint">
        <p>弹窗5(hint)</p>
        <p>提示:这是元素添加 popover="hint" 属性后创建的原生弹窗。</p>
        <p>关闭弹窗(可"轻关闭"):点击弹窗外部、按 ESC 键关闭弹窗、再次点击按钮关闭。</p>
        <p>打开 hint 弹窗时:关闭其他 hint 弹窗,不关闭其他 auto 弹窗。</p>
    </div>
    <!-- 把元素设置为弹出层:添加 popover 属性 、id-->
    <div id="my-popover6" popover="hint">
        <p>弹窗6(hint)</p>
        <p>提示:这是元素添加 popover="hint" 属性后创建的原生弹窗。关闭弹窗:再次点击按钮、点击弹窗外部、按 ESC
            键关闭弹窗。</p>
    </div>

    <div id="my-popover7" popover>
        <p>弹窗7(auto):内部还有嵌套的 auto 弹窗</p>
        <p>我是 popover 创建的弹窗元素,可以"轻关闭"。</p>
        <p>我的内部还有一个 auto 弹窗。</p>
        <p>点击下方按钮,打开内部嵌套的 auto 弹窗,我这个 auto 弹窗也不会关闭哦。</p>
        <button popovertarget="my-nested-popover1">打开"弹窗元素"内部的弹窗元素</button>
    </div>
    <!-- 在 auto 弹窗内部使用的 auto 弹窗 -->
    <div id="my-nested-popover1" popover>
        <p>我是弹窗元素内部的"嵌套弹窗",popover 创建的弹窗元素,可以"轻关闭"。</p>
        <p>打开我时,我外层 auto 弹窗不会关闭。</p>
    </div>
    
    <!-- auto 弹窗,内部有按钮,可以打开 hint 弹窗,同时不会关闭 auto 弹窗 -->
    <div id="menu" popover>
        <ul>
            <li>
                新建
                <button popovertarget="new-info">ⓘ</button>
            </li>
            <li>
                打开
                <button popovertarget="open-info">ⓘ</button>
            </li>
            <li>
                保存
                <button popovertarget="save-info">ⓘ</button>
            </li>
        </ul>
    </div>

    <!-- auto 弹窗内部的 hint 弹窗 -->

    <ul>
        <li popover="hint" id="new-info">新建一个文件</li>
        <li popover="hint" id="open-info">打开一个文件</li>
        <li popover="hint" id="save-info">保存文件</li>
    </ul>

演示效果

  • 点击"auto 弹窗"、"hint 弹窗" :可以"轻关闭",同一时间只能有一个 auto 弹窗、hint 弹窗。

    • auto 弹窗内部有嵌套的 auto 弹窗时,打开内部的弹窗,外部的弹窗不会自动关闭。
  • 点击"manual 弹窗" :无法"轻关闭",可以用多个 manual 弹窗同时存在。


26. slot 属性:把内容插入到"指定名称的插槽"中 → 内容插入到"指定 name 的 slot 标签"中⇒ slot 属性值 → 对应 slot 标签的 name 属性值 (属性值:slot="slot.name";插槽分配:无 slot 放无名,有 slot 找有名)

slot美/slɑːt/ 属性 : HTML 全局属性,主要用于 原生的 Web Components (小众但刚需),做内容分发 ,也就是把外部写的标签内容 "插到" 组件内部指定位置

  • 关键词:插入内容、外部标签内容、组件内部、指定名称插槽、占位孔、有名插槽、无名插槽仅一个

  • 给外部内容"分配位置"(普通标签 → <slot> 标签) :把当前这个普通元素的内容,放到组件内部指定名称的插槽(<slot>中 ⇒ 对应name 属性的 <slot> 标签

    • 在自定义元素内部(组件内) :用 <slot name="xxx"> 定义 "占位孔(插槽) ",挖坑
    • 外部使用时,给普通标签加 slot="xxx" 属性 :内容会自动 "插入" 对应孔位(插槽),填坑
  • 核心作用

    • 给"指定名称的插槽" 分配内容slot 属性值 → 对应 slot 标签的 name 属性值 。
    • 属性值slot="slot.name"
    • 让一个组件的外壳和结构固定,但内部的内容可以灵活变化。
    • :在一个组件中,不具名的 <slot>(即默认插槽)标签只能有一个 。如果写了多个,只有第一个会生效,其余的被忽略。
      • 默认插槽 = 不具名插槽 = 无名插槽 = 没有 name 属性的 <slot>标签:一个组件中 只能有一个"默认插槽"。

框架替代方案更强

  • Vuev-slot / #(更简洁、支持作用域)
  • Reactchildren / render props(更灵活)
  • :前端项目:90%+ 是 Vue/React/Angular,slot 属性几乎不用,Vue 3 明确 slot 属性废弃。
  • 必须学:做原生组件、跨框架库、Web Components。
  • 了解即可:Vue/React 开发者(知道历史用法)。

slot 属性简记口诀

组件挖坑 <slot>,外部填坑 slot 属。

slot 放无名,有 slot 找有名。

原生组件做分发,内容就位不用怕。


使用自定义组件,有自定义内容

  • 通过 slot 属性 给"具名插槽"分配内容,无 slot 属性给"默认插槽"分配内容。
html 复制代码
  <!-- 1.自定义组件 -->
    <template id="card-template">
        <!-- 定义自定义组件的样式 -->
        <!-- style 标签写在 template 内容:写在 主文档的 style 标签中不会生效,理由是"Shadow DOM 的封装" -->
        <!-- Shadow DOM 的样式隔离:Shadow DOM 创建了一个"封装的 DOM 树",主文档的 CSS 无法影响 "Shadow DOM"内部元素 -->
        <!-- 样式的作用域:写在 <template> 中,<style> 标签的样式会和 <template>一起被复制到"每个组件实例"的 Shadow DOM 中。 -->
        <!-- 插槽样式继承:插槽 slot 的内容,可以继承 Shadow DOM 中的样式 -->
        <style>
            * {
                margin: 0;
                padding: 0;
            }

            /* 卡片容器的样式 */
            .my-card {
                border: 1px solid #ccc; /* 卡片的边框 */
                border-radius: 8px; /* 边框的圆角 */
                padding: 16px; /* 上下左右内边距 */
            }

            /* 卡片头部区域的样式 */
            .header {
                background-color: #c7eace;
                padding: 8px;
                font-size: 18px;
                font-weight: bold;
            }

            /*  卡片内容区域的样式  */
            .content {
                padding: 16px;
                background-color: #ccc;
                margin-top: 10px;
            }

            /* 卡片页脚区域的样式   */
            .footer{
                padding: 16px;
                background-color: #c7eae7;
                margin-top: 10px;
                text-align: right;
                font-size: 14px;
                color: #666;
            }

            .header,.content,.footer{
                border: 1px solid #ccc;
                border-radius: 8px;
            }

        </style>
        <!-- 自定义组件的大容器 -->
        <div class="my-card">
            <!-- (div[class]>slot[name])*3 -->
            <!-- 具名插槽:头部区域,标题。 -->
            <div class="header">
                <slot name="title">头部区域:slot 标签默认的内容(具名插槽)</slot>
            </div>
            <!-- 默认插槽:内容区域 -->
            <div class="content">
                <slot>内容区:slot 标签的默认内容(第 1 个不具名插槽)</slot>
                <br>
                <slot>内容区:slot 标签的默认内容(第 2
                    个不具名插槽),一个组件,只能用一个"默认插槽(不具名)"多个不具名插槽,仅第一个生效。
                </slot>
            </div>
            <!-- 具名插槽:底部区域 -->
            <div class="footer">
                <slot name="footer">底部区域:slot 标签的默认内容(具名插槽)</slot>
            </div>
        </div>


    </template>

    <!-- 2.注册"自定义元素" -->
    <script>
        class MyCard extends HTMLElement {
            constructor() {
                super();
                const template = document.getElementById('card-template');
                const shadow = this.attachShadow({mode: 'open'});
                shadow.appendChild(template.content.cloneNode(true));
            }
        }

        // 自定义标签名:<my-card>
        customElements.define('my-card', MyCard);
    </script>

    <!-- 3.使用自定义组件,用 slot 属性给具名插槽"分配内容" -->
    <!-- 无自定义内容 -->
    <h3>直接使用"自定义组件",无自定义内容</h3>
    <my-card></my-card>

    <!-- 有自定义内容 -->
    <h3>使用自定义组件,有自定义内容:通过 slot 属性 给"具名插槽"分配内容,无 slot 属性给"默认插槽"分配内容</h3>
    <my-card>
        <!-- 分配到 name="title" 的插槽(slot 标签) -->
        <div slot="title">标题:这是自定义的卡片标题(可修改)</div>
        <!--  无 slot 属性的内容,分配给默认插槽(无 name slot)     -->
        <div>
            内容区域:我是自定义的内容,可修改,我没有 slot 属性,内容会分配给默认插槽(无 name 的 slot 标签)。
        </div>
        <p>p 标签的内容:一个没有 slot 属性的段落。</p>
        <!-- 分配给 name="footer" 的插槽(slot 标签) -->
        <div slot="footer">页脚区域(可写发布时间等)</div>
    </my-card>

演示效果

  • 使用自定义组件,有自定义内容 :通过 slot 属性 给"具名插槽"分配内容,无 slot 属性给"默认插槽"分配内容。

27. spellcheck 属性:对"可编辑元素"进行"拼写检查" ⇒ 用"红色波浪下划线" 标注"错误单词"(枚举属性;开启/ 关闭拼写检查:spellcheck="true/ false";非正常拼写词汇/代码、隐私信息:显式禁用拼写检查,避免误报、避免泄露隐私给第三方)

spellcheck 属性 : HTML 全局属性,枚举属性。用来控制浏览器是否对可编辑文本 开启拼写检查红色波浪线提示错误)。

  • 对"可编辑元素"的提示作用spellcheck 属性仅仅是"给浏览器的 提示 ",浏览器不必须检查拼写错误。通常情况下,即使 spellcheck 属性设置为 true 且浏览器支持拼写检查,非可编辑元素也不会进行检查拼写错误。
  • 关键词:可编辑元素、拼写检查、红色波浪线、错误提示、第三方检查、安全隐私、非正常拼写、显式禁用

spelcheck 的属性值

  • spellcheck="true" 或 空值"":开启拼写检查。
  • spellcheck="false":关闭拼写检查。
  • 不写时 :浏览器按默认规则处理
    • 普通文本框 :默认开启,密码 / 代码框:默认关闭,可以显式关闭,避免误报的红线干扰。

spellcheck 适用元素:

  • <input type="text">
  • <textarea>
  • 显式设置的"可编辑元素" :设置了 contenteditable="true" 的普通标签。

拼写检查和"安全隐私":显式禁用"拼写检查"

  • 开启拼写检查后,用户输入的密码、信用卡号、身份证号等敏感信息 可能会被发送到第三方拼写检查服务商 (而非绝对在本地处理),存在泄露风险
  • 所以,隐私信息 ,应该 显式禁用拼写检查 spellcheck="false"
  • 如下,增强型拼写检查,会被发送给 Google,存在泄露隐私信息风险。

spellcheck 全局属性的实际显式使用率很低(远低于 5%),但浏览器默认拼写检查功能的覆盖率非常高。

  • 默认行为(隐式启用)
    • <input type="text/search"><textarea>contenteditable 等可编辑元素:默认开启拼写检查spellcheck 未显式设置时)。
    • ❷ 密码、邮箱、URL、数字等输入框:可能出现非正常拼写单词 ,默认不检查
      • 谷歌浏览器实测,也有拼写检查提示,会提示错误,防止误报、防止隐私泄露,可显式禁用spellcheck="false"
  • 显式书写率(开发者主动添加)
    • spellcheck="false":常见于代码框、命令行输入、ID/序列号、专业术语区(避免误报)。
    • spellcheck="true":极少显式书写(因默认已开启)。

常见使用场景(显式设置)

  • 必须 spellcheck="false" :可能出现非正常拼写的文本输入(代码、术语、用户名等)
    • 代码编辑器、命令输入框
    • 用户名、ID、序列号、验证码
    • 专业术语、缩写、多语言混合文本
    • 隐私信息:密码、验证码等(防止被发送给第三方检查,泄露隐私)
  • 极少 spellcheck="true"
    • 需强制检查的特殊可编辑区域(通常默认已开启)

在谷歌浏览器中 开启"拼写检查"

第一步:设置 → 在正中间的搜索框搜索"拼写",查看是否已开启"拼写检查",如果出现以下提示,就是没有开启,进行第二步。


  • 第二步 :搜索"语言"→ 首选语言 → 添加语言 → 选择"英语(美国)" → 点击"添加"按钮。

第三步 :重新搜索"拼写" → 开启拼写检查的按钮。


例 1: 测试开启和关闭拼写检查的效果,测试未设置拼写检查时的默认行为。

html 复制代码
    <style>
        /* 加内边距 :输入文字不贴边,鼠标聚焦时可以显示闪烁的光标,不被遮挡*/
        .editable{
            padding: 8px;
        }

        /*空内容时,显示灰色的占位文本*/
        .editable:empty:before{
            content: '请输入您的想法...';
            color: #666;
        }
        /* 聚焦时,隐藏占位文本*/
        .editable:focus:before{
            content: none;
        }
    </style>

    <h2>spellcheck 属性:是否对"可编辑元素"开启"拼写检查",若拼写错误,一般会有"红色波浪下划线"</h2>
    <h3>富文本编辑器:未设置拼写检查,div 设置 contenteditable="true"</h3>
    <div id="my-editor1" class="editable"  contenteditable="true" style="width: 300px;height: 100px;background-color:#eee;"></div>
    <br>
    <h3>富文本编辑器:开启拼写检查(spellcheck="true")</h3>
    <div id="my-editor2" class="editable" spellcheck="true" contenteditable="true" style="width: 300px;height: 100px;background-color:#eee;"></div>
    <br>
    <h3>富文本编辑器:关闭拼写检查(spellcheck="false" )</h3>
    <div id="my-editor3" class="editable" spellcheck="false" contenteditable="true" style="width: 300px;height: 100px;background-color:#eee;"></div>
    <h3>不设置拼写检查时的默认行为:可编辑元素一般默认开启"拼写检查"</h3>
    <input type="text" aria-label="测试拼写检查" placeholder="text 未设置拼写检查">
    <input type="search" aria-label="测试拼写检查" placeholder="search 未设置拼写检查">
    <input type="password" aria-label="测试拼写检查" placeholder="password 未设置拼写检查">
    <br>
    <br>
    <input type="email" aria-label="测试拼写检查" placeholder="email 未设置拼写检查">
    <input type="url" aria-label="测试拼写检查" placeholder="url 未设置拼写检查">
    <br>
    <br>
    <textarea name="test-spell-check" id="test-spell-check" aria-label="测试拼写检查" placeholder="textarea 未设置拼写检查"></textarea>

演示效果

  • 谷歌中测试,除了密码框,其他的可编辑元素输入"拼写错误词汇"时,都会出现红线提示。

例 2关闭移动端的自动处理。

  • autocorrect="off":关闭自动更正,防止 iOS 自动篡改字符。
  • spellcheck="false":关闭拼写检查,防止桌面 / Chrome 标红。
  • autocapitalize="off":关闭自动大写,防止首字母自动大写。
html 复制代码
    <h3>关闭移动表单的自动处理:关闭自动大写、自动更正、拼写检查</h3>
    <!-- 彻底关闭自动处理 -->
    <input type="text" aria-label="测试关闭自动处理" placeholder="输入框无自动处理,关闭自动大写、自动更正、拼写检查" autocorrect="off" autocapitalize="off" spellcheck="false" style="width: 400px">

演示效果


28. style 属性:给单个元素设置样式 ⇒ 仅对当前元素生效的"内联样式"(属性值:style="CSS属性名: 值; CSS 属性名: 值;" ;冒号分名值,分号分属性)

style 属性 :包含要应用于本元素的 CSS 样式声明 ,即 只对当前元素生效的"内联样式"

  • 用于:直接为单个 HTML 元素指定 CSS 样式 。它的值是 CSS 声明块 ,可以包含一个或多个 CSS 属性和值的配对
  • 基本用法
    • <标签 style="CSS属性名: 值; CSS属性名: 值;">内容</标签>
    • CSS 样式声明和 CSS 文件中一致冒号分名值,分号分属性 。冒号:分隔属性名和值,分号;分隔两个属性。
  • 缺点:样式和内容混杂在一起,会维护困难,仅对单个元素生效,不能复用。
  • 推荐方案 :优先使用外部 CSS 文件或 <style> 标签,仅在必要时使用 style 属性。
  • 适合使用 style 属性的情况:JavaScript 动态修改样式、临时测试、高优先级覆盖样式、只单用、不复用。

style 属性使用注意事项

只作用当前元素,不影响其他标签

样式优先级最高,会覆盖 classid 样式

多个样式用分号;分隔,最后一条可省略

属性和值用冒号:连接,不能写空格错误

不能写选择器,只能写 CSS 属性名和值

尽量少用,结构样式混杂,不易维护复用

适合临时调试、动态样式,不适合整站样式

伪类/伪元素无效::hover::before 等无法在内联样式中使用;

无法响应式设计(@media) → 无法在 style 中实现

: 给单个元素设置样式。

html 复制代码
    <style>

        /* 测试 style 属性中样式的优先级,style 属性中设置的样式优先 style 标签中的样式,加了 !important 后,才能高于元素中的内联样式 */
        .test-priority{
            color: green;
           /* color: green !important; */
        }
    </style>

   <h2> style 属性:只对当前元素生效的"内联样式"</h2>
   <p class="test-priority" style="color: red;font-weight: bold">你好,通过元素的 style 属性设置,我的文字会变成红色,会变成粗体。</p>

演示效果


29. tabindex 属性:控制元素是否可以被 tab 键聚焦、聚焦顺序(属性值:整数值。0、-1、正整数;零可Tab,负JS焦,正数千万别乱标,跑完正数跑自然,特殊情况才需要)

tabindex 属性 :是 HTML 全局属性,用来控制元素"是否可以被键盘 Tab 键聚焦、以及聚焦顺序"

  • 关键词 :tab 聚焦、JS 聚焦、自然顺序、自定义顺序
    tabindex 属性的常见用法
  • tab 键聚焦、自然顺序tabindex="0"
    • 作用:让原本不能聚焦的元素可以被 Tab 选中,顺序按 DOM 自然顺序。
    • 表示该元素应在顺序键盘导航中可聚焦,在所有正的 tabindex 值之后。这些元素的焦点导航顺序由它们在文档源中的顺序定义。
    • 适用:divspan 等自定义控件。
  • tab 不聚焦、JS 可聚焦tabindex="-1"通过 JS 聚焦 :加 tabindex="-1",JS 中.focus()聚焦,tab 不聚焦)
    • 作用:元素不能被 Tab 选中,但可以用 JS 代码主动聚焦.focus() 可生效)。
    • 不加 tabindex="-1",普通 div 根本不支持 .focus(),JS 聚焦会失效。
    • 不聚弹窗要聚焦,必须负一标;Tab 不进来,JS 能抓到。
    • 适用:弹窗、提示框、需要程序控制焦点的区域。
  • tab 可聚焦、自定义顺序tabindex="正整数"(不推荐)
    • 作用:自定义 Tab 顺序,正数字越小越先聚焦。
    • 按 tab 键时,会先到 tabindex="1",再到 2... ,先走完正整数的元素,再走自然顺序的元素。
    • 元素会按照 1, 2, 3... 的正数值顺序被聚焦,这通常会破坏页面的自然阅读顺序。

总结

  • tabindex="0":让普通元素支持 Tab 聚焦。
  • tabindex="-1":只允许 JS 聚焦,不参与 Tab。
  • tabindex="≥1":强行指定顺序,特殊情况下使用,平时尽量别用。

tabindex 简记口诀

零可Tab,负JS焦,正数千万别乱标

原生自带不用加,自定义控件才需要

  1. 零可Tabtabindex="0" → 元素可被 Tab 键聚焦。
  2. 负JS焦tabindex="-1" → 仅 JS 可聚焦(focus()),不进 Tab 流。
  3. 正数千万别乱标tabindex≥1 破坏顺序,影响无障碍,禁止使用。
  4. 原生自带不用加:按钮、链接、输入框等默认可聚焦,无需额外设置。
  5. 自定义控件才需要div/span 做按钮、弹窗时才用 tabindex

默认可聚焦的元素(默认 tabindex="0" :(一般是需要互动的元素、点击、填写等)

  • 带有 href 属性的 <a><area>
  • <button><frame>(已废弃)、<iframe><input><object><select><textarea><summary>
  • tabindex 属性不能用于 <dialog> 元素,它不按普通元素规则参与 Tab 聚焦。

例 1 : 测试 tabindex 不同属性值时的效果。

html 复制代码
    <style>
        /* 当弹窗内任何元素获得焦点时,元素的样式,这段代码不注释的话,放:focus 后面时,会显示绿色,因为弹窗聚焦,也满足弹窗内获得焦点,两个权重一样,后面的会生效 */
        /* 弹窗自己聚焦 = 同时触发 :focus 和 :focus-within ,所以,:focus-within 放前面,避免覆盖 弹窗自己聚焦时的样式 :focus*/
        #my-panel:focus-within {
            border: 2px solid green;
        }

        /* 弹窗自己获得焦点时的样式*/
        #my-panel:focus {
            border: 2px solid red;
        }        
    </style>

    <h2>tabindex 属性:控制元素是否可以被 tab 键聚焦、聚焦顺序</h2>
    <h3>让原本不能被 tab 键聚焦的元素可以被 tab 键选中,顺序按"DOM 自然顺序":tabindex="0"</h3>
    <input type="text" aria-label="测试是否默认可被聚焦" placeholder="input 默认可聚焦">
    <div>我是 div,默认不可聚焦,tab 键聚焦时会跳过我</div>
    <div tabindex="0">我是 div,设置了 tabindex="0",现在可以用 tab 键聚焦了,tab 键会聚焦我,不会再跳过我</div>
    <h3>元素不能被 tab 选中,但 JS 代码可以主动聚焦</h3>
    <button popovertarget="my-panel" id="panel-btn">tab 键选中或点击我,显示弹窗</button>

    <!-- 通过 JS 聚焦:不加 tabindex="-1",普通 div 根本不支持聚焦,通过 JS 设置 .focus()也没用,JS 聚焦也会失效。 -->
    <div id="my-panel" popover tabindex="-1">
    <!-- <div id="my-panel" popover> -->
        <input id="my-panel-input"  type="text" aria-label="测试tab聚焦"
               placeholder="打开弹窗后,可通过 tab 聚焦">
        <p>我是弹窗内的内容,我上方的输入框可通过 tab 键获得焦点,获得焦点后,弹窗边框变绿色。</p>
        <p>如果让弹窗本身获得焦点,可点击按钮,弹窗获得焦点,弹窗边框会变红色。</p>
    </div>

    <script>
        const myPanel = document.getElementById('my-panel');
        const myPanelInput = document.getElementById('my-panel-input');
        // 监听弹窗的 toggle 事件,打开后弹窗时,让输入框聚焦
        myPanel.addEventListener('toggle', (event) => {
            if (event.newState === 'open') {
                // myPanelInput.focus();
                myPanel.focus();
            }

        });
    </script>

    <h3>自定义 tab 键聚焦顺序,数字越小越先聚焦:tabindex="正整数(1,2,3...)"</h3>
    <small>注:按 Tab 会先到 tabindex="1",再到 2... ,先走完正整数的元素,再走自然顺序的元素。</small>
    <div>
        <a href="#">登录页面的改进建议</a>
        <br>
        <input type="text" aria-label="账户名" placeholder="账号名、手机号、邮箱" name="login-name" tabindex="1">
        <br>
        <input type="password" name="login-pwd" id="login-pwd" tabindex="2">
        <br>
        <button tabindex="3">登录</button>
        <br>
        <a href="#">友情链接1</a>
        <a href="#">友情链接2</a>
        <a href="#">友情链接3</a>
    </div>

演示效果

  • tab 顺序:跑完整数,跑自然顺序。

弹窗效果

  • 通过 JS 聚焦 :加 tabindex="-1",JS 中.focus()聚焦。
    • <div>本身不支持聚焦,不设置 tabindex="-1",通过 JS 设置 .focus()也没用,JS 聚焦也会失效。

: 京东登录中的 tab 键顺序。

  • 用户名、密码、登录 三个元素优先,用户进入页面,最常见的做法就是登录。

30. title 属性:悬停提示、添加一段"附加说明、提示文字",鼠标悬停时显示(属性值:title="提示文本、说明信息、备用样式表名称、iframe 辅助标签";可多行:换行、空格被保留;基础用法:悬停提示非关键,移动端上看不见)

title 属性 :为页面中的元素提供一段附加的"说明信息、提示文字" 。当用户将鼠标悬停在该元素上 停留片刻后,浏览器会将这些信息显示为一个小小的提示框(Tooltip)。

  • 关键词:说明信息、提示文字、悬停提示、提示框、移动端看不见、非关键信息

存在问题title 提供的信息需要鼠标悬浮时才会显示 ,所以无法使用鼠标的人,就无法得到相关提示,如 移动端的触摸屏、视障人士的屏幕阅读器、键盘导航的人。因此,重要的关键信息应该直接"用文本标出来" ,而不是作为额外的提示信息

  • 简记:悬停提示非关键,移动端上看不见
    • 基础用法:只在桌面端鼠标悬停时,作为非必要的附加说明;在移动端则完全无效,不可依赖。

title 属性的各种用法。

html 复制代码
  <h2>title 属性:给元素添加一段"附加说明、提示文字",鼠标悬停时显示</h2>
    <h3>⑴ 给链接、图标添加说明:title="说明文字"</h3>
    <a href="#" title="点击进入设置页面">设置</a>
    <br>
    <a href="#" title="2026年度报告,pdf文件,文件大小约20M">查看报告</a>
    <br>
    <a href="#" title="点击进入设置页面">⚙️ </a>
    <br>
    <button title="打印当前页面">🖨️</button>


    <h3>⑵ 给缩写词标注全称:title="全称"</h3>
    <p>前端开发的基础三大件:
        <abbr title="超文本标记语言(Hypertext Markup Language)">HTML</abbr>、
        <abbr title=" 层叠样式表(cascading style sheet)">CSS</abbr>、
        <abbr title="JavaScript">JS</abbr>。
    </p>
    <small>注:首次使用时,全称是关键信息,应该用纯文本直接标出,而不是使用 title 属性。</small>

    <h3>⑶ 表单输入提示:title="输入提示"</h3>
    <input type="password" title="请输入字母、数字的组合,至少含一个字母" placeholder="请输入密码">
    <small>注:不能用 title 替代 &lt;label&gt; 标签。</small>

    <h3>⑷ 图片的补充说明:title="说明文字"(alt 是图片缺失时提示,title 是悬停提示)</h3>
    <img src="images/ponyo.png" alt="动漫《悬崖上的金鱼姬》里的主角波妞" title="动漫《悬崖上的金鱼姬》里的主角-波妞">

    <h3>⑸ 给内联框架 iframe 提供辅助标签</h3>
    <iframe src="https://www.baidu.com" title="百度搜索的首页"></iframe>

    <h3>⑹ 创建备用样式表,备用样式表的名称:title="备用样式表的名称"(必需),搭配 link 标签的 rel="alternate stylesheet"</h3>
    <small>注:目前仅 Firefox 浏览器支持备用样式表,添加 CSS 文件后,菜单栏 → 查看→ 页面样式中可选择备用样式</small>
    <pre>
        <code>
         &lt;link rel="stylesheet" href="#"&gt;
         &lt;link rel="alternate stylesheet" href="#" title="暗模式"&gt;
         &lt;link rel="alternate stylesheet" href="#" title="大字体模式"&gt;
        </code>
    </pre>

    <h3>⑺ title 属性可以包含多行:换行、空格会被保留。</h3>
    <p title="我是第一行,
    我是第二行,
        我是第三行。">
        测试 title 属性的换行</p>

演示效果


31. translate 属性:是否允许翻译⇒ 不想翻译设置 no (枚举属性:translate="yes/ no";默认可翻,不翻no;代码、品牌常用no,子承父业一起no)

translate 属性 :是 HTML 全局属性,枚举属性,用来告诉浏览器、翻译插件、搜索引擎:这段内容要不要被翻译

属性值(两个有效值):

  • 允许翻译(默认,可省略)translate="yes"、空字符串 。
  • 禁止翻译,保持原文translate="no"

: 设置translate 属性后的翻译效果。

  • 翻译插件:谷歌的"沉浸式翻译"。
html 复制代码
    <h2>translate 属性:是否翻译该元素的内容</h2>
    <h3>⑴ 保护品牌名、产品名不被翻译:translate="no"</h3>
    <p>Recommended AI tool for developers is <span translate="no">Windsurf</span>。</p>
    <small>(设置了不翻译)</small>
    <p>Recommended AI tool for developers is Windsurf。</p>
    <small>(未设置)</small>
    <p><span translate="no">Tiktok</span> is his favorite app.</p>
    <small>(设置了不翻译)</small>
    <p>Tiktok is his favorite app.</p>
    <small>(未设置)</small>

    <h3>⑵ 代码、命令行、标识符等需要保持原文、不应该被翻译:translate="no"</h3>
    <p>Type "<code translate="no">node -v</code>" in the terminal to view the version of Node.js.</p>
    <small>(设置了不翻译)</small>
    <p>Type "<code>node -v</code>" in the terminal to view the version of Node.js.</p>
    <small>(未设置)</small>


    <h3>⑶ 父元素设置了不翻译,子元素也不翻译</h3>
    <div translate="no">
        <p>Tiktok is his favorite app.</p>
    </div>

演示效果


virtualkeyboardpolicy 属性 :是一个实验性 的 HTML 全局属性,用于精确控制触摸屏设备 (如手机、平板)上虚拟键盘的显示行为。

  • 控制可编辑元素<input><textarea>contenteditable 元素)在触屏设备上聚焦时,虚拟键盘的自动弹出行为。

  • 可以控制用户点击输入框时,键盘是自动弹起 (默认行为),还是完全通过代码控制

  • 属性值

属性值 行为描述
auto (默认值) 自动模式,自动弹出虚拟键盘 。 当用户点击或聚焦到可编辑元素(如 <input><textarea>contenteditable 元素)时,浏览器会自动弹出虚拟键盘
manual 手动模式,代码管 。 浏览器不会 自动弹出键盘。需要使用 JavaScript 来精确控制键盘的显示与隐藏。 适用:自定义输入体验时非常有用。 禁止自动弹出。键盘仅在调用 navigator.virtualKeyboard.show() 时显示,仅在调用 hide() 时隐藏。

适用元素virtualkeyboardpolicy 属性只对可编辑 元素生效,如 <input><textarea> 或设置了 contenteditable 属性的元素。因为不可编辑元素,也不需要虚拟键盘来进行交互。

: 禁用虚拟键盘的自动弹出。

html 复制代码
   <h2>virtualkeyboardpolicy 属性:控制虚拟键盘的弹出行为,默认自动弹出,可禁用</h2>
    <h3>禁用键盘自动弹出、通过自定义按钮唤起虚拟键盘:virtualkeyboardpolicy="manual"</h3>
    <small>注:移动端,点击内容不会弹出虚拟键盘,点击按钮才会弹出虚拟键盘。Safari、Firefox 不支持。</small>
    <div contenteditable="true" virtualkeyboardpolicy="auto"
         style="border: 2px solid green;padding: 8px;margin-top:8px">virtualkeyboardpolicy="auto"
    </div>
    <div contenteditable="true"
         style="border: 2px solid green;padding: 8px;margin-top:8px">未设置 virtualkeyboardpolicy
    </div>
    <div id="editor1" contenteditable="true" virtualkeyboardpolicy="manual"
         style="border: 2px solid green;padding: 8px;margin-top:8px">
        <p>内容区1</p>
        <p>contenteditable="true"(可编辑),virtualkeyboardpolicy="manual"(不弹出)</p>
        <p>我是原本就有的内容,点击下方按钮进行编辑。</p>
    </div>

    <div id="editor2" contenteditable="false" virtualkeyboardpolicy="manual"
         style="border: 2px solid green;padding: 8px;margin-top:8px">
        <p>内容区2</p>
        <p>contenteditable="false"(不可编辑),virtualkeyboardpolicy="manual"(不弹出)</p>
        <p>我是原本就有的内容,点击下方按钮进行编辑。</p>
    </div>
    <button id="edit-btn1">编辑内容1</button>
    <button id="edit-btn2">编辑内容2</button>

    <script>

        // if ('virtualKeyboard' in navigator) {
            const editor1 = document.getElementById('editor1');
            const editor2 = document.getElementById('editor2');
            const editBtn1 = document.getElementById('edit-btn1');
            const editBtn2 = document.getElementById('edit-btn2');

            // 阻止默认行为:阻止点击编辑器(div)时自动弹出虚拟键盘
            editor1.addEventListener('click', (e) => {
                e.preventDefault();
            });
            editor2.addEventListener('click', (e) => {
                e.preventDefault();
            });


            editBtn1.addEventListener('click', () => {
                // 编辑器获取焦点
                editor1.focus();
                // 通过 JS 手动唤起虚拟键盘:显示虚拟键盘
                navigator.virtualKeyboard.show();
            });
            editBtn2.addEventListener('click', () => {
                // 编辑器获取焦点
                editor2.focus();
                // 让 div 可编辑
                editor2.contentEditable="true";
                // 通过 JS 手动唤起虚拟键盘:显示虚拟键盘
                navigator.virtualKeyboard.show();
            });
        // }
    </script>

演示效果

  • 安卓手机谷歌浏览器中测试,manual 并未成功阻止虚拟键盘弹出。
  • 采用内容区2的方案:默认不可编辑(contenteditable="false"),点击按钮后→ 变"可编辑"的方案(contenteditable="true"),不可编辑状态下,点击内容区不会弹出"虚拟键盘"。

33. writingsuggestions 属性:是否启动浏览器提供的"写作建议" (枚举属性;writingsuggestions="true/ false";Firefox 不支持)

writingsuggestions: 全局属性,枚举属性。用于指示是否在元素的作用范围内 启用浏览器提供的写作建议,一般是显示在光标之后的灰色预测文本。

  • writingsuggestions 属性适用标签 :可以设置在 <input><textarea>contenteditable 元素 等可编辑元素上,或设置在其他 HTML 元素上,以控制浏览器建议在页面部分或整个页面的行为。
  • 属性值
    • true(或缺省属性、缺省属性值):启用建议(默认)。在支持它们的浏览器中,写作建议默认启用
      • 启用写作建议 :未设置、无属性值、值为 true。将属性的值设置为 true ,或省略值,将启用写作建议。
    • false:禁用建议。
      • 禁用写作建议 :要禁用它们,设置 writingsuggestions="false"
html 复制代码
    <!-- 禁用写作建议:false -->
    <input type="text" writingsuggestions="false" placeholder="false,显式禁用写作建议" />
    <!-- 启动写作建议:默认是启用的 -->
    <input type="text" placeholder="未设置写作建议,默认启动" />
    <input type="text" writingsuggestions placeholder="写作建议仅属性名,默认启用" />
    <input type="text" writingsuggestions="true" placeholder="写作建议值为 true,显式启用"/>


全局事件属性 (简介表格)

  • Window 事件属性
    • 针对 window 对象触发的事件(应用到 <body> 标签)
  • Form 事件
    • 表单内的 动作触发的事件
    • (应用到几乎所有 HTML 元素,但最常用在 form 元素中)
  • Keyboard 事件
  • Mouse 事件
  • Media 事件
    • 由媒介(比如视频、图像和音频)触发的事件(适用于所有 HTML 元素,但常见于媒介元素中,比如 <audio>、<embed>、<img>、<object> 以及 <video>

关于 HTML 全局事件属性,简单来说:不需要花大量时间"深度学习",但值得花几分钟彻底理解它为什么不需要学。

  • 它不是一个需要死记硬背的技术点,MDN 上也没有为其设立专门的教程。

为什么不需要"深度学习"?

⚠️主要原因有三点:现代开发的最佳实践已将其淘汰、MDN 将其视为"警告"而非重点、以及它本身缺乏技术深度

  • 现代开发已弃用,有更优替代方案

    • 将 JavaScript 代码直接写在 HTML 标签里(如 <button onclick="...">)是早期的做法。它会导致代码难以维护、全局变量污染以及无法绑定多个事件等问题。
    • 现代前端开发强烈推荐使用 addEventListener(),它更强大、更灵活,真正实现了结构与行为的分离。
    • 集中精力掌握核心 :把深度学习的时间投入到 addEventListener() 上。需要重点掌握:
      • 如何为同一事件添加多个监听器。
      • 如何精确移除事件监听器(使用具名函数)。
      • 理解事件对象 e 的常用属性和方法(如 target, preventDefault())。
      • 理解事件捕获与冒泡机制,并学会使用事件委托来优化性能。
  • MDN 将其列为"警告"而非重点

    • 在 MDN 的官方文档中,虽然列出了所有事件处理属性(如 onclickonload),但同时会附上清晰的警告 :"不推荐使用 HTML onevent 属性设置事件处理程序!它们会使标记膨胀,降低可读性且难以调试"。
    • 因此,MDN 并没有,也不需要为这种"过时"的用法单独开设教程。
  • 知识点零散,无技术深度

    • 这些属性只是将事件名称加上 "on" 前缀 (如 clickonclick),其用法就是把一段 JavaScript 代码作为字符串值。它本身没有任何复杂的逻辑或机制需要花时间去"钻研"。
  • 最高效的学习方式:了解即可,无需深究

    • 时间应该花在刀刃上。对于 HTML 全局事件属性,最好的学习方式就是"知道它们是什么即可"。

花几分钟了解:通读一遍下面表格中的常用属性,

属性 触发时机
onclick 元素被点击时
onload 页面或图片加载完成时
onchange 表单元素内容改变时
onmouseover 鼠标指针移动到元素上时
onkeydown 用户按下键盘按键时

以下是按功能分类的 HTML 全局事件属性完整列表。

  • 所有事件属性的名称都以"on"开头,其值应为要执行的 JavaScript 代码
  • on事件名="JS 代码"

⑴ 窗口事件 (Window Events)

这些事件作用于<body>标签,与浏览器窗口相关。

属性 触发时机
onafterprint 文档打印之后
onbeforeprint 文档打印之前
onbeforeunload 文档卸载之前
onblur 窗口失去焦点时
onerror 错误发生时
onfocus 窗口获得焦点时
onhashchange URL的锚部分变化时
onload 文档加载完成时
onmessage 触发消息时
onoffline 文档离线时
ononline 文档上线时
onpagehide 窗口隐藏时
onpageshow 窗口可见时
onpopstate 窗口历史记录改变时
onresize 调整窗口大小时
onstorage Web Storage 区域更新时
onunload 用户离开文档时

⑵ 表单事件 (Form Events)

这些事件与表单交互相关。

属性 触发时机
onblur 元素失去焦点时
onchange 元素值改变时
oncontextmenu 触发上下文菜单时
onfocus 元素获得焦点时
oninput 元素获得用户输入时
oninvalid 元素无效时
onreset 表单重置时
onsearch 用户在搜索字段输入时
onselect 选取元素文本时
onsubmit 提交表单时

⑶ 键盘事件 (Keyboard Events)

这些事件由键盘操作触发。

  • 执行顺序: onkeydown 事件 最先执行,其次是onkeypress,最后是onkeyup
属性 触发时机
onkeydown 按下按键时
onkeypress 按下并松开按键时
onkeyup 松开按键时

⑷ 鼠标事件 (Mouse Events)

这些事件由鼠标操作触发。

属性 触发时机
onclick 单击鼠标时
ondblclick 双击鼠标时
onmousedown 按下鼠标按钮时
onmousemove 鼠标指针移动时
onmouseout 鼠标指针移出元素时
onmouseover 鼠标指针移至元素上时
onmouseup 松开鼠标按钮时
onmousewheel 转动鼠标滚轮时
onwheel 鼠标滚轮滚动时
onscroll 滚动元素的滚动条时

⑸ 拖拽事件 (Drag Events)

这些事件与拖放操作相关。

属性 触发时机
ondrag 拖动元素时
ondragend 拖动操作结束时
ondragenter 元素被拖至有效拖放目标时
ondragleave 元素离开有效拖放目标时
ondragover 元素被拖至有效拖放目标上方时
ondragstart 拖动操作开始时
ondrop 被拖动元素被拖放时

⑹ 剪贴板事件 (Clipboard Events)

这些事件与复制、剪切、粘贴操作相关。

属性 触发时机
oncopy 复制元素内容时
oncut 剪切元素内容时
onpaste 粘贴内容到元素时

⑺ 多媒体事件 (Media Events)

这些事件适用于<audio><video>媒体元素

属性 触发时机
onabort 中止事件发生时
oncanplay 文件就绪可开始播放时
oncanplaythrough 可无需缓冲播放至结尾时
oncuechange <track>元素字幕改变时
ondurationchange 媒体时长改变时
onemptied 媒体资源突然为空时
onended 媒体播放至结尾时
onerror 元素加载期间发生错误时
onloadeddata 加载媒体数据时
onloadedmetadata 加载媒体元数据时
onloadstart 开始加载媒体数据时
onpause 媒体数据暂停时
onplay 媒体数据将要开始播放时
onplaying 媒体数据已开始播放时
onprogress 浏览器获取媒体数据时
onratechange 播放速率改变时
onseeked 定位结束时
onseeking 定位开始时
onstalled 获取媒体数据延迟时
onsuspend 停止获取媒体数据时
ontimeupdate 播放位置改变时
onvolumechange 音量改变或设置静音时
onwaiting 停止播放但预期恢复时

⑻ 其他事件 (Misc Events)

属性 触发时机
onshow <menu>元素作为上下文菜单显示时
ontoggle 用户打开或关闭可折叠元素,如 <details>元素时


♣ 结束语 和 友情链接


  • 友情链接
    • MDN Web Docs
      • 在搜索框输入关键词查询,可以看详细知识点。可以在文章的最下方看到浏览器支持,点击浏览器版本,还能看到具体支持情况。
    • Can I use... Support tables for HTML5, CSS3, etc
      • 在搜索框输入查询,可以查询特性的浏览器支持,点击浏览器版本,能看到具体支持情况。

  • 感谢:❤ 如果这篇文章对您有帮助的话,可以点赞、评论、关注,鼓励下作者哦,谢谢小可爱们 ~╮( ̄▽ ̄)╭ ~
  • 欢迎指正: 如果发现 有需要更正的细节问题,欢迎指正。
  • 喜欢请收藏:喜欢本文 可收藏哦,方便快捷,会持续进行 ❶ 知识点更新 及 ❷ 修正错误。

  • 转载 请评论告知作者 并注明出处 ,Thanks♪(・ω・)ノ
    • 作者:Hey_Coder
    • 来源:CSDN
    • 版权声明:本文为博主原创文章,转载请附上博文链接!