本文详解移动端检测横竖屏的多种实现方式。首先分析CSS3 Media在部分安卓设备上的局限性,引出iOS特有的orientationchange事件及window.orientation属性。接着介绍纯CSS的Media Queries写法,最后针对不支持上述特性的设备,提供基于resize和innerWidth/innerHeight的兼容方案,并给出综合代码示例。
CSS Media查询在移动端的局限性
使用CSS3的media查询来判断屏幕宽度时,可能会遇到兼容性问题。
在iOS设备上,旋转屏幕时样式能正常切换;但在部分安卓设备上却无反应,横屏时仍显示竖屏样式。
查阅相关资料发现,若要在移动端获得较好的CSS3 Media显示效果,需在页面头部添加特定的viewport设置。
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
然而,这段代码无法使用,因为我的页面已经实现了自适应适配,可根据屏幕大小动态调整字号和样式。若添加该viewport代码,将破坏现有的自适应逻辑,因此需要寻找其他替代方案。
针对上述问题,以下是具体的解决思路。
利用orientationchange事件检测
移动端设备提供了一个专门的事件:orientationchange事件。
该事件由苹果公司为Safari浏览器引入,旨在帮助开发人员判断用户何时将设备从横向查看模式切换为纵向查看模式。
当设备发生旋转时,会触发此事件。
// Listen for orientation changes
window.addEventListener("orientationchange", function() {
// Announce the new orientation number
alert(window.orientation);
}, false);
只要用户改变了设备的查看模式,就会触发orientationchange事件。需要注意的是,此时的event对象本身不包含有价值的信息。
获取旋转状态的关键信息,需通过访问window.orientation属性来实现。
关于orientation属性,
它主要包含三个数值:0、90和-90。
其中,0代表竖屏模式(portrait);-90表示设备向右旋转后的横屏模式(landscape);而90表示设备向左旋转后的横屏模式(landscape)。
此外还有一个值为180,表示竖屏但屏幕翻转180度的模式。不过,这种模式至今尚未得到广泛支持。
如图所示:

因此,结合orientationchange事件和window.orientation属性,我们可以较为准确地判断设备当前是处于横屏还是竖屏状态。
(function(){
var init = function(){
var updateOrientation = function(){
var orientation = window.orientation;
switch(orientation){
case 90:
case -90:
orientation = 'landscape'; //这里是横屏
break;
default:
orientation = 'portrait'; //这里是竖屏
break;
}
//html根据不同的旋转状态,加上不同的class,横屏加上landscape,竖屏
//加上portrait
document.body.parentNode.setAttribute('class',orientation);
};
// 每次旋转,调用这个事件。
window.addEventListener('orientationchange',updateOrientation,false);
// 事件的初始化
updateOrientation();
};
window.addEventListener('DOMContentLoaded',init,false);
})();
基于不同的旋转状态,我们可以为HTML元素添加相应的class,从而在CSS中编写对应的样式规则。
/**竖屏 body显示红色**/
.portrait body div{
background: red;
}
/**横屏 body显示蓝色**/
.landscape body div{
background: blue;
}
纯CSS Media Queries方案
另一种写法是,借助CSS的media queries。
@media all and (orientation: portrait) {
body div {background: red;}
}
@media all and (orientation: landscape) {
body div {background: blue; }
}
这种orientation media query在iOS 3.2及以上版本、Android 2.0及以上版本以及其他浏览器中均有效。
相比之下,这种代码更加简洁。与前述的JS结合CSS方案不同,这是纯CSS实现。当设备旋转时,浏览器会根据设备方向自动调用对应的CSS样式。
兼容旧设备的resize事件方案
接下来讨论兼容性问题。
部分设备并未提供orientationchange事件,且不触发窗口的resize事件。此外,若media queries也不支持,我们该如何处理?
此时可以使用resize事件进行判断。通过获取innerWidth和innerHeight来检索屏幕尺寸,依据宽和高的大小进行比较:若宽小于高,则为竖屏;若宽大于高,则为横屏。
具体代码如下:
(function(){
var updateOrientation = function(){
var orientation = (window.innerWidth > window.innerHeight) ? 'landscape' : 'portrait';
document.body.parentNode.setAttribute('class',orientation);
};
var init = function(){
updateOrientation();
//监听resize事件
window.addEventListener('resize',updateOrientation,false);
};
window.addEventListener('DOMContentLoaded',init,false);
})();
通过这种方式,我们便能在浏览器中观察到屏幕旋转带来的样式变化。
综合检测代码示例
将上述两种检测方法结合,完整的代码如下:
(function(){
var supportOrientation = (typeof window.orientation === 'number' &&
typeof window.onorientationchange === 'object');
var init = function(){
var htmlNode = document.body.parentNode,
orientation;
var updateOrientation = function(){
if(supportOrientation){
orientation = window.orientation;
switch(orientation){
case 90:
case -90:
orientation = 'landscape';
break;
default:
orientation = 'portrait';
break;
}
}else{
orientation = (window.innerWidth > window.innerHeight) ? 'landscape' : 'portrait';
}
htmlNode.setAttribute('class',orientation);
};
if(supportOrientation){
window.addEventListener('orientationchange',updateOrientation,false);
}else{
//监听resize事件
window.addEventListener('resize',updateOrientation,false);
}
updateOrientation();
};
window.addEventListener('DOMContentLoaded',init,false);
})();
利用这种方法,即可有效解决移动端设备横竖屏检测的困扰。