无障碍、HTML 小细节、焦点、a11y、Accessibility、框架选择javascript
无障碍开发仍是应该从 HTML
开始聊起,不管是盲人阅读器仍是浏览器等工具最核心的部分仍是在 HTML
,毕竟没了 CSS
只是不美观了,没了 JavaScript
只是少了交互和无限扩展的可能性。css
有的同窗会说了产品和老板拿着鞭子在后头赶马车哪里有时间写这些
。现实是这样的,可是在选择UI框架的时候能够选择 无障碍
作得好的来提高网站的友好度,有句话说得好 居庙堂之高则忧其民,处江湖之远则忧其君
,灵活变通下不影响生活体验岂不是美哉?html
HTML
标签元素中还有一种比较少人知道的分类方法:交互标签
和 非交互标签
,在无障碍开发中须要留意的即是这两者。交互标签
每每会和 焦点
一块儿出现,按下 tab
键选择页面上的 交互标签
这个时候交互标签会被 蓝色的 焦点
框覆盖,若是想反向选择可使用 shift + tab
。java
在掘金我的主页里按下 tab
键后,蓝色的焦点
框会从 logo 到 首页一个个连接遍历下来,在这个过程当中能够发现 连接
、按钮
、搜索框
都会产生焦点。细心的同窗若是打开控制台会还会发现,跳转的顺序和标签在 HTML 中出现的前后顺序
有关。git
运动觉障碍的用户,例如霍金大大就能够利用他的三个指头配合 tab
和 shift + tab
来浏览 掘金
并在掘金上作交互性的操做。除此以外键盘上的 方向键
也是移动和浏览页面必不可少的一部分,你可使用 上下键
来是的页面能够上下滚动,也能够在 select 标签
中选择选项。github
更多无障碍群体内容能够阅读 无障碍世界浏览器
正所谓 工欲善其事必先利其器
对于被 焦点
选中的元素,能够经过 document.activeElement
来获取。固然也可使用插件来完成,这里推荐谷歌浏览器的一款插件 accessibility developer tools
。bash
经过这个测试能够知道关于交互标签的情报
即是 连接
、按钮
、搜索框
是交互标签,下面用选择器来总结一下 交互标签
:微信
const tags = [
'a[href]', 'area[href]', 'audio[controls]', 'video[controls]',
'input:not([disabled])', 'select:not([disabled])',
'textarea:not([disabled])', 'button:not([disabled])',
'iframe', 'object', 'embed', '[contenteditable]',
'[tabindex="0"]',
];
const allTagsDOM = document.querySelectorAll(tags.join(','));
console.log(allTagsDOM);
复制代码
除了 交互标签
中提到的标签外都属于 非交互标签
,有些开发老司机可能会问:框架
非交互标签
变成 交互标签
怎么办?这里便须要一个很常常被忽略掉的标签 tabindex
:
<element tabindex="number">
复制代码
它根据 tabindex
从小到大来控制 tab
的跳动顺序,虽然能够控制整个页面的浏览顺序,可是最好只使用 0
来指定 tabindex
属性。在上面也提到过打开控制面板查看页面结构
会发现 tab
默认的跳转顺序
和 标签顺序
是一致的,若是破坏掉了这个顺序对于一些不兼容 tabindex
的盲人辅助工具、浏览器会形成没法兼容的状况。
从下面例子也能了解到 页面结构顺序
很是重要,若是屏幕阅读器
不支持 tabindex
时便会先读取footer
标签的中内容,对于盲人来讲可能会一头雾水不知道网站怎么使用:
<!-- 正常顺序 -->
<!--<header>header</header>-->
<!--<main>main</main>-->
<!--<footer>footer</footer>-->
<!-- tabindex 控制顺序 -->
<footer tabindex='3'>footer</footer>
<main tabindex='2'>main</main>
<header tabindex='1'>header</header>
复制代码
除此以外当使用 css 样式 float: right
改变页面渲染的排列顺序也可能会形成影响,对于习惯从右向左阅读的用户来讲会形成困惑找不到焦点的位置。
<style>
button { float: right; }
</style>
<button>1</button>
<button>2</button>
<button>3</button>
复制代码
当自定义元素时须要把元素默认的 焦点
功能模拟出来进行替换便可。在上文提到了 非互动标签
转换 互动标签
利用 tabindex
这个属性来完成,其实还有一个小技巧利用 tabindex=-1
设置标签后,对应的 DOM 节点将会拥有 focus()
方法,利用这一点能够配合 JavaScript
能够实现很是多的功能。
主要须要注意的是 tab键
、enter键
、方向键
、space键
的功能。
提到看不见的元素不少同窗可能会一头雾水,最多见的看不见标签即是隐藏的导航菜单栏
:
上面讲到的 交互标签
会按顺序被 tab
选中成为焦点,导航菜单中的元素是一个个的 a[href]
,当在使用 tab
浏览的时候焦点会被锁定在这个隐藏的菜单
之中。若是没有把鼠标悬浮在首页
上时,用户可能会产生困惑 焦点去哪里了
。
这个时候的解决方法即是使用 display:none
或者 visibility:hidden
来控制标签不在 tab
的选着范围中。二者区别是 display:none
会让元素在渲染树中消失,不占用任何空间,visibility:hidden
则保留元素占据的空间,也依旧在渲染树中。当须要的时候使用 display:block
和 visibility:visible
进行显示。
掘金的隐藏菜单作得挺好的,不会让焦点跳转到
隐藏菜单
,美中不足的是只能经过鼠标悬浮来显示菜单
,不能经过tab
和enter
进行选中操做。
经过点击菜单栏来进行页面的切换,可是你有思考过当切换完菜单,用户要浏览内容还得按多少下 tab
才能进入内容标签嘛?若是菜单栏有五六十个的状况是多么可怕,你还真别说没有 某东
和 某宝
的菜单项就有这么多:
不过当选中标签按下 enter
时,他们会直接打开新的页面算是减小了用户须要 tab
的次数,不过在新页面上仍是要从新点击屡次 tab
才能浏览内容。咱们能够利用 锚点
和 tabindex=-1
来帮助用户快速切换内容焦点:
<a class="super-skip" href="#content">快速进入内容</a>
<nav>
<a class="menu-items" data-page="home" href="/home">Home</a>
<a class="menu-items" data-page="post" href="/post">Post</a>
<a class="menu-items" data-page="user" href="/user">User</a>
</nav>
<main id="content" tabindex="-1">
主要内容
</main>
复制代码
这下用户按下 tab
即可以快速选择是否直接浏览内容
,可是这个 a 标签
会影响到页面的美观,能够利用 css
样式中的 position: absolute
和 :focus
来帮助隐藏 a 标签
功能保持不变codepan
.super-skip {
position: absolute;
top -40px;
left: 0;
z-index:100;
}
.super-skip:focus {
top: 0;
}
复制代码
在单页面浏览中用户会在 菜单
中选择 菜单项
,可是页面内容改变的却仍是要 tab
浏览完剩下的标签才能将 焦点
切换到 页面内容
,能够利用 tabindex=-1
和 focus()
来快速的将焦点
切换至页面内容 codepan:
<style> .page { display: none; } .active { display: block; } </style>
<nav>
<a class="menu-items" data-page="home" href="/home">Home</a>
<a class="menu-items" data-page="post" href="/post">Post</a>
<a class="menu-items" data-page="user" href="/user">User</a>
</nav>
<div class="home page active">
<h1 class="title" tabindex="-1">home</h1>
</div>
<div class="post page">
<h1 class="title" tabindex="-1">post</h1>
</div>
<div class="user page">
<h1 class="title" tabindex="-1">user</h1>
</div>
<script> const doms = document.querySelectorAll('.menu-items'); const items = Array.from(doms); function superSkip(e) { const page = e.target.getAttribute('data-page'); const oldPage = document.querySelector('.active'); const newPage = document.querySelector(`.${page}`); const newPageTitle = document.querySelector(`.${page} .title`); // 切换页面 oldPage.classList.remove('active'); newPage.classList.add('active'); // 设置焦点 newPageTitle.focus(); e.preventDefault(); } items.forEach(i => i.onclick = superSkip); </script>
复制代码
在使用弹出自定义 Alert
时,因为 Alert
的内容也在 dom 元素里,使用 tab
进行切换时会致使切换的焦点
没法落在 Alert
对话框中,这里推荐阅读 SweetAlert
的源码它的无障碍作得很是棒,重点阅读 getFocusableElements 和 restoreActiveElement 这两个函数。
主要的流程分为:
document.activeElement
记录当前的焦点元素
和页面 x
和 y
坐标。Alert
对话框中的 变成交互标签
上文中提到的 tags
。tag
的属性为 focus()
。tag
被点击时须要循环重置到第一个 tag
。Alert
则经过一开始记录的焦点元素
和页面 x
和 y
坐标进行恢复。在 Element UI 中的自定义元素都作得不错,就是对于视障用户 焦点focus
的颜色区分度不够,就连小二本身都看不清已选择的元素时被focus
在哪里,不过能够经过修改 is-focus
来修改样式颜色:
tab
和 space
都有实现。tab
和 space
都有实现。tab
和 enter
都有实现。tab
和 enter
、方向键
都有实现。Material UI
在无障碍上就作得很是好,而在 Ant Design 无障碍相关的 交互元素
就作得不怎么好了,若是产品目标群体中有须要 无障碍
相关的服务,在选择框架时能够试试其中的 交互元素
作得如何,毕竟站在巨人的肩膀上比本身造轮子快又好
。
在困惑的城市里总少不了并肩同行的
伙伴
让咱们一块儿成长。
点赞
。小星星
。m353839115
。本文原稿来自 PushMeTop