css实现1px的几种办法

  • 背景
  • 物理像素和逻辑像素
  • 为什么css设置1px,但是在移动端上显示却感觉有些粗呢?
  • css如何实现1px的物理像素
    • 法一:利用box-shadow
    • 法二:设置 border-image 方案
    • 法三:使用background-image实现
    • 法四:多背景渐变实现
    • 法五:用小数来写px值
    • 法六:viewport + rem 实现
    • 法七:伪类 + transform 实现

背景

物理像素和逻辑像素

  • 物理像素(physical pixel)
    物理像素也叫硬件像素或者设备像素,一个物理像素是显示器(手机屏幕)上最小的物理显示单元(像素颗粒),在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。 如:iPhone6上就有750*1334个物理像素颗粒。

  • 逻辑像素(density-independent pixel)
    逻辑像素也叫设备独立像素或者密度无关像素,可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如:css像素。然后由相关系统转换为物理像素。所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比。

(3)设备像素比(device pixel ratio )简称dpr
设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。它的值可以按如下的公式的得到:

设备像素比(dpr)=物理像素/逻辑像素(px) // 在某一方向上,x方向或者y方向,下图dpr=2

为什么css设置1px,但是在移动端上显示却感觉有些粗呢?

知道了设备像素比,我们就大概知道了1px线变粗的原因。简单来说就是手机屏幕分辨率越来越高了,同样屏幕大小的一个手机,它的实际物理像素数更多了。因为不同的移动设备有不同的像素密度,所以我们所写的1px在不同的移动设备上展示是不一样的。

  • 先从一个例子来看:
    iPhone 3GS 和 iPhone 4 的像素分别是 320px 和 640px,但是显示屏的宽度都是相同的,所以为了在所有设备上渲染出的显示效果相同,CSS 中的 1px 映射到 iPhone 4 的物理像素上,就会是 2px。同样的道理,在 iPhone 5、6 上 CSS 的 1px 对应物理像素 2px,6plus 则是 3px。所以当我们设置 1px 时,实际的显示效果其实是由两个甚至三个像素点所绘制的。

  • 现在做移动端开发时一般都要加上一句话:

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

    这句话定义了本页面的viewport的宽度为设备宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放。

    手机存在一个能完美适配的理想viewport, 分辨率相差很大的手机的理想viewport的宽度可能是一样的, 这样做的目的是为了保证同样的css在不同屏幕下的显示效果是一致的, viewport的好处就在于一套css可以适配多个机型。

    在window对象中有一个devicePixelRatio属性,他可以反应css中的像素与设备的像素比。然而1px在不同的移动设备上都等于这个移动设备的1px,这是因为不同的移动设备有不同的像素密度。有关这个属性,它的官方的定义为:设备物理像素和设备独立像素(逻辑像素)的比例,也就是

    devicePixelRatio = 物理像素 / 设备独立像素
    
  • 1px变粗的原因:
    viewport的物理像素和逻辑像素(css像素)是按比例而不是相同的. 移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长。通过设置viewport,可以改变css中的1px用多少物理像素来渲染,设置了不同的viewport,当然1px的线条看起来粗细不一致。

    其实出现1px的原因还是在于,UI设计师要求的1px是物理像素,而我们开发写的css是逻辑像素,他们是不一样的,存在一个换算比例,通常JavaScript可以通过window.devicePixelRatio来获取,在iPhone上出现边框变宽原因就是因为devicePixelRatio=2,而border-width=1,边框被放大了俩倍,导致出现边框变宽。

css如何实现1px的物理像素

法一:利用box-shadow

  • 优点:
    代码量少
    可以满足所有场景
  • 缺点:
    边框有阴影,颜色变浅

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>.box {width: 100px;height: 100px;margin: 50px auto;background-color: antiquewhite;box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 1);}</style>
</head>
<body><div class="box"></div>
</body>
</html>

效果

将阴影尺寸设置为负数,设置成-1px 是为了让阴影尺寸稍小于div元素尺寸,这样左右两边的阴影就不会暴露出来,实现只有底部一边有阴影的效果。从而实现分割线效果(单边边框)

法二:设置 border-image 方案

用1px宽度图片做border图片

  • 优点:
    可以设置单条,多条边框
    没有性能瓶颈的问题
  • 缺点:
    修改颜色麻烦, 需要替换图片
    圆角需要特殊处理,并且边缘会模糊
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>.box {width: 100px;height: 100px;margin: 50px auto;background-color: antiquewhite;}.border-image-1px {border-bottom: 1px solid transparent;border-image: url(border.png) 30 stretch;}</style>
</head>
<body><div class="box border-image-1px"></div>
</body>
</html>

法三:使用background-image实现

background-image 跟border-image的方法一样,你要先准备一张符合你要求的图片。然后将边框模拟在背景上。

  • 优点:
    可以设置单条,多条边框
    没有性能瓶颈的问题
  • 缺点:
    修改颜色麻烦, 需要替换图片
    圆角需要特殊处理,并且边缘会模糊
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>.box {width: 100px;height: 100px;margin: 50px auto;background-color: antiquewhite;}.background-image-1px {background: url(border.png) repeat-x left bottom;-webkit-background-size: 100% 1px;background-size: 100% 1px;background-color: antiquewhite;}</style>
</head>
<body><div class="box background-image-1px"></div>
</body>
</html>

法四:多背景渐变实现

与background-image方案类似,只是将图片替换为css3渐变。设置1px的渐变背景,50%有颜色,50%透明。

  • 优点:
    可以实现单条、多条边框
    边框的颜色随意设置
  • 缺点:
    代码量不少
    圆角没法实现
    多背景图片有兼容性问题
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>.background-gradient-1px {background:linear-gradient(#000, #000 100%, transparent 100%) left / 1px 100% no-repeat,linear-gradient(#000, #000 100%, transparent 100%) right / 1px 100% no-repeat,linear-gradient(#000,#000 100%, transparent 100%) top / 100% 1px no-repeat,linear-gradient(#000,#000 100%, transparent 100%) bottom / 100% 1px no-repeat}.box {width: 100px;height: 100px;margin: 50px auto;background-color: antiquewhite;}</style>
</head>
<body><div class="box background-gradient-1px"></div>
</body>
</html>

法五:用小数来写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 }
}
  • 优点:
    简单,不需要过多代码。
  • 缺点:
    无法兼容安卓设备、 iOS 8 以下设备。

法六:viewport + rem 实现

整体思路:是在viewport设置缩放,通过js去动态修改viewport的值。

  • 优点:
    所有场景都能满足
    一套代码,可以兼容基本所有布局
  • 缺点:
    老项目修改代价过大,只适用于新项目

在页面初始化的时候,设置viewport:

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

通过js来动态实现对viewport的修改:

var viewport = document.querySelector("meta[name=viewport]")
if (window.devicePixelRatio == 1) {viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')
}
if (window.devicePixelRatio == 2) {viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')
}
if (window.devicePixelRatio == 3) {viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')
}
var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;

法七:伪类 + transform 实现

原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,边框宽度设置为1px,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。

  • 优点:
    所有场景都能满足
    支持圆角(伪类和本体类都需要加border-radius)
  • 缺点:
    需要注意<input type=“button”>是没有:before, :after伪元素的
    对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套

单条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;
}

四条boder样式设置:

.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('ul').className = 'scale-1px';
}

文章参考:
7种方法解决移动端Retina屏幕1px边框问题
移动端1px细线解决方案总结
css基础之移动端1px问题
移动端1px模糊产生的原因以及解决方案
css实现1px 像素线条_解决移动端1px线条的显示方式
关于移动端开发1px线的一些理解和解决办法
移动端1px误差的原因以及解决方案
CSS 实现移动端 1px 线条的绘制

css实现1px的几种办法相关推荐

  1. CSS实现垂直居中的6种办法

    1:使用绝对定位 + transform,给子元素添加如下样式 父子元素都不确定宽高的情况也适用.如果子元素的宽高确定的话,translate中的值也可以设置为子元素宽高的一半,即transform: ...

  2. 解决塌陷的几种·办法

    <!DOCTYPE html> <html> <head>   <meta charset="UTF-8">   <title ...

  3. 使用CSS替代JS实现几种常见的特效

    本文介绍用CSS代替JS来实现我们页面中所需要的几种常见效果.包括导航高亮,下拉菜单等. 1. 导航高亮      导航高亮是一种很常见的问题,包括当前页面的导航在菜单里面高亮和hover时高亮.你可 ...

  4. 在HTML中使用CSS美化网页的三种方法

    在HTML中使用CSS美化网页的三种方法 CSS是Cascading Style Sheets(级联样式表)的缩写,CSS是一种样式表语言,用于为HTML文档定义布局.例如,CSS涉及字体.颜色.边距 ...

  5. axure web组件下载_实践干货:Axure插入图标的4种办法

    编辑导读:图标是我们在制作产品原型的时候使用的比较多的一类素材,在日常绘制原型的时候一般是以插入的形式添加到Axure中.本文作者结合自身经验,介绍了四种Axure中引入图标的方法,希望对大家能有所帮 ...

  6. 提高CSS文件可维护性的五种方法

    当完成一项前端的工作之后,许多人都会忘记该项目的结构与细节.然而代码并不是马上就能完全定型,在余下的时间里还有不断的维护工作,而这些工作也许不会是你自己完成.所以,结构优良的代码能很大程度上优化它的可 ...

  7. axure弹窗关闭_干货来袭,Axure插入图标的几种办法

    前言 在日常绘制原型的时候,经常会需要插入相应的图标(icon)到Axure中,但是看似好像很简单的事情也给蛮多小伙伴造成了困扰. 现在很多开发团队都会用一些比较常见的前端框架来搭建后台管理系统,例如 ...

  8. CSS相关知识点:6种清除浮动和BFC

    文章目录 CSS相关知识点:6种清除浮动和BFC 一.6种清除浮动 1.场景 2.原因 3.清除浮动 (1).给父级设置对应的高度 (2).给父级增加定位absolute (3).将父级也设计成浮动 ...

  9. 引入CSS样式表的三种方式

    引入CSS样式表的三种方式 行内样式 通过标签的style属性来设置元素的样式,其基本语法格式如下: <h1 style="color:red;">style属性的应用 ...

最新文章

  1. SubVersion(SVN) 服务器Windows安装指南
  2. 互联网协议 — L2TP 二层隧道协议
  3. 怎样知道一个数是不是2的N次方,怎样判断一个数是奇数还是偶数
  4. 清除距今天7天的日志
  5. conda环境下如何升级python?
  6. U-Boot 之二 详解使用 eclipse + J-Link 进行编译及在线调试
  7. CyclicBarrier(回环栅栏)
  8. 2013年大数据全球技术峰会观后感
  9. 20应用统计考研复试要点(part41)--概率论与数理统计
  10. [css] 写出你知道的CSS水平和垂直居中的方法
  11. dedeCMS初始化数据体验包的安装与清除?
  12. java extends 继承的一些小结。
  13. mysql数据库主从同步的原理_mysql数据库主从同步复制原理
  14. centos下redis安全相关
  15. linux echo输出结果赋值给变量,shell变量n位补零
  16. nowcoder20072 [HNOI2009]图的同构
  17. 计算程序中flag是什么意思,python中flag什么意思
  18. VMware的网络连接原理
  19. DDU(Display Driver Uninstaller) 18.0.3.5 显卡驱动彻底卸载清理工具,支持卸载NVIDIA, AMD, Intel
  20. C语言常见问题(3):Although the value stored to ‘ret‘ is used in the enclosing expression

热门文章

  1. 洛谷P4233 射命丸文的笔记 分治NTT+竞赛图
  2. 盘点|2018半导体产业城市“风云榜”
  3. mysql去重分组_mysql 分组 去重
  4. 孤尽31天-day02
  5. mysql获取当天每小时统计_详解mysql 获取某个时间段每一天、每一个小时的统计数据...
  6. jnz和djnz_单片机里的cjne  djnz分别是什么意思?
  7. Time Freeze 时间冻结 影子系统
  8. 经营者购买餐饮商铺需要注意些什么
  9. 配置console口认证(华为/思科)
  10. ADS2017安装步骤