使用CSS媒体查询(Media Queries)和JavaScript判断浏览器设备类型的方法


Posted in HTML / CSS onApril 03, 2014

有无数的理由要求我们在任何时候都应该知道用户是使用的什么设备浏览我们的网站——宽屏,普通屏,平板,手机?知道这些特征,我们web应用的CSS和JavaScript才能同步做相应的操作。在给Mozilla Developer Networks改版设计的过程中,我发现使用CSS媒体查询(media queries)虽然非常的有效,但有时,JavaScript却不能及时知道用户浏览设备的状态。浏览网站的用户使用的是桌面电脑,还是平板,还是手机?这对于CSS来说很容易,但CSS却无法将这些信息告诉JavaScript。我发明了一种基于CSS媒体查询和z-index属性的方法,能告诉JavaScript用户当前使用的是什么屏幕,这样我能调整JavaScript的动作来响应这种屏幕尺寸。

CSS代码

首先最重要的还是CSS媒体查询代码。这里只是示例,我们创建了三个媒体查询规则(但不包括缺省的“all”),它能控制四种屏幕情况:桌面(这是缺省状态,不需要媒体查询规则),“小屏幕”,平板,手机。针对每一种屏幕,我们给它一种不同的z-index值,这个值我们可以用JavaScript检测到。我们把这个元素定位到屏幕外,这样它就不会显示出来;记住,它的作用就是存放z-index值,我们要用javaScript获取这个值。

复制代码
代码如下:

/* 缺省屏幕 */
.state-indicator {
position: absolute;
top: -999em;
left: -999em;
z-index: 1;
}
/* 小屏幕 */
@media all and (max-width: 1200px) {
.state-indicator {
z-index: 2;
}
}
/* 平板 */
@media all and (max-width: 1024px) {
.state-indicator {
z-index: 3;
}
}
/* 手机 */
@media all and (max-width: 768px) {
.state-indicator {
z-index: 4;
}
}

每种z-index都在告诉我们的JavaScript当前的用户使用的是什么规格的屏幕。我们并不像知道用户究竟使用的是什么设备,因为你可以将浏览器宽度拉的很窄,但我们需要就是可视宽度,这样我们可以调整应用的布局。

JavaScript代码

也许你认为可以在DomContentLoaded时知道屏幕的大小,但我们需要实时知道屏幕的大小(因为用户会调整浏览器窗口的大小),我们需要有个方法获取当前窗口的属性:

复制代码
代码如下:

// 创建状态指示元素
var indicator = document.createElement('div');
indicator.className = 'state-indicator';
document.body.appendChild(indicator);
// 获取设备类别的方法
function getDeviceState() {
return parseInt(window.getComputedStyle(indicator).getPropertyValue('z-index'), 10);
}

使用这个方法,你就能检测出页面布局/js饰件中那些需要显示,那些需要隐藏。
复制代码
代码如下:

if(getDeviceState() < 3) { // 如果是桌面电脑后小屏幕电脑
// 显示js饰件....
}

有人也许会认为这些数字太容易搞错,让代码很难维护。其实我们可以用一个对象来处理这种事情:
复制代码
代码如下:
function getDeviceState() {
var index = parseInt(window.getComputedStyle(indicator).getPropertyValue('z-index'), 10);
var states = {
2: 'small-desktop',
3: 'tablet',
4: 'phone'
};
return states[index] || 'desktop';
}

这样,你就一个写出更具可读性的逻辑判断:
复制代码
代码如下:
if(getDeviceState() == 'tablet') {
// Do whatever
}

也许使用CSS的伪元素的content属性是个更好的方法:
复制代码
代码如下:

.state-indicator {
position: absolute;
top: -999em;
left: -999em;
}
.state-indicator:before { content: 'desktop'; }
/* 小屏幕桌面 */
@media all and (max-width: 1200px) {
.state-indicator:before { content: 'small-desktop'; }
}
/* 平板 */
@media all and (max-width: 1024px) {
.state-indicator:before { content: 'tablet'; }
}
/* 手机 */
@media all and (max-width: 768px) {
.state-indicator:before { content: 'mobile'; }
}

用下面的JavaScript方法获取关键的内容:
复制代码
代码如下:
var state = window.getComputedStyle(
document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')

如何组织这些代码全看你自己了。如果你有一个全局对象,例如window.config或window.app等,你可以把这些方法放到里面。我倾向于模块化这些功能,你可以把它做成jQuery插件或JavaScript工具包。不管你如何实现,它们都是你可以信赖的、简单易用的检测用户设备的好方法。

更上一层楼

我们知道屏幕尺寸会发生变化——用户手工调整浏览器大型或手机用户调整了手机方向,所以,当这些事件发生时,我们需要让系统告诉我们。下面这段简单的代码估计是你需要的:

复制代码
代码如下:
var lastDeviceState = getDeviceState();
window.addEventListener('resize', debounce(function() {
var state = getDeviceState();
if(state != lastDeviceState) {
// 保持当前的状态
lastDeviceState = state;
// 宣告状态变化,通过自定义的DOM事件或JS 消息发布/订阅模式,
// 我喜欢后者,所有就假设使用了一个这样的工具库
publish('/device-state/change', [state]);
}
}, 20));
// 用法
subscribe('/device-state/change', function(state) {
if(state == 3) {
// or "tablet", if you used the object
}
});

注意,这里我使用了debounce方法来执行resize事件发生时的动作——这对于性能来说非常重要。是使用自定义DOM事件还是使用发布/订阅模式,你自由选择,因为都很简单。

我觉得这种方法非常的好。有人可能会指出使用matchMedia也可以有相同效果,但问题是你需要在CSS里和JavaScript里都使用媒体查询,而有些媒体查询语句可能会很复杂,甚至会成为你的噩梦,不如使用简单的z-index。也有人会说可以使用 window.innerWidth来判断,但这样JS里获取的属性和CSS里的媒体查询就需要相互转换了,同样也会成为你的恶魔。我的方法的好处就在于你可以用它判断其他类型的媒体查询属性,例如检查手机是横向(landscape)还是竖向(portrait)。

不管怎样,你可以试一下,告诉我你的感觉!

HTML / CSS 相关文章推荐
可自定义箭头样式的CSS3气泡提示框
Mar 16 HTML / CSS
html5 sessionStorage会话存储_动力节点Java学院整理
Jul 06 HTML / CSS
html5 input元素新特性_动力节点Java学院整理
Jul 06 HTML / CSS
html5 canvas绘制放射性渐变色效果
Jan 04 HTML / CSS
浅谈cookie和localStorage那些事
Aug 27 HTML / CSS
HTML5 Web Database 数据库的SQL语句的使用方法
Dec 09 HTML / CSS
深入解析HTML5使用SVG图像时的viewBox属性用法
Sep 02 HTML / CSS
详解HTML5之pushstate、popstate操作history,无刷新改变当前url
Mar 15 HTML / CSS
HTML5 移动页面自适应手机屏幕四类方法总结
Aug 17 HTML / CSS
html svg生成环形进度条的实现方法
Sep 23 HTML / CSS
div或img图片高度随宽度自适应的方法
Feb 06 HTML / CSS
CSS完成视差滚动效果
Apr 27 HTML / CSS
css3实现input输入框颜色渐变发光效果代码
Apr 02 #HTML / CSS
CSS去掉A标签(链接)虚线框的方法
Apr 01 #HTML / CSS
使用css3背景渐变中的透明度来设置不同颜色的背景渐变
Mar 31 #HTML / CSS
你应该知道的30个css选择器
Mar 19 #HTML / CSS
纯CSS3打造动感漂亮时尚的扇形菜单
Mar 18 #HTML / CSS
CSS3中background-clip和background-origin的区别示例介绍
Mar 10 #HTML / CSS
CSS3中:nth-child和:nth-of-type的区别深入理解
Mar 10 #HTML / CSS
You might like
PHP在字符串中查找指定字符串并删除的代码
2008/10/02 PHP
判断php数组是否为索引数组的实现方法
2013/06/13 PHP
针对thinkPHP5框架存储过程bug重写的存储过程扩展类完整实例
2018/06/16 PHP
Ubuntu中支持PHP5与PHP7双版本的简单实现
2018/08/19 PHP
PHP实现的策略模式示例
2019/03/20 PHP
Firefox+FireBug使JQuery的学习更加轻松愉快
2010/01/01 Javascript
js实现的仿新浪微博完美的时间组件升级版
2011/12/20 Javascript
HTML长文本截取含有HTML代码同样适用的两种方法
2013/07/31 Javascript
jquery ajax jsonp跨域调用实例代码
2013/12/11 Javascript
3种Jquery限制文本框只能输入数字字母的方法
2014/12/03 Javascript
JS实现简单的二维矩阵乘积运算
2016/01/26 Javascript
Jquery实现遮罩层的简单实例(就是弹出DIV周围都灰色不能操作)
2016/07/14 Javascript
jQuery flip插件实现的翻牌效果示例【附demo源码下载】
2016/09/20 Javascript
AngularJS 在同一个界面启动多个ng-app应用模块详解
2016/12/20 Javascript
Vue.js组件tab实现选项卡切换
2020/03/23 Javascript
vue用addRoutes实现动态路由的示例
2017/09/15 Javascript
基于vue.js无缝滚动效果
2018/01/25 Javascript
JavaScript实现的前端AES加密解密功能【基于CryptoJS】
2018/08/28 Javascript
npm scripts 使用指南详解
2018/10/08 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
nodejs使用node-xlsx生成excel的方法示例
2019/08/22 NodeJs
vue父子组件间引用之$parent、$children
2020/05/20 Javascript
javascript canvas封装动态时钟
2020/09/30 Javascript
JavaScript用document.write()输出换行的示例代码
2020/11/26 Javascript
[01:00:59]VP VS VG Supermajor小组赛胜者组第二轮 BO3第二场 6.2
2018/06/03 DOTA
python实现网页链接提取的方法分享
2014/02/25 Python
Python中read()、readline()和readlines()三者间的区别和用法
2017/07/30 Python
python binascii 进制转换实例
2019/06/12 Python
Python通过format函数格式化显示值
2020/10/17 Python
怀旧收藏品和经典纪念品:Betty’s Attic
2018/08/29 全球购物
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
生产现场禁烟通知
2015/04/23 职场文书
幼师必备:幼儿园期末教师评语50条
2019/11/01 职场文书
Python中os模块的简单使用及重命名操作
2021/04/17 Python
Java实现房屋出租系统详解
2021/10/05 Java/Android
详解redis在微服务领域的贡献
2021/10/16 Redis