HTML Basic Notes
Emmet
嵌套操作
孩子 : >.
<!-- div>ul>li -->
<div>
  <ul>
    <li></li>
  </ul>
</div>
兄弟 : +.
<!-- div+ul>li -->
<div></div>
<ul>
  <li></li>
</ul>
上级:^.
<!-- ul>li^div -->
<ul>
  <li></li>
</ul>
<div></div>
ul>li>a^^div
<ul>
  <li><a href=""></a></li>
</ul>
<div></div>
重复: *.
<!-- ul>li*3 -->
<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>
分组:().
<!-- div>(p>span)*2 -->
<div>
  <p><span></span></p>
  <p><span></span></p>
</div>
属性操作
- id: #.
- class: ..
<!-- div#header+div.main+div#footer -->
<div id="header"></div>
<div class="main"></div>
<div id="footer"></div>
属性值: [].
<!-- a[title=test target=_self] -->
<a title="test" target="_self" href=""></a>
数列值:$.
<!-- p.item$*3 -->
<p class="item1"></p>
<p class="item2"></p>
<p class="item3"></p>
<!-- p.item$$*3 -->
<p class="item01"></p>
<p class="item02"></p>
<p class="item03"></p>
数列操作符:@
<!-- p.item$@-*3 @- = -1 -->
<p class="item3"></p>
<p class="item2"></p>
<p class="item1"></p>
<!-- p.item$@3*3 @3 = 从3开始3次 -->
<p class="item3"></p>
<p class="item4"></p>
<p class="item5"></p>
<!-- p.item$@-3*3 @-3 = 3次后到3结束 -->
<p class="item5"></p>
<p class="item4"></p>
<p class="item3"></p>
字符操作
字符操作:{}.
<!-- a{click} -->
<a href="">click</a>
<!-- a>{click}+span{me} -->
<a href="">click<span>me</span></a>
缺省元素
- .header+.footer->- div.header+div.footer.
- ul>.item*3->- ul>li.item*3.
- table>.row*4>.cell*3->- table>tr.row*4>td.cell*3.
Structure
Section
必须含有hx标题子标签.
Header
Not only can the page <body> contain a header,
but also can every <article> and <section> element.
Footer
Not only can the page <body> contain a footer,
but also can every <article> and <section> element.
hgroup
nav
- 传统导航条
- 侧边栏导航
- 页内跳转
- 翻页操作
main
- 每个网页只有 1 个main元素
- main不可为- article、- aside、- header、- footer、- nav孩子
address
联系信息 - QQ、住址、电子邮箱、主页链接
aside
名词解释的附属部分/友情链接/广告
blockquote
长文本引用
pre
代码段
Head
Meta data list in
HEAD.
Favicon
<head>
  <link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
</head>
Generating favicons in all necessary sizes:
<head>
  <link rel="icon" type="image/png" href="/favicon-32x32.png" />
  <link rel="apple-touch-icon" sizes="48x48" href="/favicon-48x48.png" />
  <link rel="apple-touch-icon" sizes="72x72" href="/favicon-72x72.png" />
  <link rel="apple-touch-icon" sizes="96x96" href="/favicon-96x96.png" />
  <link rel="apple-touch-icon" sizes="256x256" href="/favicon-256x256.png" />
  <link rel="apple-touch-icon" sizes="384x384" href="/favicon-384x384.png" />
  <link rel="apple-touch-icon" sizes="512x512" href="/favicon-512x512.png" />
  <link rel="manifest" href="/manifest.webmanifest" crossorigin="anonymous" />
</head>
Theme Color
<meta
  name="theme-color"
  content="#319197"
  media="(prefers-color-scheme: light)"
/>
<meta
  name="theme-color"
  content="#872e4e"
  media="(prefers-color-scheme: dark)"
/>
Form
Form:
<form action="表单提交的后台地址接口" method="post" 提交方式,一般为post>
  <fieldset 若内容比较多,用来分区>
    <legend>这是分区的标题</legend>
    <label for="file">选择照片按钮</label>
    <input type="file" id="file" />
  </fieldset>
  <fieldset>
    <legend>这是分区的标题</legend>
    <div>选择尺寸:</div>
    <input
      type="checkbox"
      多选框
      name="size"
      数据名称,交给后台
      value="5"
      值
      id="cb_0"
      checked
      disabled
      默认勾选,无法更改
    />
    <label for="cb_0">5寸</label>
    <!-- 一个input一个label,一一对应,同类name相同 -->
    <input type="radio" 单选框 name="material" value="fs" id="rd_0" />
    <label for="rd_0">富士,单选第一个</label>
    <input
      type="text"
      单行文本框,默认
      id="description"
      placeholder="里面是提示"
      value="这里是默认内容"
      readonly只读
      hidden隐藏
    />
    <input type="submit" 提交按钮 /> == <button type="submit">提交</button>
    <input type="reset" 重置按钮 /> == <button type="reset">重置</button>
    <div>
      <label for="delivery" 功能提示信息,通过for与标签对应>配送方式</label>
      <select id="delivery" 下拉选择>
        <optgroup label="group1" 给选项分组>
          <option value="0">快递</option>
          <option value="1">EMS</option>
        </optgroup>
        <option value="2" selected>平邮</option>
      </select>
    </div>
    <div>
      <label for="feedback">意见反馈,多行文本框</label>
      <textarea name="feedback" rows="4" 4行 id="feedback"></textarea>
    </div>
  </fieldset>
</form>
<input type="email" />
<input type="url" />
<input type="number" />
<input type="tel" />
<input type="search" />
<input type="range" />
<input type="color" />
<input type="date picker(data,month,week,time,datetime,datetime-local)" />
Form Validation
const usernameInput = document.querySelector('[name="name"]');
usernameInput.addEventListener('invalid', () => {
  usernameInput.setCustomValidity('Please enter your name.');
});
Form Element Attributes
Form Attribute
form=form_name:
使表单元素可放置于表单之外
Form Action Attribute
formaction=target_name:
使表单元素可提交到不同页面
Form Method Attribute
formmethod=post/get:
使表单元素以不同的方式提交
Form Enctype Attribute
enctype (HTTP Content-Type header):
- 默认值: application/x-www-form-urlencoded, 提交前编码所有字符.
- multipart/form-data不编码字符, 上传控件表单元素必须使用改值.
- text/plain: 表单元素数据中的空格编码为- +.
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">Choose file to upload</label>
    <input type="file" id="file" name="file" multiple />
  </div>
  <div>
    <button>Upload image</button>
  </div>
</form>
Form Target Attribute
target 定义表单提交后加载页面打开方式:
- self(default): 在相同的框架中打开被链接文档.
- blank: 在新窗口中打开被链接文档.
- parent: 在父框架集中打开被链接文档.
- top: 在整个窗口中打开被链接文档.
- frameName: 在指定的框架中打开被链接文档.
Form Novalidate Attribute
取消表单元素的提交验证 (novalidate):
将 submit 元素的 formnovalidate 属性值为 true,
使整个表单提交验证失效, 实现假提交,
进而弹出再次确认按钮 (真提交).
AutoFocus Attribute
<div class="form-control">
  <label for="search">Search the site...</label>
  <input
    id="search"
    name="search"
    type="search"
    placeholder="Search here ..."
    autofocus
  />
</div>
Required Attribute
<div class="form-control">
  <label for="film">The film in question?</label>
  <input
    id="film"
    name="film"
    type="text"
    placeholder="e.g. King Kong"
    required
    aria-required="true"
  />
</div>
Disabled and Hidden Attribute
- disabled表单元素的数据不会被提交.
- hidden表单元素的数据仍会被提交.
AutoComplete Attribute
- email.
- new-password.
- current-password.
- street-address.
- address-line1.
- address-line2.
- address-line3.
- city.
- state.
- country.
- tel.
- zip.
- one-time-code.
- cc-name.
- cc-number.
- cc-exp.
- off.
<form>
  <div>
    <label for="email">Email</label>
    <input autocomplete="email" required type="email" id="email" name="email" />
  </div>
  <div>
    <label for="password">Password</label>
    <input
      autocomplete="new-password"
      type="password"
      id="password"
      name="password"
    />
  </div>
  <button>Sign up</button>
</form>
<form>
  <div>
    <label for="email">Email</label>
    <input autocomplete="email" required type="email" id="email" name="email" />
  </div>
  <div>
    <label for="password">Password</label>
    <input
      autocomplete="current-password"
      type="password"
      id="password"
      name="password"
    />
  </div>
  <button>Sign in</button>
</form>
Form Labels
指定表单元素的标签
<label for="input_id">OS : </label>
隐式 Control 属性
javascript tips:通过 control 属性改变标签对应表单元素的值
const textbox = $('#label_id').control;
textbox.value = '666666'; //  等同于 input.value = '666666';
Form Input
Text Input
<input type="text" spellcheck="true" lang="en" />
Radio Input
name 相同时, 多个 radio 组成一个 radio group.
Checkbox Input
Search Input
搜索条:
<div class="form-control">
  <label for="search">Search the site...</label>
  <input
    id="search"
    name="search"
    type="search"
    placeholder="Search here ..."
  />
</div>
Tel Input
电话号码无输入检查:
<div class="form-control">
  <label for="tel">Telephone (so we can berate you if you're wrong)</label>
  <input
    id="tel"
    name="tel"
    type="tel"
    placeholder="1-234-546758"
    autocomplete="off"
    required
  />
</div>
Url Input
<div class="form-control">
  <label for="web">Your Web address</label>
  <input id="web" name="web" type="url" placeholder="https://www.mysite.com" />
</div>
Email Input
<div class="form-control">
  <label for="email">Your Email address</label>
  <input
    type="email"
    id="email"
    name="email"
    placeholder="dwight.schultz@gmail.com"
    required
  />
</div>
Number Input
<div class="form-control">
  <label for="yearOfCrime">Year Of Crime</label>
  <input
    id="yearOfCrime"
    name="yearOfCrime"
    type="number"
    min="1929"
    max="2015"
    step="1"
    required
  />
</div>
Range Input
<div class="form-control">
  <input
    id="howYouRateIt"
    name="howYouRateIt"
    type="range"
    min="1"
    max="10"
    value="5"
    onchange="showValue(this.value)"
  />
  <span id="range">5</span>
</div>
DateTime Input
[type]:
- date.
- month.
- week.
- time.
- datetime-local.
<input id="date" name="date" type="date" />
<input id="month" name="month" type="month" />
<input id="week" name="week" type="week" />
<input id="time" name="time" type="time" />
Color Input
<div class="form-control">
  <label for="color">Your favorite color</label>
  <input id="color" name="color" type="color" />
</div>
List Input
autocomplete, 为输入框指定智能提示数据:
<div class="form-control">
  <label for="awardWon">Award Won</label>
  <input id="awardWon" name="awardWon" type="text" list="awards" />
  <datalist id="awards">
    <select>
      <option value="Best Picture"></option>
      <option value="Best Director"></option>
      <option value="Best Adapted Screenplay"></option>
      <option value="Best Original Screenplay"></option>
    </select>
  </datalist>
</div>
File Input
File type:
<input type="file" accept=".jpeg,.png" />
Multiple files:
<input type="file" multiple />
Capture device camera:
<!-- Front camera -->
<input type="file" capture="user" accept="image/*" />
<!-- Back camera -->
<input type="file" capture="environment" accept="image/*" />
Indeterminate
检查 [type=checkbox] 的状态:
if (checkbox.indeterminate) {
  doSomething();
} else {
  if (checkbox.checked) {
    doSomething();
  } else {
    doSomething();
  }
}
Pattern
通过正则表达式指定输入格式:
<input pattern="[0-9][A-Z]{3}" />
Validity
返回 ValidityState 对象, 拥有 ValidityState.valid 属性.
Output
<input> 元素的镜像元素.
Textarea
Maxlength
Cols
每行可显示字符最大数
Wrap
- hard:换行时加入换行标志,此时必须指定cols属性
- soft:不加入换行标志
Menu
Dialog
<button class="btn" data-toggle="#dialog">Open modal</button>
<button class="btn" data-toggle="#dialog-tall">Open tall modal</button>
<dialog id="dialog">
  <header>
    Example modal
    <button class="btn btn-close" data-close>
      <svg width="16" height="16"><use xlink:href="#x" /></svg>
    </button>
  </header>
  Some basic text inside the modal to demonstrate how it all looks and works.
</dialog>
<dialog id="dialog-tall">
  <header>
    Super tall modal
    <button class="btn btn-close" data-close>
      <svg width="16" height="16"><use xlink:href="#x" /></svg>
    </button>
  </header>
  <p>Line breaks to push the height out.</p>
  <button type="button" class="btn" data-close>Close</button>
</dialog>
const togglers = document.querySelectorAll('[data-toggle]');
const closers = document.querySelectorAll('[data-close]');
togglers?.forEach(toggler => {
  const target = toggler.getAttribute('data-toggle');
  const dialogs = document.querySelectorAll(target);
  toggler.addEventListener('click', _event => {
    dialogs.forEach(dialog => {
      dialog.showModal();
    });
  });
});
closers?.forEach(closer => {
  closer.addEventListener('click', _event => {
    const dialog = closer.closest('dialog');
    dialog.close();
  });
});
Datalist
<datalist id="register-prompt" style="display:none;">
  <option value="Windows">Windows</option>
  <option value="Mac OS">Mac OS</option>
  <option value="Linux">Linux</option>
</datalist>
<label for="myBrowser">Choose a browser from this list:</label>
<input list="browsers" id="myBrowser" name="myBrowser" />
<datalist id="browsers">
  <option value="Chrome"></option>
  <option value="Firefox"></option>
  <option value="Internet Explorer"></option>
  <option value="Opera"></option>
  <option value="Safari"></option>
  <option value="Microsoft Edge"></option>
</datalist>
Form Demo
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Sign Up Form</title>
    <link rel="stylesheet" href="css/normalize.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Lato:300,400,700"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="css/main.css" />
  </head>
  <body>
    <form action="index.html" method="post">
      <h2>Your basic info</h2>
      <label for="name">Name</label>
      <input type="text" id="name" name="student_name" />
      <label for="mail">Email</label>
      <input type="email" id="mail" name="student_email" />
      <label for="password">Password</label>
      <input type="password" id="password" name="student_password" />
      <label>Age:</label>
      <input
        type="radio"
        id="under_16"
        value="under_16"
        name="user_age"
      /><label for="under_16" class="light">Under 16</label><br />
      <input type="radio" id="over_16" value="over_16" name="user_age" /><label
        for="over_16"
        class="light"
        >16 or Older</label
      >
      <h2>Your profile</h2>
      <label for="bio">Biography</label>
      <textarea id="bio" name="student_bio"></textarea>
      <label for="courses">Select Courses</label>
      <select id="courses" name="student_courses">
        <optgroup label="Engineering">
          <option value="computer_engineering">
            Computer Science Engineering
          </option>
          <option value="electrical_engineering">Electrical Engineering</option>
          <option value="mechanical_engineering">Mechanical Engineering</option>
          <option value="civil_engineering">Civil Engineering</option>
          <option value="chemical_engineering">Chemical Engineering</option>
        </optgroup>
        <optgroup label="Management">
          <option value="finance_management">Finance Management</option>
          <option value="technology_management">Technology Management</option>
          <option value="marketing_management">Marketing Management</option>
          <option value="business_administration">
            Business Administration
          </option>
        </optgroup>
      </select>
      <label>Interests:</label>
      <input
        type="checkbox"
        id="engineering"
        value="interest_engineering"
        name="user_interest"
      /><label class="light" for="engineering">Engineering</label><br />
      <input
        type="checkbox"
        id="business"
        value="interest_business"
        name="user_interest"
      /><label class="light" for="business">Business</label><br />
      <input
        type="checkbox"
        id="law"
        value="interest_law"
        name="user_interest"
      /><label class="light" for="law">Law</label>
      <button type="submit">Submit</button>
    </form>
  </body>
</html>
Content
Details
Accordion list:
<div class="container">
  <h3>FAQ</h3>
  <details open>
    <summary>Why is it called an accordion menu?</summary>
    <hr />
    <p>
      Because each part of it can expand and contract, like in an accordion. If
      you don't know what an accordion is, just imagine a cute fluffy cat. You
      still won't know what it is, but at least you'll feel better about not
      knowing.
    </p>
  </details>
  <details>
    <summary>Huh?</summary>
    <hr />
    <p>Huh.</p>
  </details>
  <details>
    <summary>If I use an accordion menu will it make me cool?</summary>
    <hr />
    <p>
      No, not unless you're designing a MySpace profile. The
      <code>{"details"}</code> element is cool though, and you can use that for
      a lot of things. I'm using it on this page right below here, to show the
      code for each example!
    </p>
  </details>
</div>
<style>
  .container {
    padding: 1em 2em;
    border: 0.2em solid black;
    border-radius: 2em;
  }
  details {
    padding: 1em;
    margin-bottom: 1em;
    border: 0.1em solid black;
    border-radius: 1em;
  }
  summary {
    font-size: 1.2em;
    cursor: pointer;
  }
  summary::-webkit-details-marker {
    display: none;
  }
  details[open] summary {
    font-size: 1.3em;
  }
</style>
Details Summary
展开与收缩时触发 toggle 事件:
<details>
  <summary>Details</summary>
  Something small enough to escape casual notice.
</details>
Details Data Grid
Details AutoComplete
Details Open
默认 open=false.
Description List
- <dl>: description list.
- <dt>: description Term.
- <dd>: description details.
<h1>Review your data</h1>
<p>
  Please review the data you entered in the previous step to ensure it is
  correct:
</p>
<dl>
  <dt>First name</dt>
  <dd>Marc</dd>
  <dt>Last name</dt>
  <dd>Simmons</dd>
  <dt>Date of Birth</dt>
  <dd><time datetime="1990-05-15">May 15 1990</time></dd>
</dl>
Table
<table>
  <thead>
    <tr>
      <th scope="col">Col Header 1</th>
      <th scope="col">Col Header 2</th>
      <th scope="col">Col Header 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Row Header 1</th>
      <td>Row 1 Col 2</td>
      <td>Row 1 Col 3</td>
    </tr>
    <tr>
      <th scope="row">Row Header 2</th>
      <td>Row 2 Col 2</td>
      <td>Row 2 Col 3</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th scope="row">Summary</th>
      <td>Col 2 summary</td>
      <td>Col 3 summary</td>
    </tr>
  </tfoot>
</table>
Mark
突出/高亮显示,无关原文作者
Ins
Insert text
<ins
  cite="https://bugzilla.mozilla.org/show_bug.cgi?id=1620467"
  datetime="2020-07-23"
>
  The <code>appearance</code> property, previously only available prefixed in
  Firefox, can now be used in all modern browsers un-prefixed.
</ins>
Del
Delete text
<del
  cite="https://bugzilla.mozilla.org/show_bug.cgi?id=1620467"
  datetime="2020-07-23"
>
  Firefox doesn't support CSS's standard <code>appearance</code> property, so
  you can only use it prefixed.
</del>
U
underline text
Em
文章重点
Strong
段落强调
Small
- 免责声明、注意事项、法律规定、版权声明
- 不改变文字样式
Hr
下划线
Progress
value/max 百分比
<label for="file">File progress:</label>
<progress id="file" max="100" value="70">70%</progress>
Meter
Value
Min
Max
Low
High
Optimum
Wbr
软换行
Media
Figure
流内容: 如代码、文件、图片、音频、视频.
Figcaption
<figure> 可拥有唯一的 0/1 个 <figcaption>:
<figure aria-labelledby="image-alt">
  <img src="/media/cc0-images/elephant-660-480.jpg" alt="Elephant at sunset" />
  <figcaption id="image-alt">An elephant at sunset</figcaption>
</figure>
Image
Attr -
Src
Alt
(图片崩溃时文本)、title(提示信息)、class(CSS 类选择器)
Responsive Images
<!-- `img` element -->
<img src="foo" alt="bar" />
<!-- `img` element, `srcset` attribute -->
<img
  srcset="foo-320w.jpg 320w, foo-480w.jpg 480w, foo-800w.jpg 800w"
  sizes="(max-width: 480px) 440px, 320px"
  src="foo-320w.jpg"
  alt="bar"
/>
Picture
- Multiple <source>and only one<img>
<!-- `picture` and `source` elements, `srcset` attributes -->
<picture>
  <source media="(max-width: 799px)" srcset="foo-480w.jpg" />
  <source media="(min-width: 800px)" srcset="foo-800w.jpg" />
  <img src="foo-800w.jpg" alt="bar" />
</picture>
- Multiple width images
<picture>
  <source srcset="128px.jpg, 256px.jpg 2x, 512px.jpg 3x" />
  <img src="foo.jpg" alt="bar" />
</picture>
- Multiple type images
<picture>
  <source srcset="foo.avif" type="image/avif" />
  <source srcset="foo.webp" type="image/webp" />
  <img src="foo.jpg" />
</picture>
SVG
const svgElement = document.createElementNS(
  'http://www.w3.org/2000/svg',
  'svg'
);
const svgRectElement = document.createElementNS(
  'http://www.w3.org/2000/svg',
  'rect'
);
Embed
Embed best practice:
<script src="lazySizes.min.js" async></script>
<iframe
  data-src="https://www.youtube.com/embed/aKydtOXW8mI"
  width="560"
  height="315"
  class="lazyload"
  title="YouTube video player"
  frameborder="0"
  allow="accelerometer; autoplay; clipboard-write;
        encrypted-media; gyroscope; picture-in-picture"
  allowfullscreen
>
</iframe>
Video
<video
  src="myVideo.mp4"
  width="640"
  height="480"
  controls
  autoplay
  preload="auto"
  loop
  poster="myVideoPoster.png"
>
  If you're reading this either video didn't load or your browser is legacy!
</video>
<video
  width="640"
  height="480"
  controls
  preload="auto"
  loop
  poster="myVideoPoster.png"
>
  <source src="myVideo.sp8" type="video/super8" />
  <source src="myVideo.mp4" type="video/mp4" />
  <p><b>Download Video:</b> MP4 Format:<a href="myVideo.mp4">"MP4"</a></p>
</video>
Anchor
Anchor Href
[href] 超链接指向超链接/#id/#name:
<a href="https://github.com">Link</a> <a href="#title">Link</a>
Anchor ID
当前锚点标识.
Anchor Name
当前锚点名字.
Anchor Target
定义被链接文档出现方式:
- self: 默认方式, 在相同的框架中打开被链接文档.
- blank: 在新窗口中打开被链接文档.
- parent: 在父框架集中打开被链接文档.
- top: 在整个窗口中打开被链接文档.
- framename: 在指定的框架中打开被链接文档.
Command
Information
Time
Pub Date
pubdate:
boolean 代表当前<time>表示整个网页的时间
DateTime
<time datetime="2010-11-13T20:00Z"></time>
<time datetime="2010-11-13T20:00+09:00"></time>
- T分隔日期与时间
- Z使用 UTC 标准时间
- +时差
Attributes
dataset
<td data-row="1" data-column="1"></td>
const onChange = event => {
  const {
    currentTarget: {
      dataset: { row, column },
    },
  } = event;
};
Global Attributes
contentEditable
-boolean
hidden
boolean
spellcheck
boolean
tabindex
-1: 编程可获得焦点,tab 键不可获得焦点
Accessibility
Semantic HTML
Structure Accessibility
- Semantics Section Reference
- <header>:- role="banner"
- <nav>:- role="navigation"
- <main>:- role="main"
- <aside>:- role="complementary"
- <section>:- role="region"
- <article>:- role="article"
- <footer>:- role="contentinfo"
<header>
  <nav>
    <ul>
      <li><a></a></li>
    </ul>
  </nav>
</header>
<main>
  <section></section>
</main>
<footer></footer>
Heading Accessibility
- 7 heading levels: <div role="heading" aria-level="7"></div>
- One <h1>per page
Navigation Accessibility
- Have a HTML sitemap.
- Support keyboard navigation (Key and Tab Index).
- Breadcrumbs a11y:- aria-label="breadcrumbs"
- aria-label="page"
 
<nav aria-label="breadcrumbs">
  <ol>
    <li>
      <a href="https://example.com/"> Home </a>
    </li>
    <li>
      <a href="https://example.com/products"> Products </a>
    </li>
    <li>
      <a href="https://example.com/products/childrens-clothing">
        Children's clothing
      </a>
    </li>
    <li>
      <a
        href="https://example.com/products/childrens-clothing/shoes"
        aria-current="page"
      >
        Shoes
      </a>
    </li>
  </ol>
</nav>
Section Accessibility
<section aria-labelledby="sectionHeader1">
  <h2 id="sectionHeader1">A great section</h2>
</section>
<section aria-labelledby="sectionHeader2">
  <h2 id="sectionHeader2">An even better section</h2>
</section>
Article Accessibility
The <article> element is used to represent a fully self-contained region of content
<article>
  <header>
    <h1>Why you should buy more cheeses than you currently do</h1>
  </header>
  <section>
    <header>
      <h2>Part 1: Variety is spicy</h2>
    </header>
    <!-- cheesy content -->
  </section>
  <section>
    <header>
      <h2>Part 2: Cows are great</h2>
    </header>
    <!-- more cheesy content -->
  </section>
</article>
Reference Accessibility
- <cite>
- <q>
- <blockquote>
- <code>
<p>
  Every time Kenny is killed, Stan will announce
  <q cite="http://en.wikipedia.org/wiki/Kenny_McCormick#Cultural_impact">
    Oh my God, you/they killed Kenny! </q
  >.
</p>
<blockquote cite="https://www.huxley.net/bnw/four.html">
  <p>
    Words can be like X-rays, if you use them properly – they'll go through
    anything. You read and you're pierced.
  </p>
</blockquote>
<cite>– Ados Huxley, Brave New World</cite>
Link Accessibility
<article>
  <h2 id="article1-title">My article</h2>
  <p>Article brief description with truncation...</p>
  <a href="article1-url" aria-labelledby="article1-title">Read more</a>
</article>
Text Accessibility
- <b>
- <strong>
- <mark>
- <ins>
- <del>
- <abbr>: 专有名词解释- <abbr title="HyperText Markup Language">HTML</abbr>
不要将 <b> 元素与 <strong>、<em> 或 <mark> 元素混淆:
- <strong>元素表示某些重要性的文本
- <em>强调文本
- <mark>元素表示某些相关性的文本
Text Color A11Y
- Devtool inspect elements A11Y for color contrast ratio.
- Don't forget ::selection.
Text Spacing A11Y
- line-heightof blocks of text should be 1.5.
- space between paragraphs should be 1.5 times the line-height(so a minimum of2.25 rem).
- Line height (line spacing) to at least 1.5 times the font size.
- Spacing following paragraphs to at least 2 times the font size.
- Letter spacing (tracking) to at least 0.12 times the font size.
- Word spacing to at least 0.16 times the font size.
Button Accessibility
Use <button> for clickable elements
Image Accessibility
- alt=""
SVG Accessibility
- <title>
- <desc>
<svg width="100" height="75">
  <title>Dark rectangle</title>
  <desc>A grey rectangle with rounded corners and a dark green border</desc>
  <rect
    width="75"
    height="50"
    rx="20"
    ry="20"
    fill="#666"
    stroke="#229b23"
    stroke-fill="1"
  />
</svg>
Figure Accessibility
<figure aria-labelledby="image-alt">
  <img src="" alt="" />
  <br />
  <figcaption id="image-alt"></figcaption>
</figure>
Audio Source Accessibility
- src=""
- type=""
Form Accessibility
Group Related Fields
With fieldset and legend:
<form role="form">
  <fieldset>
    <legend>Choose one of these three items:</legend>
    <input id="one" type="radio" name="items" value="one" />
    <label for="one">Choice One</label><br />
    <input id="two" type="radio" name="items" value="two" />
    <label for="two">Choice Two</label><br />
    <input id="three" type="radio" name="items" value="three" />
    <label for="three">Choice Three</label>
  </fieldset>
</form>
Input Accessibility
- label[for]input.
- aria-labeland- aria-describedbyfor input hint.
- aria-invalidfor error input.
- aria-hiddenfor hidden input.
<form role="form">
  <label for="name">Name:</label>
  <input id="name" name="name" type="text" />
</form>
<form role="form">
  <label for="name">Name:</label>
  <span class="prefix-input">
    <span class="prefix-icon" id="name-icon" aria-label="Input Prefix Icon">
      <icon />
    </span>
    <input id="name" name="name" type="text" aria-describedby="name-icon" />
  </span>
</form>
<form role="form">
  <label for="email-address"> Your Email Address </label>
  <span id="email-error">
    Error: Your email address must contain an @ symbol
  </span>
  <input
    id="email-address"
    name="email-address"
    type="email"
    aria-describedby="email-error"
    aria-invalid="true"
  />
</form>
const Field = () => (
  <>
    <div className="user-code-field">
      <input
        id="userCode"
        aria-describedby={
          errors.userCode ? 'user-code-error' : 'user-code-help'
        }
      />
      <span id="user-code-help" className="user-code-help">
        Enter your 4 digit user code
      </span>
    </div>
    {errors.userCode && (
      <div id="user-code-error" role="alert" className="error">
        You must enter your 4 character user code
      </div>
    )}
  </>
);
Time Accessibility
<time datetime="2016-09-15">Thursday, September 15<sup>th</sup></time>
Address Accessibility
<footer>
  <section class="contact" vocab="http://schema.org/" typeof="LocalBusiness">
    <h2>Contact us!</h2>
    <address property="email">
      <a href="mailto:us@example.com">us@example.com</a>
    </address>
    <address property="address" typeof="PostalAddress">
      <p property="streetAddress">123 Main St., Suite 404</p>
      <p>
        <span property="addressLocality">Your Town</span>,
        <span property="addressRegion">AK</span>,
        <span property="postalCode">12345</span>
      </p>
      <p property="addressCountry">United States of America</p>
    </address>
  </section>
</footer>
Color Contrast
- more than 4.5:1 ratio
Keys and Tabindex Accessibility
<a id="second" href="" accesskey="c"></a>
document.addEventListener('keyup', event => {
  switch (event.keyCode) {
    // escape
    case 27:
      // exit
      break;
    // enter || space bar
    case 13 || 32:
      // submit or something
      break;
    // left arrow
    case 37:
      // move back / previous
      break;
    // right arrow
    case 39:
      // move forward
      break;
    // up arrow
    case 38:
      // move up
      break;
    // down arrow
    case 40:
      // move down
      break;
    default:
      throw new Error('Unsupported key!');
  }
});
/**
 * Traps the tab key inside of the context, so the user can't accidentally get
 * stuck behind it.
 *
 * Note that this does not work for VoiceOver users who are navigating with
 * the VoiceOver commands, only for default tab actions. We would need to
 * implement something like the inert attribute for that (see https://github.com/WICG/inert)
 * @param  {object} e the Event object
 */
export function trapTabKey(e, context) {
  if (e.key !== 'Tab') return;
  const focusableItems = getFocusable(context);
  const focusedItem = document.activeElement;
  const focusedItemIndex = focusableItems.indexOf(focusedItem);
  if (e.shiftKey) {
    if (focusedItemIndex === 0) {
      focusableItems[focusableItems.length - 1].focus();
      e.preventDefault();
    }
  } else {
    if (focusedItemIndex === focusableItems.length - 1) {
      focusableItems[0].focus();
      e.preventDefault();
    }
  }
}
ARIA
Web Accessibility Initiative - Accessible Rich Internet Applications:
- aria-label.
- aria-labelledby="dropdownMenuButton": dropdown/form>.
- aria-describedBy: input + small.
<label id="l1" for="f3">label text</label>
<input type="text" id="f3" aria-labelledby="l1 l2" />
<p>other content</p>
<span tabindex="-1" id="l2">more label text</span>
<div aria-describedby="test">text</div>
<div id="test" role="tooltip">tooltip text</div>
<div role="dialog" aria-label="login" aria-describedby="log1">
  <div id="log1" tabindex="-1">Provide user name and password to login.</div>
</div>
- aria-disabled="true": disable element.
- aria-hidden="true".
- aria-controls="navbarSupportedContent": navigation/select.
- aria-expanded="false": dropdown.
- aria-haspopup="true": dropdown/popup.
- aria-current="pages: breadcrumb.
- aria-valuenow/- aria-valuemin/- aria-valuemax: progress.
- role.- <header>:- role="banner".
- <nav>:- role="navigation".
- <main>:- role="main".
- <section>:- role="region".
- <article>:- role="article".
- <aside>:- role="complementary".
- <footer>:- role="contentinfo".
- <form>:- role="form".
- 7th heading level: <div role="heading" aria-level="7"></div>.
- role="button".
- role="checkbox".
- role="gridcell".
- role="link".
- role="menuitem".
- role="menuitemcheckbox".
- role="menuitemradio".
- role="option".
- role="progressbar".
- role="radio".
- role="scrollbar".
- role="searchbox".
- role="separator (when focusable)".
- role="slider".
- role="spinbutton".
- role="switch".
- role="tab".
- role="tabpanel".
- role="textbox".
- role="tooltip".
- role="treeitem".
- role="presentation": removes the semantics of an element. If set an interactive or focusable element to- role="presentation", assistive technology user will not know what it is or how to use it.
- role="application".
 
<button
  class="list-expander"
  aria-expanded="false"
  aria-controls="expandable-list-1"
>
  Expand List
</button>
<ul id="expandable-list-1">
  <li><a href="http://example.com">Sample Link</a></li>
  <li><a href="http://example.com">Sample Link 2</a></li>
  <li><a href="http://example.com">Sample Link 3</a></li>
</ul>
const listExpander = document.querySelector('.list-expander');
const list = document.querySelector('#expandable-list-1');
listExpander.addEventListener('click', e => {
  if (list.getAttribute('aria-expanded') === 'true') {
    list.setAttribute('aria-expanded', 'false');
  } else {
    list.setAttribute('aria-expanded', 'true');
  }
});
HTML First over ARIA
<!--div role="banner"-->
<header></header>
<!--div role="navigation"-->
<nav></nav>
<!--div role="main"-->
<main></main>
<!--div role="region"-->
<section [accessible name]></section>
<!--div role="complementary"-->
<aside></aside>
<!--div role="contentinfo"-->
<footer></footer>
<!--div role="form"-->
<form></form>
<div role="search"></div>
Accessibility Best Practice
A11y audit list:
- Don't use aria-hiddenon the<body>element.
- Complete meta header:- Add missing languages.
- Make sure documenthas atitleelement.
- Tool: react-helmet.
 
- Fix low text contrast: 确保文本与其背景保持足够的对比.
- 不要将颜色作为传达信息的唯一手段 (色盲/弱).
- Add missing alternative text.
- Remove empty links and buttons.
- 注意表单:- Add missing labels.
- 提供输入焦点的视觉提示.
 
- 避免组件识别障碍.
- Make sure IDsandKeysof elements are unique.
- Required context role.
- Required aria attribute.
- Valid aria attribute.
Accessibility Checklist
- W3C ARIA Usage Rule
- WebAIM WCAG (Web Content Accessibility Guidelines) 2 Checklist
- A11Y Project
- A11Y 101