上篇文章《淘宝弹性布局方案lib-flexible实践》结合一个简单的实例,说明了lib-flexible的基本用法,但是lib-flexible的这种适配方式在适配的时候会修改viewport的initial-scale,导致viewport的width不等于device width,使得那些根据width编写的media query不一定与预期的一致,还有移动web经典的retina屏图片问题和1px边框问题在lib-flexible下也会与通常的做法有所差异,本文的内容就是研究这些东西,并提出一些自己思考和解决方法。
1. lib-flexible不能与响应式布局兼容先说说响应式布局的一些基本认识:
响应式布局的表现是:网页通过css媒介查询判断可视区域的宽度,在不同的范围应用不同的样式,以便在不同尺寸的设备上呈现最佳的界面效果。典型的例子是,有一个商品列表页,应用响应式布局后,可能在pc上是用4列展示,在平板上用3列展示,在手机上只用1列展示。这种布局的最大好处就是节省人力、资源和时间,所以很多公司都喜欢用。而响应式布局有两个必须的要求:
1)是viewport的设置,width跟initial-scale要采用如下配置,保证viewport的宽度与device width相同:
2)是要利用media query,针对不同的width范围,编写不同的css,比如bootstrap:
@media (max-width: @screen-xs-max) { ... } @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { ... } @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { ... } @media (min-width: @screen-lg-min) { ... }
需要注意的是:第(1)个要求提到的device width与media query里面的device-width属性表达的意思有些区别:第(1)个要求提到的device width在移动设备下指的是设备的宽度,但是在pc下指的是浏览器可视区域的宽度,比如下面这个网页,我把浏览器窗口缩小,然后你看它viewport里尽管已经把width设置成了device-width,但是网页大小却不是我的桌面的分辨率宽度(设备宽度):
media query里的device-width属性,始终指的是设备的宽度。所以响应式布局的媒介查询要用width属性,不用device-width属性,因为在桌面设备下,把浏览器窗口缩小的时候,device-width并不会发生改变,当调整浏览器窗口大小就看不到响应式的效果。
再来看lib-flexible的特点:
lib-flexible在适配的时候会修改viewport的initial-scale,导致viewport的width不等于device width。这是采用lib-flexible,在iphone6 plus下适配后,自动添加的viewport设置代码:
在这个viewport的作用下,网页的缩放系数为0.3333333333333333,iphone6 plus的device width为414个不缩放的css像素,经过缩放之后,viewport的width等于device width / 0.3333333333333333,为1242个缩放后的css像素,远远大于device width:
假如你的网页想同时使用响应式布局和lib-flexible,然后你写了一个媒介查询,需要在1024px以上的分辨率(桌面设备)呈现某个特殊样式(代码仅仅是为了举例):
@media only screen and (min-width: 1024px) { body { border: 10px solid #ccc; } }
会发现这个页面在iphone6 plus下也会应用到该媒介查询的样式:
究其原因是:iphone6 plus下的网页由于lib-flexible的作用,导致页面的width与实际物理分辨率的宽相等,也就是1242个像素,完全达到了该媒介查询的范围。
所以,在使用lib-flexible的项目里很难再实现响应式布局,要是有人有这种综合两者一起使用的想法,可得注意了。实际上,这两个方案本质性的东西就不相同,适用的场景也不相同。响应式布局的目的是一套代码,能够在手机平板和pc上都能良好展现,适用于网站类的项目,而lib-flexible解决的是手机端网页的适配问题,压根不管平板和pc的情况,适用于web app类的项目。
2. 1px边框在lib-flexible下如何处理web app有时候会设计出一些特别细的线条或者边框,如果我们直接通过css设置边框为1px:
border: 1px solid #ccc;
结果会发现这种边框在手机里看起来的效果,显得特别地粗,之所以会有这个效果,原因很简单,因为现在大部分手机的分辨率很高,一个css像素,比如上面代码中的1px,可能相当于2个甚至3个物理分辨率像素,而不像pc,一个css像素始终等于1个物理分辨率像素,所以手机里看到的1px会比实际的粗。
为了解决这个问题,你可能会想到用0.5px来代替1px,不过这个是解决不了问题的,而且带小数的像素在不同的浏览器下绝对是一个坑,千万要尽量避免。
那么通常在web app下显示1px的做法是怎样的呢,前阵子在weui的源码中看到了一个很好的办法,值得分享:
//这是一个mixin,用来设置顶部的边框,其它方向的代码没有贴出 .setTopLine(@c: #C7C7C7) { content: " "; position: absolute; left: 0; top: 0; width: 100%; height: 1px; border-top: 1px solid @c; transform-origin: 0 0; transform: scaleY(0.5); } //应用举例 .weui_cell { // onepx position: relative; &:before { .setTopLine(@weuiCellBorderColor); } }
这个办法并不是利用border属性来显示边框,而是利用了伪类和transform,最妙的是这个transform,0.5px办不到的事情,它却办得到。