在移动端经常会遇到根据横竖屏以不同的样式来适配或提醒用户切换为竖屏以保持良好的用户体验需求,这里结合JavaScript&CSS检测手机横竖屏
一文做一下总结:
CSS Media Queries检测手机横竖屏
通过媒体查询的方式,我们可以通过以下方法来实现根据横竖屏不同的情况来适配样式:
内联样式
@media screen and (orientation: portrait) {
/*竖屏...*/
}
@media screen and (orientation: landscape) {
/*横屏...*/
}
Orientation属性有两个值:
- portrait:指的是当height大于等于width的情况
- landscape:指的是当height小于width的情况
外联样式
<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="...">
<!-- 横屏 -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="...">
当点击输入框下方输入键盘弹起时,上面的css检测横屏可能会失效,不妨试试这个:
@media screen and (min-aspect-ratio: 13/9){ // landscape 横屏
.tips {
display:flex;
}
}
@media screen and (max-aspect-ratio: 13/9){ // portrait 竖屏
.tips{
display: none;
}
}
window.innerHeight/window.innerWidth
通过比较页面的宽高,当页面的高大于等于宽时则认为是竖屏,反之则为横屏。
function detectOrient(){
if(window.innerHeight >= window.innerWidth) {
// 竖屏
return;
}
// 横屏
}
detectOrient();
window.addEventListener('resize',detectOrient);
innerheight返回窗口的文档显示区的高度。innerwidth返回窗口的文档显示区的宽度。附送:PC端window.innerHeight、innerWidth浏览器兼容解决方法。
window.orientation
window.orientation 这个属性,它返回一个与默认屏幕方向偏离的角度值:
- 0:代表此时是默认屏幕方向
- 90:代表顺时针偏离默认屏幕方向90度
- -90:代表逆时针偏离默认屏幕方向90度
- 180:代表偏离默认屏幕方向180度
在 iOS 的开发者文档(iOS Developer Library - Handling Orientation Events)是这样明确定义的:
window.addEventListener("resize", ()=>{
if (window.orientation === 180 || window.orientation === 0) {
// 正常方向或屏幕旋转180度
console.log('竖屏');
};
if (window.orientation === 90 || window.orientation === -90 ){
// 屏幕顺时钟旋转90度或屏幕逆时针旋转90度
console.log('横屏');
}
});
window.matchMedia()
除此之外,CSS Object Model(CSSOM)Views 规范增加了对 JavaScript 操作 CSS Media Queries 的原生支持,它在 window 对象下增加了 matchMedia() 方法,让我们能够通过脚本的方式来实现媒体查询。
window.matchMedia() 方法接受一个 Media Queries 语句的字符串作为参数,返回一个 MediaQueryList 对象。该对象有 media 和 matches 两个属性:
- media:返回所查询的 Media Queries 语句字符串
- matches:返回一个布尔值,表示当前环境是否匹配查询语句
同时,它还包含了两个方法,用来监听事件:
- addListener(callback):绑定回调 callback 函数
- removeListener(callback):注销回调 callback 函数
那么,通过 window.matchMedia() 的方法,我们可以这样判断横竖屏:
var mql = window.matchMedia("(orientation: portrait)");
function onMatchMeidaChange(mql){
if(mql.matches) {
// 竖屏
}else {
// 横屏
}
}
onMatchMeidaChange(mql);
mql.addListener(onMatchMeidaChange);
通过Can I Use - matchMeida可以知道,该API在移动端得到良好的支持,并无兼容性问题。
移动端横竖屏最佳实践
如果页面中没有input元素唤出软键盘弹出的情况下,上面检测手机横竖屏方法都可以用。如果存在有input的元素时,页面有时会因为软键盘的弹出而导致页面回缩,即页面的宽度(竖屏时)或者高度(横屏时)被改变。以上几种方法好像变得并不可靠,在Android手机上在竖屏时由于软键盘弹出导致页面高度小于宽度,被错误地判定为横屏。参考探讨判断横竖屏的最佳实现一文中提到的方法:
<meta name="viewport" content="width=device-width">
HTML页面中添加上面一行代码,以保证在横竖屏切换的场景中document.documentElement.clientWidth/clientHeight必然与screen.width/height其中一值相等,这也是此方法的核心。
// 判断横竖屏
var utils = {
debounce: function(func,delay){
var timer = null;
return function(){
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},delay);
}
}
}
function detectOrient() {
var storage = localStorage; // 不一定要使用localStorage,其他存储数据的手段都可以
var data = storage.getItem('J-recordOrientX');
var cw = document.documentElement.clientWidth;
let _Width = 0;
let _Height = 0;
if(!data) {
let sw = window.screen.width;
let sh = window.screen.height;
// 2.在某些机型(如华为P9)下出现 srceen.width/height 值交换,所以进行大小值比较判断
_Width = sw < sh ? sw : sh;
_Height = sw >= sh ? sw : sh;
storage.setItem('J-recordOrientX',_Width + ',' + _Height);
}else {
var str = data.split(',');
_Width = +str[0];
_Height = +str[1];
}
console.log(cw,'jinbo',_Width);
if(cw == _Width) {
//竖屏
return;
}
if(cw == _Height){
// 横屏
return;
}
}
// 3.函数去抖处理
window.onresize = utils.debounce(detectOrient,300);
detectOrient();