js 弹出菜单/窗口效果


Posted in Javascript onOctober 30, 2011

是不是应该为弹出菜单提供更好的可访问支持?这篇文章将涉及到3种常见的弹窗:

window.open 新建的浏览器窗口
<iframe /> 创建的窗口
页面 DOM 创建的伪弹出窗口:如弹出 tips 等

一、当页面无 JS 的时候
通常来说,无 JS 的情况那就按 HTML 的行为来做事。让链接可以链接,就已经解决。比较简单,我们简单带过:

1. window.open 新建的浏览器窗口:尽量让 JS 触发器绑定在 <a /> 上,并把 a 链接到一个新的页面,即可。

// 链接与 window.open 的目标相同 
<a href="/target.html" target="_blank">[open window]</a> 
// 记得阻止链接有默认行为,不然有 JS 的时候会打开两次 
window.open('./iframe.html', 'name', 'height=300,width=500'); 
return false;

2. <iframe /> 创建的窗口:如果是用 JS 动态创建的,那么记得触发器也应该像 window.open 的方法一样,把解法链接写在一个 <a /> 上,让用户通过链接来访问。而如果是隐藏的,那么尽量来使用 <noscript /> 来隐藏,再用 JS 让其正常显示出来;或者高度为 0 的空 iframe 。这样即可保证在有 JS 的时候可用,而在无 JS 的时候可以正常显示。详细应用可以参照:支付宝新首页的几点前端实践。
// 动态创建,请尽量使用这种方法,因为 IE8 不能用 JS focus 到动态创建的 focusable 元素 
// 而空 src 则请使用 javascript:'' 这种方式,因为这是解决性能的最好方式,详见:空路径对页面性能影响的解决方案 <a href="/target.html" target="_blank">[open iframe]</a> 
<iframe src="javascript:''" frameborder=0 id="theframe"></iframe> 
// js 
document.getElementById('theframe').src = '/target.html'

3. 页面 DOM 创建的伪弹出窗口:使用 <noscript /> 来隐藏。链接用锚点。
<a href="#target">[open current page DOM]</a> 
... 很多很多东西隔在中间 ... 
<noscript><div id="target">content</div></noscript>

二、大多数情况下
大数多情况下,用户的浏览器都是有开启 JS 的。而我们要做的是:focus 到弹出的窗口,并且第一个 tab 就可以访问里面的内容。听过来挺简单的,hub? 先看看 DEMO:

预览:可访问弹出菜单/窗口

1. window.open 新建的浏览器窗口:focus 到新建的窗口即可。

// 引用自:QuickMode - popups 
function popitup(url) { 
newwindow=window.open(url,'name','height=200,width=150'); 
if (window.focus) { 
// focus 到新建窗口 
newwindow.focus(); 
} 
// 阻止触发器的默认行为 
return false; 
}

2. <iframe /> 创建的窗口:调试了好久,IE8/9 需要等 iframe onload 成功后 setTimeout 来 hack;firefox 不能使用 ifrcontentWindow.focus(),只能用 iframe.focus()。综合起来需要这样的代码:
// for all except firefox 
setTimeout(function(){ 
f.contentWindow.focus(); 
}, 50); // hack for firefox 
navigator.userAgent.toLowerCase().indexOf('firefox') !== -1 && f.focus();

3. 页面 DOM 创建的伪弹出窗口:对于 dom,除了 <a /> <input /> 等这些 focusable 元素(W3C SPEC),都是不可以 focus 的。那么当需要 focus 到一个 div 时,我们有什么方法可以做到呢?通常来说,我们可以设置 Tabindex 来让像 <div /> 这样的非 focusable 元素可以触发 focus 事件。但我们想要的时真正 focus 到一个地方,以便于使用 tab 来访问这个区域的内容,所以这种方法对我们等于无用。

目前还没有比较好的方法(对于我能想到的和找到的),所以目前来说,我们只能利用一个 focusable 元素来创建 focus 目标。我们可以这样做:

<a href="#" class="getfocus">Get focus</a>
<input title="testing" />
但问题是,对于这个链接对于我们来说是毫无作用的,我们需要隐藏他,又能 focus 到。但 display:none 的时候是不能 focus 的。对于隐藏 来说,这里也不想说太多。推荐看看这篇文章:使用clip隐藏内容。那么我们可以这样来 hack 我们的这个链接:

// html: 注意用 hidefocus 来删除虚线框 
<a href="#" class="getfocus" hidefocus>Get focus</a> // CSS: 使用 clip 
.getfocus{ 
position:relative; 
clip:rect(1px 1px 1px 1px); 
clip:rect(1px, 1px, 1px, 1px); 
} 
// javascript: 记得把 <a /> 放在这个 DOM 结构的最前面方便自上至下 tab 下去 
a.focus()

三、总结:
至此,重要的技术实现点也已经说明白。代码请见这个粗陋的 DEMO,虽然只是没有特别优化的一段代码,但相信可以解决很多问题。对于可访问性,我们要走的路还有很多。一点点来吧,从今天开始。
Javascript 相关文章推荐
Three.js源码阅读笔记(基础的核心Core对象)
Dec 27 Javascript
深入理解JavaScript系列(35):设计模式之迭代器模式详解
Mar 03 Javascript
javascript实现全角半角检测的方法
Jul 23 Javascript
如何使用jQuery技术开发ios风格的页面导航菜单
Jul 29 Javascript
ES6记录异步函数的执行时间详解
Aug 31 Javascript
jQuery-mobile事件监听与用法详解
Nov 23 Javascript
JS图片延迟加载插件LazyImgv1.0用法分析【附demo源码下载】
Sep 04 Javascript
Vue组件库发布到npm详解
Feb 17 Javascript
解决vue-router进行build无法正常显示路由页面的问题
Mar 06 Javascript
从零到一详聊创建Vue工程及遇到的常见问题
Apr 25 Javascript
vue实现评价星星功能
Jun 30 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
Dec 02 Vue.js
基于Jquery+Ajax+Json的高效分页实现代码
Oct 29 #Javascript
简单的前端js+ajax 购物车框架(入门篇)
Oct 29 #Javascript
分享一个自己写的table表格排序js插件(高效简洁)
Oct 29 #Javascript
Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
Oct 29 #Javascript
基于jQuery的输入框在光标位置插入内容, 并选中
Oct 29 #Javascript
基于jquery的无限级联下拉框js插件
Oct 29 #Javascript
对setInterval在火狐和chrome切换标签产生奇怪的效果之探索,与解决方案!
Oct 29 #Javascript
You might like
输入值/表单提交参数过滤有效防止sql注入的方法
2013/12/25 PHP
php项目中百度 UEditor 简单安装调试和调用
2015/07/15 PHP
js中if语句的几种优化代码写法
2011/03/12 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
NodeJS仿WebApi路由示例
2017/02/28 NodeJs
Agularjs妙用双向数据绑定实现手风琴效果
2017/05/26 Javascript
jQuery实现的简单手风琴效果示例
2018/08/29 jQuery
node之本地服务器图片上传的方法示例
2019/03/26 Javascript
node.js使用mongoose操作数据库实现购物车的增、删、改、查功能示例
2019/12/23 Javascript
vue学习之Vue-Router用法实例分析
2020/01/06 Javascript
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
介绍Python的@property装饰器的用法
2015/04/28 Python
简单讲解Python中的数字类型及基本的数学计算
2016/03/11 Python
Python操作Excel之xlsx文件
2017/03/24 Python
Python使用pip安装pySerial串口通讯模块
2018/04/20 Python
ubuntu系统下使用pm2设置nodejs开机自启动的方法
2018/05/12 NodeJs
为什么从Python 3.6开始字典有序并效率更高
2019/07/15 Python
pytorch中如何使用DataLoader对数据集进行批处理的方法
2019/08/06 Python
Python中的wordcloud库安装问题及解决方法
2020/05/27 Python
Python通过zookeeper实现分布式服务代码解析
2020/07/22 Python
用python绘制樱花树
2020/10/09 Python
香港通票:Hong Kong Pass
2019/02/26 全球购物
C面试题
2015/10/08 面试题
会计师事务所审计实习自我鉴定
2013/09/20 职场文书
班主任工作年限证明
2014/01/12 职场文书
我们的节日中秋活动方案
2014/08/19 职场文书
卫生厅领导班子党的群众路线教育实践活动整改措施
2014/09/20 职场文书
2015年教师节主持词
2015/07/03 职场文书
重阳节活动主持词
2015/07/04 职场文书
推广普通话的宣传语
2015/07/13 职场文书
二十年同学聚会致辞
2015/07/28 职场文书
2015年党务工作者个人工作总结
2015/10/22 职场文书
如何利用js在两个html窗口间通信
2021/04/27 Javascript
Spring Boot 启动、停止、重启、状态脚本
2021/06/26 Java/Android
提高系统的吞吐量解决数据库重复写入问题
2022/04/23 MySQL
Python查找算法的实现 (线性、二分,分块、插值查找算法)
2022/04/24 Python