现在的PM和UI总以看app的眼光看html5, html页面要做的专业美观,而且必须很精细.

去年的时候UI就告诉我h5上的边框线太粗,把整站都给拉low了. 当时工期紧就没太在意1px粗细, 好在那个版本没上线就迭代掉了,后面的版本针对这个问题做了些尝试, 这里总结下1px细线的处理方法

移动端1px变粗的原因

为什么移动端css里面写了1px, 实际看起来比1px粗. 其实原因很好理解:这2个’px’的含义是不一样的. 移动端html的header总会有一句

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

这句话定义了本页面的viewport的宽度为设备宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放. viewport通俗的讲是浏览器上可用来显示页面的区域, 这个区域是可能比屏幕大的.

根据这篇文章http://www.cnblogs.com/2050/p/3877280.html的分析, 手机存在一个能完美适配的理想viewport, 分辨率相差很大的手机的理想viewport的宽度可能是一样的, 这样做的目的是为了保证同样的css在不同屏幕下的显示效果是一致的, 上面的meta实际上是设置了ideal viewport的宽度.

以实际举例: iphone3和iphone4的屏幕宽度分别是320px,640px, 但是它们的ideal viewport的宽度都是320px, 设置了设备宽度后, 320px宽的元素都能100%的填充满屏幕宽. 不同手机的ideal viewport宽度是不一样的, 常见的有320px, 360px, 384px. iphone系列的这个值在6之前都是320px, 控制viewport的好处就在于一套css可以适配多个机型.

看懂的人应该已经明白 1px变粗的原因了, viewport的设置和屏幕物理分辨率是按比例而不是相同的. 移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长.

1px解决方案

1.用小数来写px值

IOS8下已经支持带小数的px值, media query对应devicePixelRatio有个查询值-webkit-min-device-pixel-ratio, css可以写成这样

.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border { border: 0.333333px solid #999 }
}

如果使用less/sass的话只是加了1句mixin

缺点: 安卓与低版本IOS不适用, 这个或许是未来的标准写法, 现在不做指望

2.border-image

这样的1张6X6的图片, 9宫格等分填充border-image, 这样元素的4个边框宽度都只有1px

@media screen and (-webkit-min-device-pixel-ratio: 2){
.border{
border: 1px solid transparent;
border-image: url(border.gif) 2 repeat;
}
}

图片可以用gif, png, base64多种格式, 以上是上下左右四条边框的写法, 需要单一边框只要定义单一边框的border, 代码比较直观.

border-image兼容性:

缺点: 对于圆角样式, 将图片放大修改成圆角也能满足需求, 但这样无形中增加了border的宽度

存在多种边框颜色或者更改的时候麻烦

3. background渐变

背景渐变, 渐变在透明色和边框色中间分割, frozenUI用的就是这种方法, 借用它的上边框写法:

@media screen and (-webkit-min-device-pixel-ratio: 2){
    .ui-border-t {
        background-position: left top;
        background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.5,transparent),color-stop(0.5,#e0e0e0),to(#e0e0e0));
    }
}

这样更改颜色比border-image方便, 兼容性

缺点: 代码量大, 而且需要针对不同边框结构, frozenUI就定义9种基本样式

而且这只是背景, 这样做出来的边框实际是在原本的border空间内部的, 如果元素背景色有变化的样式, 边框线也会消失.

最后不能适应圆角样式

4. :before, :after与transform

之前说的frozenUI的圆角边框就是采用这种方式, 构建1个伪元素, 将它的长宽放大到2倍, 边框宽度设置为1px, 再以transform缩放到50%.

.radius-border{
position: relative;
}
@media screen and (-webkit-min-device-pixel-ratio: 2){
.radius-border:before{
content: "";
pointer-events: none; /* 防止点击触发 */
box-sizing: border-box;
position: absolute;
width: 200%;
height: 200%;
left:;
top:;
border-radius: 8px;
border:1px solid #999;
-webkit-transform(scale(0.5));
-webkit-transform-origin: 0 0;
transform(scale(0.5));
transform-origin: 0 0;
}
}

需要注意<input type="button">是没有:before, :after伪元素的

优点: 其实不止是圆角, 其他的边框也可以这样做出来

缺点: 代码量也很大, 占据了伪元素, 容易引起冲突

5. flexible.js

这是淘宝移动端采取的方案, github的地址:https://github.com/amfe/lib-flexible. 前面已经说过1px变粗的原因就在于一刀切的设置viewport宽度, 如果能把viewport宽度设置为实际的设备物理宽度, css里的1px不就等于实际1px长了么. flexible.js就是这样干的.

<meta name=”viewport”>里面的scale值指的是对ideal viewport的缩放, flexible.js检测到IOS机型, 会算出scale = 1/devicePixelRatio, 然后设置viewport

metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

devicePixelRatio=2时输出meta如下, 这样viewport与ideal viewport的比是0.5, 也就与设备物理像素一致

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

另外html元素上的font-size会被设置为屏幕宽的1/10, 这样css可以以rem为基础长度单位进行改写, 比如rem是28px, 原先的7px就是0.25rem. border的宽度能直接写1px.

function refreshRem() {
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) { //大于540px可以不认为是手机屏
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}

px和rem相互转换的计算方法会暴露在window.lib.flexible中. 这样可以为less/sass编写宏方法. 具体的css改写方法参照大漠的文章http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html

项目中特别指出了为了防止字体模糊, 出现奇数字号的字体, 字体的实际单位还是要以px为单位.

缺点: 不适用安卓, flexible内部做了检测 非iOS机型还是采用传统的scale=1.0, 原因在于安卓手机不一定有devicePixelRatio属性, 就算有也不一定能响应scale小于1的viewport缩放设置, 例如我的手机设置了scale=0.33333333, 显示的结果也与scale=1无异.

综合使用

对于IOS, flexible.js处理的已经很好了, 对于Android,方法2,3,4结合起来大体可以满足要求. flexible.js虽然不适用于安卓, 但它里面的这一段代码可以用来做对安卓机的部署.

if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}

这里对安卓做检测, 如果是安卓, js动态加载css.

var link = document.createElement('link');
link.setAttribute("rel","stylesheet");
link.setAttribute("type","text/css");
link.setAttribute("href",".......Android.css");
document.querySelector('head').appendChild(link);

移动端1px细线解决方案总结的更多相关文章

  1. 移动端1px细线解决方案--利用transform缩放方式

    移动端1px会显示为2px; 解决方式很多,这里介绍比较常用的一种方式--css的transform属性缩放 1. 上边框 相当于 border-top <div class="bor ...

  2. 移动端1px细线的处理

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 移动端1px细线问题

    1可以用伪类实现 .con{position: relative;.con:before { content: " "; position: absolute; left: 0; ...

  4. 移动端1px边框解决方案

    在retina屏中,像素比为2(iPhone6/7/8)或3(iPhone6Plus/7Plus/8Plus),1px的边框看起来比真的1px更宽. 使用伪类加transform的方式 元素本身不定义 ...

  5. 移动端高清适配方案(解决图片模糊问题、1px细线问题)

    本文介绍了移动端适配的3种方法,以及移动端图片模糊问题和1px细线问题的解决方法.当然了,在这之前先整理了与这些方法相关的知识:物理像素.设备独立像素.设备像素比和viewport. >> ...

  6. 移动端1px边框

    问题:移动端1px边框,看起来总是2倍的边框大小,为了解决这个问题试用过很多方法,用图片,用js判断dpr等,都不太满意, 最后找到一个还算好用的方法:伪类 + transform 原理是把原先元素的 ...

  7. 手机端1px细线公共类

    手机端1px细线公共类 .borderBottom1px{ position: relative; } .borderBottom1px:after{ content: ""; p ...

  8. 移动端web常见问题解决方案

    meta基础知识 H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 忽略将页面中的数字识别为电话号码 忽略Android平台中对邮箱地址的识别 当网站添加到主屏幕快速启动方式,可隐藏地址栏,仅针对i ...

  9. 移动端1px边框伪类宽高计算

    移动端1px边框在手机上看显得比较粗,于是我们用伪类结合css3缩放的方法去设置线条,但是如果设置div的一条边,水平线就设置宽度100%,垂直线就设置高度100%,那么如果是div的四条边呢?宽高1 ...

随机推荐

  1. PHP内置安全函数一览

    内置安全函数 filter_var函数 根据参数中的过滤类型进行过滤,如过滤Email类型的,则符合的字符串返回字符串,不符合的返回False. urldecode函数 写这个函数是特别为了提醒注意, ...

  2. 下载Google Play外国区APP技巧

    安卓用户若遇到喜欢的APP是外国区的,只要FQ就能下载.比起果粉还要注册,是简便很多.但有没有更简单的办法?这个必须有!笔者前几天在网上闲逛时,就发现了一个给力的网站.让你不用FQ,只需3个步骤,就能 ...

  3. Sublime text3配置LiveReload 浏览器即时刷新

    1.在sublime控件台 install livereload插件(缺点:每次重新打开Sublime都需要启动) 2.配置Preference > Package Settings > ...

  4. Git - 使用BitBucket和SourceTree进行源代码管理遇到POST git-receive-pack (chunked)

    我使用的是SourceTree Mac版,提交到BitBucket时出现 一直处于 POST git-receive-pack (chunked)  状态,经过百度,解决问题 在使用SourceTre ...

  5. 爬虫自动登陆GitHub

    import requests from bs4 import BeautifulSoup r1 = requests.get( url='https://github.com/login' ) s1 ...

  6. 地址转换函数:inet_aton & inet_ntoa & inet_addr和inet_pton & inet_ntop

    在Unix网络编程中,我们常用到地址转换函数,它将ASCII字符串(如"206.62.226.33")与网络字节序的二进制值(这个值保存在套接口地址结构中)间进行地址的转换. 1. ...

  7. CSS在网页中应用的方式_嵌入式

    内联式样式表:直接写在现有的标记中,比如: 复制代码 代码如下: <p style="font-size:24px;">www.phpstudy.net</p&g ...

  8. CH0103最短Hamilton路径 & poj2288 Islands and Brigdes【状压DP】

    虐狗宝典学习笔记: 取出整数\(n\)在二进制表示下的第\(k\)位                                                    \((n >> ...

  9. poj1743 Musical Theme【后缀数组】【二分】

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 35044   Accepted: 11628 D ...

  10. R升级和包更新

    1.R升级 # 安装包"installr" install.packages("installr") # 导入包 library(installr) # 升级 ...