我们在 HTML 概览中简要讨论了属性,现在是深入了解属性的时候了。
属性是 HTML 如此强大的原因。属性是出现在开始标记中的以空格分隔的名称和名称/值对,用于提供有关元素的信息和功能。
属性用于定义元素的行为、关联和功能。有些属性是全局属性,这意味着它们可以出现在任何元素的开始标记中。其他属性适用于多个元素,但并非所有元素都适用;还有一些属性是特定于元素的,仅与单个元素相关。在 HTML 中,除了布尔属性和某种程度上的枚举属性之外,所有属性都需要一个值。
如果属性值包含空格或特殊字符,则必须用英文引号将该值引起来。出于这个原因,并为了提高可读性,我们始终建议使用引号。
虽然 HTML 不区分大小写,但某些属性值区分大小写。属于 HTML 规范的值不区分大小写。 已定义的字符串值(例如类名称和 ID 名称)区分大小写。如果某个属性值在 HTML 中区分大小写,那么在 CSS 和 JavaScript 中用作属性选择器的一部分时,该属性值也会区分大小写;否则,该属性值不区分大小写。
<!-- the type attribute is case insensitive: these are equivalent -->
<input type="text">
<input type="TeXt">
<!-- the id attribute is case sensitive: they are not equivalent -->
<div id="myId">
<div id="MyID">
布尔值属性
如果存在布尔值属性,则该属性始终为 true。布尔值属性包括 autofocus
、inert
、checked
、disabled
、required
、reversed
、allowfullscreen
、default,
、loop
、autoplay
、controls
、muted
、readonly
、multiple,
和 selected
。
如果存在这些属性中的一个(或多个),则相应元素处于停用、必需、只读等状态。如果不存在,则不处于相应状态。
布尔值可以省略、设置为空字符串或设置为属性的名称;但该值不必实际设置为字符串 true
。所有值(包括 true
、false
和 😀
)虽然无效,但都会解析为 true。
以下三个标记是等效的:
<input required>
<input required="">
<input required="required">
如果属性值为 false,则省略该属性。如果该属性为 true,请添加该属性,但不要提供值。
例如,required="required"
在 HTML 中不是有效值;但由于 required
是布尔值,因此无效值会解析为 true。
但由于无效的枚举属性不一定会解析为与缺失值相同的值,因此养成省略值的习惯比记住哪些属性是布尔值、哪些属性是枚举值并可能提供无效值要容易得多。
在 true 和 false 之间切换时,请使用 JavaScript 完全添加和移除属性,而不是切换值。
const myMedia = document.getElementById("mediaFile");
myMedia.removeAttribute("muted");
myMedia.setAttribute("muted");
请注意,在 XML 语言(例如 SVG)中,所有属性(包括布尔属性)都需要包含一个值。
枚举属性
枚举属性有时会与布尔值属性混淆。它们是 HTML 属性,具有一组有限的预定义有效值。
与布尔属性一样,如果存在该属性但缺少值,则它们具有默认值。例如,如果您包含 <style contenteditable>
,则默认值为 <style contenteditable="true">
。
不过,与布尔属性不同的是,省略该属性并不意味着其值为 false;存在但缺少值的属性不一定为 true;无效值的默认值不一定与 null 字符串相同。继续上面的示例,如果 contenteditable
缺失或无效,则默认为 inherit
,并且可以明确设置为 false
。
默认值取决于相应属性。与布尔值不同,属性在存在时不会自动设为“true”。如果您添加 <style contenteditable="false">
,则该元素无法修改。如果该值无效(例如 <style contenteditable="😀">
或令人惊讶的 <style contenteditable="contenteditable">
),则该值无效,并默认为 inherit
。
在大多数情况下,对于枚举属性,缺失值和无效值是相同的。例如,如果 <input>
上缺少 type
属性、存在该属性但没有值,或者该属性的值无效,则默认值为 text
。虽然这种行为很常见,但并非规则。
因此,务必了解哪些属性是布尔值,哪些是枚举值;尽可能省略值,以免出错,并根据需要查找值。
全局属性
全局属性是指可以针对任何 HTML 元素(包括 <head>
中的元素)设置的属性。全局属性超过 30 个。虽然从理论上讲,这些属性都可以添加到任何 HTML 元素中,但当某些全局属性设置在某些元素上时,不会产生任何效果;例如,将 hidden
设置为 <meta>
上的元内容时,不会显示。
id
全局属性 id
用于为元素定义唯一标识符。它具有多种用途,包括:
- 链接的 fragment 标识符的目标。
- 标识用于脚本的元素。
- 将表单元素与其标签相关联。
- 为辅助技术提供标签或说明。
- 在 CSS 中使用(高特异性或作为属性选择器)定位样式。
id
值是一个不含空格的字符串。如果其中包含空格,文档不会中断,但您必须在 HTML、CSS 和 JS 中使用转义字符来定位 id
。所有其他字符均有效。id
值可以是 😀
或 .class
,但最好不要这样设置。为了方便您现在和将来进行编程,请确保 id
的第一个字符是字母,并且仅使用 ASCII 字母、数字、_
和 -
。最好制定一个 id
命名惯例,然后坚持使用该惯例,因为 id
值区分大小写。
id
应在文档中保持唯一性。如果 id
被多次使用,网页的布局可能不会中断,但 JavaScript、链接和元素互动可能无法按预期运行。
链接 fragment 标识符
导航栏包含四个链接。我们稍后会介绍链接元素,但现在请注意,链接不限于基于 HTTP 的网址;它们可以是当前文档(或其他文档)中页面部分的 fragment 标识符。
在机器学习研讨会网站上,页面标题中的导航栏包含四个链接:
href 属性提供超链接,激活该链接后,用户会前往该超链接指向的网页。如果网址包含井号 (#
) 后跟一串字符,则该字符串是 fragment 标识符。如果该字符串与网页中某个元素的 id
相匹配,则该 fragment 是指向相应元素的锚点或书签。浏览器将滚动到锚点定义的位置。
这四个链接指向网页上由其 id
属性标识的四个部分。当用户点击导航栏中的任意一个链接时,与该链接关联的元素(即包含匹配 ID(不含 #
)的元素)会滚动到视图中。
机器学习研讨会的 <main>
内容包含四个带有 ID 的部分。当网站访问者点击 <nav>
中的某个链接时,包含相应 fragment 标识符的部分会滚动到视图中。标记类似于:
<section id="reg">
<h2>Machine Learning Workshop Tickets</h2>
</section>
<section id="about">
<h2>What you'll learn</h2>
</section>
<section id="teachers">
<h2>Your Instructors</h2>
<h3>Hal 9000 <span>&</span> EVE</h3>
</section>
<section id="feedback">
<h2>What it's like to learn good and do other stuff good too</h2>
</section>
比较 <nav>
链接中的 fragment 标识符,您会发现每个标识符都与 <main>
中 <section>
的 id
相匹配。浏览器会提供一个免费的“网页顶部”链接。设置 href="#top"
(不区分大小写)或仅设置 href="#"
会将用户滚动到页面顶部。
href
中的井号分隔符不属于片段标识符。片段标识符始终是网址的最后一部分,不会发送到服务器。
CSS 选择器
在 CSS 中,您可以使用 ID 选择器(例如 #feedback
)来定位每个部分,也可以使用区分大小写的属性选择器(例如 [id="feedback"]
)来降低特异性。
设计脚本
在 MLW.com 上,有一个仅供鼠标用户使用的彩蛋。点击电灯开关可切换网页的开启和关闭状态。
电灯开关图片的标记如下:
html
<img src="svg/switch2.svg" id="switch"
alt="light switch" class="light" />
id
属性可用作 getElementById()
方法的参数,也可与 #
前缀一起用作 querySelector()
和 querySelectorAll()
方法的参数的一部分。
const switchViaID = document.getElementById("switch");
const switchViaSelector = document.querySelector("#switch");
我们的一个 JavaScript 函数利用此功能按元素的 id
属性定位元素:
<script>
/* switch is a reserved word in js, so we us onoff instead */
const onoff = document.getElementById('switch');
onoff.addEventListener('click', function(){
document.body.classList.toggle('black');
});
</script>
<label>
HTML <label>
元素具有 for
属性,该属性的值是与其关联的表单控件的 id
。
通过在每个表单控件上添加 id
并将每个控件与标签的 for
属性配对来创建显式标签,可确保每个表单控件都有关联的标签。
虽然每个标签只能与一个表单控件相关联,但一个表单控件可以关联多个标签。
如果表单控件嵌套在 <label>
起始标记和结束标记之间,则不需要 for
和 id
属性:这称为“隐式”标签。标签可让所有用户了解每个表单控件的用途。
<label>
Send me a reminder <input type="number" name="min"> before the workshop resumes
</label>.
for
与 id
之间的关联可让辅助技术的用户获取相应信息。此外,点击标签上的任意位置都会将焦点移至关联的元素,从而扩大控件的点击区域。这不仅有助于精细动作障碍人士提高鼠标操作的准确性,还有助于手指比单选按钮宽的移动设备用户。
在此代码示例中,虚假测验的虚假第五个问题是单选多选题。每个表单控件都有一个明确的标签,每个标签都有一个唯一的 id
。为确保我们不会意外重复 ID,ID 值是问题编号和值的组合。
如果包含单选按钮,由于标签描述的是单选按钮的值,因此我们会将所有同名按钮都包含在 <fieldset>
中,其中 <legend>
是整个集的标签或问题。
其他无障碍用途
在无障碍功能和易用性方面,id
的使用不限于标签。在文本简介中,通过将 <h2>
的 id
作为 <section>
的 aria-labelledby
的值来提供无障碍名称,将 <section>
转换为区域地标:
<section id="about" aria-labelledby="about_heading">
<h2 id="about_heading">What you'll learn</h2>
有 50 多种 aria-*
状态和属性可用于确保无障碍性。aria-labelledby
、aria-describedby
、aria-details
和 aria-owns
将以空格分隔的 id
引用列表作为其值。aria-activedescendant
,用于标识当前获得焦点的后代元素,其值是单个 id
引用:即获得焦点的单个元素(一次只能有一个元素获得焦点)。
class
class
属性提供了一种使用 CSS(和 JavaScript)定位元素的额外方式,但在 HTML 中没有其他用途(不过框架和组件库可能会使用它们)。class 属性的值是元素的区分大小写的类列表,以空格分隔。
构建合理的语义结构可根据元素的位置和功能来定位元素。声音结构支持使用后代元素选择器、关系选择器和属性选择器。在本部分中,您将了解各种属性,并思考如何为具有相同属性或属性值的元素设置样式。并不是说您不应使用 class 属性,只是大多数开发者没有意识到他们通常不需要使用该属性。
到目前为止,MLW 尚未使用任何类。能否在没有单个课程名称的情况下发布网站?我们拭目以待。
style
借助 style
属性,您可以应用内嵌样式,即应用于设置了该属性的单个元素的样式。
style
属性的值为 CSS 属性值对,值的语法与 CSS 样式块的内容相同:属性后跟英文冒号(与 CSS 中一样),而英文分号用于结束每个声明(位于值之后)。
样式仅应用于设置了该属性的元素,后代会继承继承的属性值,除非嵌套元素或 <style>
块或样式表中的其他样式声明覆盖了这些值。由于该值相当于仅应用于相应元素的单个样式块的内容,因此不能用于生成的内容、创建关键帧动画或应用任何其他 at-rule。
虽然 style
确实是一个全局属性,但不建议使用它。而是应在单独的文件中定义样式。
不过,在开发过程中,style
属性可用于快速设置样式,例如用于测试目的。然后,将“solution”样式粘贴到关联的 CSS 文件中。
tabindex
您可以向任何元素添加 tabindex
属性,以使其能够接收焦点。tabindex
值用于定义是否将其添加到标签页顺序中,以及是否添加到非默认标签页顺序中(可选)。
tabindex
属性的值为整数。负值(惯例是使用 -1
)使元素能够接收焦点(例如通过 JavaScript),但不会将元素添加到 Tab 键顺序中。如果 tabindex
值为 0
,则表示该元素可通过 Tab 键聚焦和访问,并按源代码顺序将其添加到网页的默认 Tab 顺序中。如果值为 1
或更大,元素将进入优先聚焦序列,不建议这样做。
在此页面上,有一个使用 <share-action>
自定义元素(充当 <button>
)的分享功能。包含 tabindex
为零,以将自定义元素添加到键盘默认的 Tab 键顺序中:
<share-action authors="@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, twitter" role="button" tabindex="0">
<svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
<use href="#shareIcon" />
</svg>
<span>Share</span>
</share-action>
button
的 role
会告知屏幕阅读器用户此元素应像按钮一样运行。JavaScript 用于确保按钮功能承诺得以兑现;包括处理 click 和 keydown 事件,以及处理 Enter 和空格键按键。
表单控件、链接、按钮和可编辑内容元素能够接收焦点;当键盘用户按下 Tab 键时,焦点会移动到下一个可聚焦的元素,就像设置了 tabindex="0"
一样。其他元素默认情况下不可聚焦。向这些元素添加 tabindex
属性可让它们在通常情况下无法接收焦点时接收焦点。
如果文档包含 tabindex
为 1
或更高级别的元素,则这些元素会包含在单独的 Tab 序列中。如您在 CodePen 中所见,标签页的切换从一个单独的序列开始,按从最低值到最高值的顺序进行,然后再按源代码顺序切换常规序列中的标签页。
更改 Tab 键顺序可能会导致非常糟糕的用户体验。这使得用户难以依赖键盘和屏幕阅读器等辅助技术来浏览您的内容。对于开发者来说,管理和维护起来也很困难。焦点非常重要;我们专门用一个模块来讨论焦点和焦点顺序。
role
role
属性是 ARIA 规范的一部分,而不是 WHATWG HTML 规范的一部分。role
属性可用于为内容提供语义含义,使屏幕阅读器能够告知网站用户对象的预期用户互动。
有一些常见的界面 widget(例如组合框、菜单栏、标签页列表和树状网格)没有对应的原生 HTML 等效项。例如,在创建标签页式设计模式时,可以使用 tab
、tablist
和 tabpanel
角色。能够看到用户界面的人通过经验了解到如何浏览 widget,以及如何通过点击相关标签页来显示不同的面板。
当使用一组按钮显示不同的面板时,在 <button>
中包含 tab
角色和 <button role="tab">
可让屏幕阅读器用户知道,当前具有焦点的 <button>
可以切换相关面板以显示,而不是实现典型的按钮式功能。
role
属性不会改变浏览器行为,也不会改变键盘或指针设备互动。向 <span>
添加 role="button"
不会将其变成 <button>
。因此,建议您使用语义 HTML 元素来实现其预期用途。不过,如果无法使用正确的元素,role
属性可用于告知屏幕阅读器用户,非语义元素何时被改造为语义元素的角色。
contenteditable
如果元素的 contenteditable
属性设置为 true
,则该元素可修改、可聚焦,并且会添加到 Tab 键顺序中,就像设置了 tabindex="0"
一样。Contenteditable
是一个枚举属性,支持值 true
和 false
,如果该属性不存在或具有无效值,则默认值为 inherit
。
以下三个起始标记是等效的:
<style contenteditable>
<style contenteditable="">
<style contenteditable="true">
如果您添加 <style contenteditable="false">
,则该元素不可修改(除非默认情况下可修改,例如 <textarea>
)。如果该值无效(例如 <style contenteditable="😀">
或 <style contenteditable="contenteditable">
),则该值默认为 inherit
。
如需在状态之间切换,请查询只读属性 HTMLElement.isContentEditable 的值。
const editor = document.getElementById("myElement");
if(editor.contentEditable) {
editor.setAttribute("contenteditable", "false");
} else {
editor.setAttribute("contenteditable", "");
}
或者,您也可以通过将 editor.contentEditable
设置为 true
、false
或 inherit
来指定此属性。
全局属性可以应用于所有元素,包括 <style>
元素。您可以使用属性和少量 CSS 来制作实时 CSS 编辑器。
<style contenteditable>
style {
color: inherit;
display:block;
border: 1px solid;
font: inherit;
font-family: monospace;
padding:1em;
border-radius: 1em;
white-space: pre;
}
</style>
尝试将 style
的 color
更改为除 inherit
之外的值。然后,尝试将 style
更改为 p
选择器。
请勿移除 display 属性,否则样式块将消失。
自定义属性
我们只是简单介绍了 HTML 全局属性。还有更多属性仅适用于一个或一组有限的元素。 即使定义了数百个属性,您可能也需要规范中未包含的属性。HTML 可以满足您的需求。
您可以通过添加 data-
前缀来创建所需的任何自定义属性。您可以为属性指定任何名称,但该名称必须以 data-
开头,后跟任何不以 xml
开头且不包含冒号 (:
) 的小写字符序列。
虽然 HTML 具有容错性,即使您创建了不支持的属性(不以 data
开头),或者甚至以 xml
开头或包含 :
来创建自定义属性,也不会出现问题,但创建以 data-
开头的有效自定义属性还是有好处的。借助自定义数据属性,您可以确保自己不会意外使用现有的属性名称。自定义数据属性可应对未来变化。
虽然浏览器不会为任何特定的 data-
前缀属性实现默认行为,但有一个内置的数据集 API 可用于迭代自定义属性。自定义属性是一种通过 JavaScript 传达应用特定信息的绝佳方式。以 data-name
的形式向元素添加自定义属性,并通过 DOM 使用相关元素上的 dataset[name]
访问这些属性。
<blockquote data-machine-learning="workshop"
data-first-name="Blendan" data-last-name="Smooth"
data-formerly="Margarita Maker" data-aspiring="Load Balancer"
data-year-graduated="2022">
HAL and EVE could teach a fan to blow hot air.
</blockquote>
您可以使用完整的属性名称 getAttribute()
,也可以使用更简单的 dataset
属性。
el.dataset["machineLearning"]; // workshop
e.dataset.machineLearning; // workshop
dataset
属性会返回每个元素的 data-
属性的 DOMStringMap
对象。<blockquote>
上有多个自定义属性。通过 dataset 属性,您无需知道这些自定义属性是什么,即可访问它们的名称和值:
for (let key in el.dataset) {
customObject[key] = el.dataset[key];
}
本文中的属性是全局属性,这意味着它们可以应用于任何 HTML 元素(尽管并非所有属性都会对这些元素产生影响)。接下来,我们将深入了解链接,并介绍初始图片中未提及的两个属性(target
和 href
)以及其他几个特定于元素的属性。
检验您的掌握情况
测试您对属性的了解程度。
id
在文档中应该是唯一的。
选择格式正确的自定义属性。
birthday
data:birthday
data-birthday