对移动端兼容适配的分析
一、思考
在移动端越来越重要的背景下,每位web开发者对移动适配都有自己的想法。是移动优先,还是pc优先,还是两者兼得?在实际开发中这个问题是和项目产品定位有关的,也涉及到ui的设计,不是开发者能决定。但不管产品如何定位,作为开发者总是要提供最优的解决方案,是用一套样式还是多套样式?网上一搜,有静态布局、流式布局,响应式布局,自适应布局,弹性布局等一堆,云里雾里,到底要怎么选呢?看完这篇文章相信心中就有数了。
二、viewport的使用
1、最常见的设置,大多数的框架(如bootstrap)和知名的站点基本是这个配置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
2、这个配置重点在width=device-width,就是让视窗口等于设配宽度,也就是我们开发中能用document的宽度,其它几个“初始缩放大小”“最大缩放大小”“最小缩放大小”和“是否允许用户缩放”可以理解为用来“固定”这个设置不被破坏的。
3、这个设置很简单,但同时也会带来一些需要解决的问题。
a、现在的手机都是两倍三倍的retina高清屏,1px实际的效果是不止一个像素的,对不同的设备设置不同
的initial-scale可以有比较好的效果,比如在2倍retina的iphone6(6s,7,8)中设置为0.5。一旦
动态设置这个,也就意味这视窗口不同了,需要不同样式适配。这也是分配样式的一套基准,如何分配样式
后面会有更详细的讲解。
b、在pc端如果有最小宽度的限制,同样需要配置不同的width值。
三、单位的使用
1、css中单位很多,这里只介绍最常用的几种:
(1) px:这个可以理解为“基准”单位,就是不管在什么设备中其值是不会变的,就像cm,kg这些一样
(2) em:这个是相对父容器的单位,一般用在字体font-size中比较好。如父容器font-size为16px,则
1em=16px
(3) rem:相对于根元素html的单位,如html的font-size为16px,则1rem=16px
(4) vw/vh: 视口宽高为100vw/100vh,这个和百分比类似,只是百分比是相对于父容器,其相对于视口
2、移动适配最常用的应该是rem,很多框架和淘宝的flexible适配都是基于这个单位,而自己做的话,一般
在首页加载时全局js设置html的font-size即可,代码如下:
(function (doc, win) { var docel = doc.documentelement, resizeevt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function () { var clientwidth = docel.clientwidth; if (!clientwidth) return; //这里根据设计稿为750,设置1rem=100px, docel.style.fontsize = 100 * (clientwidth / 375) + 'px'; }; // abort if browser does not support addeventlistener if (!doc.addeventlistener) return; win.addeventlistener(resizeevt, recalc, false); doc.addeventlistener('domcontentloaded', recalc, false); })(document, window);
3.如果用了sass/less等预编译语言可以更灵活的配置的,在上面方法内配置(设计稿为750的情况下):
docel.style.fontsize = 40 * (clientwidth / 750) + 'px';
在编译函数中配置:
@function px2rem($px, $base-font-size: 20px) {
@return ($px / $base-font-size) * 1rem;
}
这样我们就可以直接使用设计稿的尺寸,如:px2rem(100px),省去了自己计算,如果没用预编译语言(推
荐使用),编辑器也有插件支持单位转化。
4.上面是基于屏幕宽度来设置根元素font-size,如果设置不同的initial-scale,我们需要基于设备像素比设置,通过window.devicepixelratio获取。
四、页面布局方式
1.理解html的文档流方式,其实就是流式布局,即横向需要我们设置,纵向自动叠加。这个和移动端的设计体验方式是比较像的。在宽度中就要用自适应的方式,如百分比,有设置相对单位的,可用相对单位,灵活使用,css3的display:flex也是很好的选择,现代浏览器和移动设备基本都支持了。
2.刚才说到体验,很明显移动端和pc端的体验真的很不同,所以光有上面的自适应是远远不够,是不是需要对这两个完全不同的体验方式响应不同的布局和样式。
五、媒体查询
1.我们除了可以用js来判断不同的设备,设置相对单位所用的根元素。另一个强大的方式是可以通过css3强大的媒体查询来指定不同的样式。
2.媒体查询的规则
@media all and ([min-width|max-width|orientation|min-device-width|...]) { ... }
中括号[]中表示需要添加的条件,可匹配宽高/横竖屏/设备类型等,比如min-width:750px,表示最小宽度为750px,{}是在匹配模式下的样式。也有逻辑判断and/or/not连接不同的规则
3.要是引入整个文件,可以在link标签中使用
<link rel="stylesheet" media="screen and (min-width:900px)" href="big.css" type="text/css" />
表示:当屏幕大于或等于900px时,将采用big.css样式来渲染web页面。
4.bootstrap响应式设计这类栅格布局采用的就是这套方式。
六、1px像素边框问题
1.除了上面说到在viewport中设置缩放外,直接设置一个空元素缩放也是可以的
p{ width: 100px; height: 1px; background: red; display: block; transform: scaley(.5); }
不足:圆角无法实现,实现4条边框比较麻烦,并且只能单独实现,如果嵌套,会对包含的效果产生不想要的效果,所以此方案配合:after和before独立使用较多
2.利用css对阴影处理的方式实现0.5px的效果
box-shadow:0 1px 1px -1px rgba(0, 0, 0, 0.5);
不足:颜色不好处理, 黑色 rgba(0,0,0,1) 最深的情况了。有阴影出现,不好用大量使用box-shadow可能会导致性能瓶颈。四条边框实现效果不理想。
3.图片实现,使用 background-image 实现1px有两种方式: 渐变 linear-gradient 或直接使用图片(base64)。渐变 linear-gradient (50%有颜色,50%透明)
div{ height: 1px; background-image:-webkit-linear-gradient(top,transparent 50%,#000 50%); background-position: top left; background-repeat: no-repeat; background-size: 100% 1px; }
不足:大量使用渐变可能导致性能瓶颈,代码量大,多背景图片有兼容性问题
七、图片高清化
1.可以使用srcset属性设置,使用看https://www.zhangxinxu.com/wordpress/2014/10/responsive-images-srcset-size-w-descriptor/
2.背景图高清
a.使用上面介绍的媒体查询,如:
/* 普通显示屏(设备像素比例小于等于1)使用1倍的图 */ .css{ background-image: url(img_1x.png); } /* 高清显示屏(设备像素比例大于等于2)使用2倍图 */ @media only screen and (-webkit-min-device-pixel-ratio:2){ .css{ background-image: url(img_2x.png); } } /* 高清显示屏(设备像素比例大于等于3)使用3倍图 */ @media only screen and (-webkit-min-device-pixel-ratio:3){ .css{ background-image: url(img_3x.png); } }
b.image-set 实现高清化
.css { background-image: url(1x.png); /*不支持image-set的情况下显示*/ background: -webkit-image-set( url(1x.png) 1x,/* 支持image-set的浏览器的[普通屏幕]下 */ url(2x.png) 2x,/* 支持image-set的浏览器的[2倍retina屏幕] */ url(3x.png) 3x/* 支持image-set的浏览器的[3倍retina屏幕] */ ); }
c.很多网页端对图片的要求还是没那么高的,不像app那样,图片一般用一张2倍高清图就行,最新的设备对以上属性的支持还是可以的,对于要求高的应用使用
八、移动端click屏幕产生300ms的延时响应
1.原因:在浏览器需要如何判断快速点击上,当用户在屏幕上单击某一个元素时候,例如跳转链接<a href="#"></a>,此处浏览器会先捕获该次单击,但浏览器不能决定用户是单纯要点击链接还是要双击该部分区域进行缩放操作,所以,捕获第一次单击后,浏览器会先hold一段时间t,如果在t时间区间里用户未进行下一次点击,则浏览器会做单击跳转链接的处理,如果t时间里用户进行了第二次单击操作,则浏览器会禁止跳转,转而进行对该部分区域页面的缩放操作。那么这个时间区间t有多少呢?在ios safari下,大概为300毫秒。这就是延迟的由来。造成的后果用户纯粹单击页面,页面需要过一段时间才响应,给用户慢体验感觉,对于web开发者来说是,页面js捕获click事件的回调函数处理,需要300ms后才生效,也就间接导致影响其他业务逻辑的处理。
2.解决方案:
(1)使用fastclick.js,只要全局加入该文件并设置如下:
fastclick.attach(document.body);
(2) zepto的touch模块,tap事件也是为了解决在click的延迟问题
九、更改默认样式
//使用appearance改变webkit浏览器的默认外观 input,select { -webkit-appearance:none; appearance: none; } //winphone下,使用伪元素改变表单元素默认外观 //1.禁用select默认箭头,::-ms-expand修改表单控件下拉箭头,设置隐藏并使用背景图片来修饰 select::-ms-expand { display:none; } //2.禁用radio和checkbox默认样式,::-ms-check修改表单复选框或单选框默认图标,设置隐藏并使用背景图片来修饰 input[type=radio]::-ms-check, input[type=checkbox]::-ms-check { display:none; } //3.禁用pc端表单输入框默认清除按钮,::-ms-clear修改清除按钮,设置隐藏并使用背景图片来修饰 input[type=text]::-ms-clear, input[type=tel]::-ms-clear, input[type=number]::-ms-clear { display:none; } // 禁止长按链接与图片弹出菜单 a,img { -webkit-touch-callout: none } // 禁止ios和android用户选中文字 html,body {-webkit-user-select:none; user-select: none; } // 改变输入框placeholder的颜色值 ::-webkit-input-placeholder { /* webkit browsers */ color: #999; } :-moz-placeholder { /* mozilla firefox 4 to 18 */ color: #999; } ::-moz-placeholder { /* mozilla firefox 19+ */ color: #999; } :-ms-input-placeholder { /* internet explorer 10+ */ color: #999; } input:focus::-webkit-input-placeholder{ color:#999; } // android上去掉语音输入按钮 input::-webkit-input-speech-button {display: none}
十、总结
1.网站适配的终端可以用js或媒体查询的方式获取,分配对应的样式。
2.布局上采用相对单位,百分比和flex的弹性方式。
3.对移动端的特殊性进行适配,如1px问题,默认样式等。