CSS :focus伪类和JS focus事件提高网站键盘可访问性
2017-04-27 12:42
1006 查看
键盘访问网站的常用操作包括:
Tab键索引控件元素;Enter键触发当前处于focus状态的点击行为;
上下键上下滚动网页;
Space空白键滚动一屏网页;
Home键返回顶部;
End键滚动到底部;
一般的操作行为是这样的,先Tab键按次序不断focus控件元素,包括
链接,按钮,输入框等表单元素或者focus设置了tabindex的普通元素,处于focus状态元素,浏览器一般会通过虚框或者外发光的形式进行区分和提示,此时我们在按下Enter回车键,就相当于鼠标点击了这个元素,从而可以前往我们想去的目的地,或者执行我们想要的交互效果。
而focus状态元素的标记默认全部都是使用outline属性
我们只要平时注意HTML语义化,例如按钮不要使用,
等标签,不要重置outline,基本上键盘可访问性就已经及格了。
一、label标签和表单元素之间的键盘可访问性
对于表单元素,如果里面有type为submit类型的按钮,则浏览器天然支持单行输入框的回车提交行为。然而原生的按钮有一个问题,那就是UI样式控制存在兼容性差异,尤其是桌面端网页项目。
可以借助<label>元素实现按钮样式的移花接木。
:focus伪类和outline都是IE8浏览器开始支持的。
html:
<form> <p>用户名:<input></p> <p> <input id="t" type="submit"> <label class="btn" for="t">提交</label> </p> </form>
css:
[type="submit"] { position: absolute; clip: rect(0 0 0 0); } .btn { display: inline-block; padding: 2px 12px; background-color: #cd0000; color: #fff; font-size: 14px; cursor: pointer; } :focus + label.btn { outline: 1px solid Highlight; outline: 5px auto -webkit-focus-ring-color; }
二、CSS hover显示隐藏内容的键盘可访问性
我列表元素信息很多,为了防止视觉干扰,一些操作按钮在鼠标hover当前列表的时候才显示很多小伙伴在实现的时候,并没有考虑很多,就直接使用display:none隐藏,或者visibility:hidden隐藏,于是会导致隐藏的控件元素压根没法通过键盘让其显示,因为这两种隐藏方式会让元素无法被focus,那该怎么办呢?可以试试使用透明度opacity控制内容的显隐,于是,我们就可以通过:focus伪类让按钮focus时候可见,
html:
<table width="300px" border="1"> <tr> <td>栏目1</td> <td>栏目2</td> <td> <a href="https://www.baidu.com" class="btn1">删除</a> </td> </tr> <tr> <td>栏目1</td> <td>栏目2</td> <td> <a href="javascript:;" class="btn1">删除</a> </td> </tr> <tr> <td>栏目1</td> <td>栏目2</td> <td> <a href="javascript:;" class="btn1">删除</a> </td> </tr> </table>
css:
table { border-spacing: 0; } .btn1 { display: inline-block; padding: 2px 12px; background-color: #cd0000; color: #fff; font-size: 14px; cursor: pointer; } tr .btn1 { opacity: 0; filter: alpha(opacity=0); } tr:hover .btn1, tr .btn1:focus { opacity: 1; filter: none; }
三、CSS hover显示下拉内容的键盘可访问性
首先一定要有键盘可访问的触发源,也就是无论是点击区还是hover区域,一定要有个<a>标签,或者原生按钮,或者设置了tabindex的普通元素。
把交互形式和实现原理,分为下面四类:
列表HTML结构依赖,使用CSS定位,hover显示;
列表HTML结构依赖,使用CSS定位,click显示;
列表HTML结构不依赖,使用JS定位,hover显示;
列表HTML结构不依赖,使用JS定位,click显示;
例如,导航上的二级菜单常使用CSS进行定位,对HTML结构有要求;而搜索的自动下拉提示列表则几乎都使用JS进行定位,列表直接创建于标签下,对HTML结构无依赖。
针对上面四种情况,我需要额外进行的处理分别是:
增加:focus控制;
无需额外处理;
增加JS focus事件处理,处理细节同mouseenter;
无需额外处理;
这些浮层显示的时候,通过上下左右键进行控制
html:
<div class="trigger-container"> <a href="javascript:;" class="trigger" data-target="list">更多操作▾</a> <div class="list" id="list"> <a href="https://www.baidu.com">编辑</a> <a href="javascript:;">删除</a> </div> </div> <div class="trigger-container"> <a href="javascript:;" class="trigger" data-target="list1">更多操作▾</a> <div class="list" id="list1"> <a href="javascript:;">编辑</a> <a href="javascript:;">删除</a> </div> </div>
css:
.trigger-container { float: left; } .list { position: absolute; visibility: hidden; } .trigger:hover + .list, .trigger:focus + .list { visibility: visible; } .outline { outline: 1px solid Highlight; outline: 5px auto -webkit-focus-ring-color; }
js:
(function (doc) { if (doc.addEventListener) { var keycode = { 37: 'left', 38: 'up', 39: 'right', 40: 'down', 13: 'enter', 9: 'tab' }; // 键盘高亮类名 var className = 'outline'; // 高亮类名的添加与删除 var classList = { add: function (ele) { ele.className = ele.className + ' ' + className; }, remove: function (ele) { ele.className = ele.className.split(/\s+/).filter(function (cl) { if (cl != className) { return cl; } }).join(' '); }, removeAll: function () { [].slice.call(doc.querySelectorAll('.' + className)).forEach(function (ele) { classList.remove(ele); }); }, has: function (ele) { return ele.className.split(/\s+/).filter(function (cl) { if (cl == className) { return cl; } }).length > 0; } }; //键盘事件 doc.addEventListener('keydown', function (event) { // 是否是上下左右键 var direction = keycode[event.keyCode]; if (!direction) { return; } if (direction == 'tab') { classList.removeAll(); return; } // 当前激活元素 var trigger = doc.activeElement; if (!trigger) { return; } // 对应的面板 var attrTarget = trigger.getAttribute('target') || trigger.getAttribute('data-target'); var target = attrTarget && doc.getElementById(attrTarget); if (!target) { return; } // 需要是显示状态 if (target.clientWidth == 0 && target.clientHeight == 0) { return; } // 如果是回车事件 if (direction == 'enter') { var eleFocus = target.querySelector('.' + className); if (eleFocus) { // 阻止默认的回车 event.preventDefault(); eleFocus.click(); return; } } // 如果都符合,同时有目标子元素 var arrEleFocusable = target.storeFocusableEle, index = target.storeIndexFocus; if (!arrEleFocusable) { arrEleFocusable = [].slice.call(target.querySelectorAll('a[href], button:not(:disabled), input:not(:disabled)')); target.storeFocusableEle = arrEleFocusable; target.storeIndexFocus = -1; index = -1; } if (arrEleFocusable.length == 0) { return; } // 先全部清除focus态 arrEleFocusable.forEach(function (ele) { classList.remove(ele); }); // 阻止默认的上下键滚屏 event.preventDefault(); // 索引加加减减 if (direction == 'left' || direction == 'up') { index--; if (index < 0) { index = -1; } } else if (direction == 'right' || direction == 'down') { index++; if (index > arrEleFocusable.length - 1) { index = arrEleFocusable.length; } } // 如果有对应的索引元素 if (arrEleFocusable[index]) { // 高亮对应的控件元素 classList.add(arrEleFocusable[index]); } // 记录索引 target.storeIndexFocus = index; }); doc.addEventListener('mousedown', function (event) { var target = event.target; if (target && !classList.has(target)) { classList.removeAll(); } }); } })(document);
相关文章推荐
- 如何提高网站的访问速度 - 从30秒到3秒的改变
- 如何提高网站访问速度的文章
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践
- 【收集】如何提高网站访问速度的文章
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践
- 如何提高网站的访问速度 - 从30秒到3秒的改变
- 【译】提高网站访问速度的34条军规(1-3)
- 提高网站程序性能的十条建议--主要针对javascript文件和css文件
- 优化网站性能 提高网站速度访问速度的14条实践(原文:http://www.phpv.net/html/1660.html)
- 采用伪静态页面技术提高网站的访问速度
- 提高网站访问速度的六个方法!
- 【译】提高网站访问速度的34条军规(7-10)
- 优化网站性能 提高网站速度访问速度的14条实践
- 优化网站性能 提高网站速度访问速度的14条实践