前端三件套简单学习:HTML篇2
属性的基本语法与规则
<tagname attr="value" boolean-attr disabled data-info='123'>内容</tagname>
- 键=值对:通常写成
name="value"
(值可以用单引号或双引号)。 - 布尔属性(boolean):只要属性存在就视为真,如
<input disabled>
。也可写成disabled="disabled"
或disabled=""
,但在 HTML 中只需存在。 - 大小写:HTML 属性名不区分大小写(惯例小写)。在 XHTML / XML 中区分大小写且必须合法闭合。
- 自定义属性:以
data-
开头,例如data-id="42"
,用于存储自定义数据,不会与将来标准冲突。
全局属性(几乎所有元素都能用)
id
:文档唯一标识,供 CSS、JS、锚点使用。class
:可复用的类名(空格分隔),供 CSS/JS 选择器使用。style
:内联样式(不推荐大量使用)。title
:额外提示(鼠标悬停通常显示为 tooltip)。hidden
:表示元素不应被显示(布尔属性)。tabindex
:定义元素的键盘焦点顺序(-1
表示可聚焦但不可通过 Tab)。lang
、dir
:语言与方向(如lang="zh"
、dir="rtl"
)。contenteditable
:允许用户直接编辑元素内容(true
/false
/inherit
)。draggable
:是否可拖动(true
/false
)。spellcheck
:是否进行拼写检查。role
(ARIA)与aria-*
系列(无障碍属性)。
示例:
<div id="profile" class="card highlighted" tabindex="0" role="region" aria-label="用户信息">
...
</div>
常见标签相关属性(按用途列举)
链接 / 资源
<a href="...">
:目标 URL。可配合target
(如_blank
)和rel
(如noopener noreferrer
)安全使用。<img src="..." alt="描述" srcset="..." sizes="..." loading="lazy">
:alt
:必须,图像替代文本(无障碍与 SEO)。srcset
/sizes
:响应式图片。loading="lazy"
:延迟加载(现代浏览器支持)。
<link href="..." rel="stylesheet" crossorigin integrity>
:资源引用与 SRI。<script src="..." async defer type="module" crossorigin>
:脚本加载控制。
表单相关
<input type="text" name="username" value placeholder required readonly disabled maxlength pattern>
<select name>
,<option value selected>
<textarea name rows cols placeholder>
<form action method enctype target>
:表单提交控制。
媒体
<video src controls autoplay muted loop poster preload>
<audio controls src>
表格
<td colspan="2" rowspan="3">
:合并单元格。<th scope="col">
:辅助无障碍说明表头作用。
属性类型(理解很重要)
- 字符串属性:任意文本(
title
,alt
,placeholder
)。 - 布尔属性:存在即真(
disabled
,checked
,readonly
,hidden
)。 - 枚举属性:接受一组特定值(如
contenteditable
的true|false|inherit
)。 - URL 属性:
href
,src
等,值为 URL(相对/绝对)。注意安全(避免javascript:
)。 - 整数/数值属性:
rows
,cols
,maxlength
等。 - 空或无值属性:在 HTML 中允许写成
<input required>
。
属性 vs DOM 属性(非常关键)
HTML 属性是 标记层 的字符串;DOM 属性是 JS 对象 的字段,它们 并不总是同步(但有映射关系)。
<input id="x" value="foo">
在 JS 中:
const el = document.getElementById('x');
el.getAttribute('value'); // "foo" —— HTML 属性字符串
el.value; // "foo" —— DOM 属性(可以变化)
el.value = 'bar'; // 改变 DOM 属性,但 HTML 源码不变
el.getAttribute('value'); // 在某些情况下仍是 "foo",除非用 setAttribute 更新
- 常见:
checked
,selected
,value
,disabled
等在 DOM 上为实时状态(property)。 - 操作方法:
element.getAttribute(name)
/element.setAttribute(name, value)
/element.removeAttribute(name)
;或直接操作element.name
(property)。 - 建议:读取原始属性使用
getAttribute
;操作控件状态用 DOM property(更直观)。
dataset:访问 data-*
自定义属性
- HTML:
<div data-user-id="42" data-role="admin"></div>
- JS:
const el = document.querySelector('div');
el.dataset.userId // "42" —— 注意 kebab-case -> camelCase
el.dataset.role // "admin"
data-*
适合存放与 DOM 元素相关的自定义数据,但不要把敏感信息或大量 JSON 放在属性中(可用 ID 再从后端/内存查找)。
无障碍属性(ARIA)
role
:声明元素用途(如role="button"
)。aria-label
,aria-labelledby
,aria-describedby
:提供可读标签/描述。aria-hidden="true"
:屏蔽屏幕阅读器。aria-expanded
,aria-controls
,aria-live
等用于动态组件。
原则:优先使用语义标签(<button>
而不是role="button"
),在必要时增加 aria 提示。
事件处理属性(内联事件)
onclick="..."
,onchange="..."
等可以直接放在标签上,但不推荐(分离关注点、难维护、易受 XSS)。- 推荐做法:用
addEventListener
在 JS 中绑定事件。
HTML 的块级元素(block)和行内元素(inline) 概念与直观区别
- 块级元素(block-level element)
- 在文档流中生成一个 块框(block box)。
- 默认会 从新行开始,并占据可用宽度的全部(即默认
width: auto
)。 - 可以设置
width
、height
、垂直方向margin
会参与折叠(margin collapse)。 - 典型用途:页面的大结构、段落、分区、列表等。
- 行内元素(inline element)
- 在文档流中生成 行内框(inline box),不换行(在可用空间内连续排列),高度由
line-height
决定。 - 默认不能设置
width
/height
(设置无效),可以设置左右margin
/padding
但垂直 margin/padding 行为较特殊。 - 典型用途:文本级别的标记,如加粗、链接、图片嵌入等。
- 在文档流中生成 行内框(inline box),不换行(在可用空间内连续排列),高度由
浏览器默认渲染行为(要点)
- 块元素会在它前后生成换行空间(如
<div>
、<p>
、<h1>
等)。 - 行内元素在行内排列(如
<span>
、<a>
、<strong>
、<img>
等)。 - 行内元素的垂直对齐可由
vertical-align
控制(baseline、middle、top、bottom 等)。 - 块元素的垂直 margin 可能发生 折叠(margin collapse)(例如相邻两个块元素垂直外边距会折叠为较大者),行内元素没有这个规则。
display
属性可以改变元素表现(例如把span
设为display:block
,或把div
设为display:inline-block
)。
3. 常见元素举例
- 常见块级元素:
div
、p
、h1
~h6
、ul
、ol
、li
、table
、header
、footer
、section
、article
、nav
、aside
、form
、figure
、blockquote
等。 - 常见行内元素:
span
、a
、strong
、em
、b
、i
、img
(替换元素)、input
(替换元素)label
、br
(换行符)、small
、cite
等。 - 替换元素(replaced elements):比如
<img>
、<input>
、<video>
(它们的显示由外部资源决定,并可能有内在尺寸)。替换元素常被当作行内元素,但也可被设为 block/inline-block。
HTML5 内容模型(更准确的语义视角)
- HTML5 用术语 flow content(流式内容)、phrasing content(短语内容) 等来描述哪些元素可以放在哪些容器中。一般来说:
- 块级语义元素通常属于 flow content(可包含其他 flow content 或 phrasing content,根据具体标签限制)。
- 行内元素通常属于 phrasing content(放在段落
<p>
等处)。
- 注意:HTML5 不再严格以“块/行内”分类作为唯一规则(浏览器实际渲染受
display
决定),但语义模型仍对文档结构、可访问性重要。
display
属性:把块/行内转换为样式控制点
display
是关键:常见值包括:display: block;
display: inline;
display: inline-block;
—— 行内流中但允许设置width/height
(非常常用)display: none;
display: list-item;
(列表项)display: table
/table-row
/table-cell
等display: flex;
/display: grid;
(把元素设为新的布局上下文)
- 举例:把
<span style="display:block">
会表现得像块元素(换行、可设宽高)。
行内与块级在布局与样式上的差异(细节)
- 宽高:块元素可直接设置
width/height
;行内元素默认忽略width/height
(使用inline-block
则可以设置)。 - 外边距(margin):
- 水平
margin-left/right
对行内元素有效,垂直margin-top/bottom
对行内元素通常不会影响行间距(行为复杂,不可依赖)。 - 块元素的垂直 margin 可折叠(例如父首个子元素的上 margin 可能与父 margin 折叠),行内没有折叠。
- 水平
- 填充(padding):行内元素的左右 padding 有效,垂直 padding 会影响行高但不会像块元素那样改变布局方式。
- 换行:块元素自动换行;行内元素在行内换行(换行点由空白或
white-space
控制)。 - 基线对齐:行内元素相互之间遵循基线(baseline)对齐(可用
vertical-align
调整)。
嵌套规则与实际浏览器行为
- 传统观点(HTML4)曾说“块元素不能放入行内元素内”。但HTML5 更灵活,语义上用 phrasing/flow 内容限制。实际浏览器在不合法嵌套时会自动修正 DOM(比如在
span
中放div
,浏览器通常会把div
移出或关闭span
)。 - 最佳实践:保持语义和合法嵌套,不要依赖浏览器的自动修正。
实例对比(HTML + CSS)
<style>
.block { background:#eef; margin:8px 0; padding:8px; }
.inline { background:#efe; padding:4px 8px; }
.inline-block { display:inline-block; padding:8px; width:150px; height:60px; }
</style>
<div class="block">这是一个块元素(div),默认换行并占满宽度。</div>
<span class="inline">这是一个行内元素(span),不会换行,只占文本宽度。</span>
<span class="inline">另一个行内元素</span>
<div class="block">
<span class="inline-block">inline-block 元素:可设置宽高</span>
<span class="inline-block">第二个 inline-block</span>
</div>
- 上例中
inline-block
在同一行显示,但可设宽高;div
是块级会单独占一行。
常见误区与坑
- 误区:用
div
/块元素做小段装饰 —— 更推荐用语义元素(如<p>
、<section>
)或行内元素配合 CSS。 - 误区:所有行内元素不能设宽高 ——
inline-block
可以;而替换元素(如img
)有内在尺寸。 - 坑:margin collapse —— 块元素的上下 margin 折叠会让间距不是你预期的大小(需用 padding 或 border 或额外 wrapper 解决)。
- 坑:把下划线样式、对齐等仅靠元素类型管理 —— 样式应交给 CSS,结构交给 HTML(语义优先)。
语义与可访问性建议
- 语义优先:选择元素时优先按语义(结构/含义),不要仅为样式选择
div
/span
。例如导航用<nav>
,文章标题用<h1>
,段落用<p>
。 - 交互元素用专有标签:例如点击行为用
<button>
而不是用<a>
或<div role="button">
(前者自带键盘/无障碍支持)。 - CSS 可用来改变呈现(display),但不要用 display 来替代语义。
什么时候用哪种类型?
- 布局/大块结构:
div
、section
、article
、header
、footer
(块级)。 - 文本级修饰:
span
、strong
、em
(行内/phrasing content)。 - 当需要行内且控制尺寸:使用
display:inline-block
或flex
(使元素成为块容器再以内联方式排列)。 - 当需要复杂行内布局:优先考虑
display:flex
或grid
在父容器上,而非滥用float
。
小结(要点回顾)
- 块元素:新行开始,占据整行,可设宽高、会参与 margin 折叠——用于页面结构。
- 行内元素:与文本同一行排列,不能直接设宽高(可用 inline-block),垂直布局受
line-height
和vertical-align
控制——用于文本级修饰与内嵌内容。 - 用
display
控制呈现,但用语义标签控制结构。 - 清晰的嵌套与可访问性比仅仅考虑显示效果更重要。
HTML表单
表单的基本结构与核心属性
<form id="signup" action="/signup" method="post" enctype="multipart/form-data" target="_self" autocomplete="on" novalidate>
<!-- 表单控件 -->
<button type="submit">提交</button>
</form>
action
:提交目标 URL(如果为空或省略,则提交到当前页面 URL)。method
:提交方法,常用get
或post
(不区分大小写)。enctype
(仅对method="post"
有意义):表单数据编码方式,常见值:application/x-www-form-urlencoded
(默认):键值对 URL 编码(空格变+
,特殊字符百分号编码)。multipart/form-data
:用于文件上传,数据分成多个部分,带 boundary。text/plain
:不常用,文本形式(不可靠)。
target
:提交后打开结果的窗口/框架(_self
,_blank
,_parent
,_top
或框架名)。autocomplete
:是否允许浏览器自动补全(on
/off
或更精细的字段级值)。novalidate
:禁止浏览器内建约束验证(Constraint Validation)提交前检查。name
:虽然是控件属性,但如果表单包含没有name
的控件,它就不会被提交(缺 name 的控件不会出现在提交数据里)。
常用表单控件(元素)与重要属性
<input>
:最常见。type
值众多:text
,password
,email
,tel
,url
,number
,range
,date
,datetime-local
,time
,checkbox
,radio
,file
,hidden
,submit
,reset
,button
,search
,color
等。- 重要属性:
name
,value
,placeholder
,required
,readonly
,disabled
,maxlength
,minlength
,min
,max
,step
,pattern
(正则)、autocomplete
。
- 重要属性:
<textarea>
:多行文本。属性:name
,rows
,cols
,maxlength
,placeholder
,wrap
。<select>
、<option>
:下拉选择。multiple
支持多选;option
有value
和selected
。<button>
:三种type
:submit
(提交表单)、reset
(重置表单)、button
(不提交,常用于 JS 事件)。<label for="id">
:为控件提供可点击文本;最好总是为每个控件提供<label>
(可提高可访问性)。也可包裹控件<label>文本 <input /></label>
。<fieldset>
+<legend>
:用于将一组控件分组并给出标题。<datalist>
:为<input list="id">
提供预选项(UI 取决于浏览器)。<output>
:显示计算结果与表单交互结果(可结合 JS 更新)。form
属性(HTML5):任何表单控件可通过form="form-id"
关联到任意<form id="form-id">
,即使不在其内部。
表单提交的两种基本模式:GET vs POST
GET
- 将表单数据编码到 URL 查询字符串(
?key=value&...
)。 - 适用于无副作用的请求(检索、搜索)。
- 有长度限制(浏览器/服务器限制),敏感数据不应放在 URL(会出现在历史、日志、分享链接中)。
- 可以被缓存、书签化。
POST
- 将数据放入请求主体(body)。
- 适用于创建/修改/包含敏感或大数据(如文件)场景。
- 无明显长度限制(受服务器限制),不可书签化。
举例(GET 请求首行):
GET /search?q=html+form&page=2 HTTP/1.1
Host: example.com
举例(POST, application/x-www-form-urlencoded body):
POST /submit HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
name=alice&email=a%40ex.com
表单编码详解(enctype)
application/x-www-form-urlencoded
(默认)- key=value 对,字符经过 percent-encoding,空格变
+
。 - 用于普通文本数据。
- key=value 对,字符经过 percent-encoding,空格变
multipart/form-data
每个字段作为单独 part,用 boundary 分隔;每个 part 包含
Content-Disposition: form-data; name="..."
,文件会包含filename="..."
和Content-Type: ...
。必须用于文件
<input type="file">
。例:一个 part 看起来像:
--AaB03x Content-Disposition: form-data; name="avatar"; filename="me.png" Content-Type: image/png <binary data...> --AaB03x--
text/plain
- 非结构化文本,通常不可用作实际应用。
浏览器端验证(Constraint Validation API)
HTML5 提供了丰富的内建验证支持:
- 常用属性:
required
,pattern
(正则),type
(email/tel/url/number etc. 会自动校验格式),min
,max
,step
,minlength
,maxlength
。 - JS API:
element.checkValidity()
:返回true/false
(是否通过验证)。element.reportValidity()
:弹出内建提示(并返回 boolean)。element.setCustomValidity("msg")
:设定自定义验证信息(空字符串表示无错误)。form.checkValidity()
:检查整个表单。input.validity
:包含一组布尔子属性(valueMissing
,typeMismatch
,patternMismatch
,tooLong
,tooShort
,rangeUnderflow
,rangeOverflow
,stepMismatch
,badInput
,customError
)。
novalidate
或者form.noValidate = true
可跳过浏览器验证(这时需用 JS 或服务端验证)。
示例:
<input type="email" name="email" required>
<script>
const f = document.querySelector('form');
f.addEventListener('submit', e => {
if (!f.checkValidity()) {
e.preventDefault(); // 阻止提交
f.reportValidity();
}
});
</script>
文件上传注意点
- 必须使用
enctype="multipart/form-data"
且method="post"
。 - 前端可加
accept
属性限制可选文件类型(accept="image/*,video/*"
),但不可代替服务端校验。 - 服务端需要:
- 限制文件大小;
- 校验文件类型(不要仅检查扩展名,建议检测 MIME 或解析头部);
- 存储到安全目录并避免文件名冲突(使用随机名);
- 禁止执行上传目录下文件(防止任意代码执行)。
无障碍(Accessibility)与表单
- 始终为控件提供
<label>
(使用for
指向id
)。 - 使用
aria-describedby
提供错误信息或提示与输入的关联。 - 对复选框/单选按钮使用
<fieldset>
+<legend>
来描述组。 - 错误提示应可被屏幕阅读器读到(使用
role="alert"
或aria-live="assertive"
动态宣布)。 - 避免仅用颜色区分错误,提供文本/图标辅助。
安全性与常见问题
- 服务器端验证必须存在:浏览器端验证只是 UX 优化,不能替代服务器验证(客户端可以绕过)。
- XSS(跨站脚本):不要把未转义的表单输入直接输出在页面上,使用适当的转义/模板引擎。
- CSRF(跨站请求伪造):
- 对修改操作(POST/PUT/DELETE)应使用 CSRF token(服务端生成并校验),或使用 SameSite cookie、双重提交 cookie 等策略。
- 文件上传:参见上面“文件上传注意点”。
- 敏感数据传输:始终通过 HTTPS 发送(阻止中间人窃听)。
target="_blank"
安全:对外链表单结果要小心window.opener
,通常在链接或脚本中加rel="noopener noreferrer"
。对于表单提交到新窗口,若在结果页中执行脚本,可能存在 opener 攻击链。
登录表单(简单)
<form action="/login" method="post" autocomplete="on">
<label for="email">邮箱</label>
<input id="email" name="email" type="email" required>
<label for="pwd">密码</label>
<input id="pwd" name="password" type="password" required minlength="6">
<button type="submit">登录</button>
</form>
文件上传 + AJAX
<form id="upload" action="/upload" method="post" enctype="multipart/form-data">
<label>选择文件 <input type="file" name="file" required></label>
<button type="submit">上传</button>
</form>
<script>
const f = document.getElementById('upload');
f.addEventListener('submit', async e => {
e.preventDefault();
const fd = new FormData(f);
const res = await fetch(f.action, { method: 'POST', body: fd });
console.log(await res.text());
});
</script>
快速检查清单
- 所有需要提交的控件都有
name
。 - 必填项使用
required
并在后端也校验。 - 对用户输入进行服务器端验证(长度、类型、范围、白名单/黑名单)。
- 文件上传做大小/类型/病毒扫描或严格校验。
- 使用 HTTPS,考虑 CSRF 防护。
- 提供无障碍标签和错误提示。
- 避免把敏感信息放在 GET 查询字符串。
- 对输出到页面的数据做适当转义,避免 XSS。