移动端的1px问题

布局视口 layout viewport:

手机一般为了容纳为桌面浏览器设计的网站,默认布局viewport宽度远大于屏幕的宽度,为了让用户看到网站全貌,缩小网站。例如,apple一般将viewport宽度定为980px。主要意义是手机厂商不至于让自家手机变得可笑,在打开大于980宽度的页面的时候可以横向拖动,而不至于挤成一团。可以通过document.documentElement.clientWidth来获取。

视觉视口 visual viewport:

屏幕的可视区域,即物理像素尺寸,可以通过window.innerWidth来获取。对于iPhone 6 Plus来说,在加了著名代码前提下,值是414px,不加的话,值是980px,著名代码如果改一改width=device-width, initial-scale=1.5,这时值是276px。所以它是一个可变的值。

理想视口 ideal viewport:

最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度

为了让viewport能够等于ideal viewport,一般我们会添加meta标签。width=device-width,initial-scale=1.0的时候,视觉视口的大小。对于iPhone 6 Plus来说,是固定值414px。所以,理想视口就等于设备宽度。

1、什么是1px问题

     移动端css设置1px(如border:1px solid #000;),实际上边框的宽度比设置的1px要宽

2、移动端1px变宽原因 

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

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

3、1px解决方案

(1)  用小数写1px

//这是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
//缺点: IOS8下已经支持带小数的px值,安卓与低版本IOS不适用, 这个或许是未来的标准写法, 现在不做指望
//这是JavaScript方式
<
body> <div id="main" style="border: 1px solid #000000;"></div> </body> <script type="text/javascript"> if (window.devicePixelRatio && devicePixelRatio >= 2) { var main = document.getElementById('main'); main.style.border = '.5px solid #000000'; } </script>

//优点: 简单

//缺点: 兼容性差,目前之余IOS8+才支持,在IOS7及其以下、安卓系统都是显示0px。

(2)使用border-image(但要注意这个属性的兼容性):不推荐

//第一种写法 使用媒体查询
@media screen and (-webkit-min-device-pixel-ratio: 2){ 
    .border{ 
        border: 1px solid transparent;
        border-image: url(border.gif) 2 repeat;
    }
}
//第二种写法 直接用类名
.border {
    border-width: 1px 0px;
    -webkit-border-image: url(border.png) 2 0 stretch;
    border-image: url(border.png) 2 0 stretch;
} 

(3)使用background渐变(但要注意这个属性的兼容性)设置1px的渐变背景,50%有颜色,50%透明--->背景渐变, 渐变在透明色和边框色中间分割

//第一种方式:媒体查询
@media screen and (-webkit-min-device-pixel-ratio: 2)
{ .border{ 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空间内部的, 如果元素背景色有变化的样式, 边框线也会消失;不适应圆角样式
//第二种方式:直接类名
.border
{ background: linear-gradient(180deg, black, black 50%, transparent 50%) top left / 100% 1px no-repeat, linear-gradient(90deg, black, black 50%, transparent 50%) top right / 1px 100% no-repeat, linear-gradient(0, black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat, linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left / 1px 100% no-repeat; }

(4)会用 :before     ,   :after 与  transform(推荐使用)

原理:把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。

//第一种方法
//构建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: 0; top: 0; 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伪元素的

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

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

//第二种方式
//单条border样式设置:
.scale-1px{
     position: relative;
     border:none;
 } 
.scale-1px:after{
     content: '';
     position: absolute; 
     bottom: 0; 
     background: #000; 
     width: 100%; 
     height: 1px;
     -webkit-transform: scaleY(0.5); 
     transform: scaleY(0.5); 
     -webkit-transform-origin: 0 0; 
      transform-origin: 0 0; 
}
//四条border样式设置:
.scale-1px{ 
    position: relative; 
    margin-bottom: 20px; border:none;
} 
.scale-1px:after{ 
    content: ''; 
    position: absolute;
    top: 0; 
    left: 0;
    border: 1px solid #000; 
    -webkit-box-sizing: border-box; 
    box-sizing: border-box; 
    width: 200%; 
    height: 200%; 
    -webkit-transform: scale(0.5); 
    transform: scale(0.5); 
    -webkit-transform-origin: left top; 
    transform-origin: left top; 
}
//结合js来代码来判断是否是Retina屏
if(window.devicePixelRatio && devicePixelRatio >= 2){
     document.querySelector('div').className = 'scale-1px';
}
//优点:所有场景都能满足 支持圆角
//缺点:对于已经使用伪类的元素,可能需要多层嵌套

(5)使用flexible.js(https://github.com/amfe/lib-flexible

   原理:viewport宽度设置为实际的设备物理宽度,

(6)使用CSS3 box-shadow

.shadow {
        -webkit-box-shadow:0 1px 1px -1px rgba(255, 0, 0, 0.5);
    box-shadow:0 1px 1px -1px rgba(255, 0, 0, 0.5);
}
//不好用,不推荐

(7)viewport结合rem

//devicePixelRatio=2设置meta
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
//devicePixelRatio=3设置meta
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">

参考文献:

https://www.cnblogs.com/lunarorbitx/p/5287309.html

https://blog.csdn.net/xuexizhe88/article/details/80566552

本文为自己知识点搜索整理,若有侵权麻烦联系我,删除本文章。谢谢(* ̄︶ ̄)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-08-09 11:46  IT记录  阅读(1568)  评论(0编辑  收藏  举报