Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

怎么来处理移动端的图片模糊以及在retina屏下1px模糊的问题? #43

Open
bibi7 opened this issue Oct 31, 2019 · 1 comment
Labels

Comments

@bibi7
Copy link
Owner

bibi7 commented Oct 31, 2019

主要的原因还是开发的时候在ios上发现1px的border线会占用2px的位置,所以稍微调研了一下下。

所以首先要明白的几个点:

物理像素(physical pixel)

物理像素往往和设备像素挂钩,他是设备(pc,移动端)能控制颜色,长宽的最小显示单位。

设备独立像素(device-independent pixel)

设备独立像素也称为密度无关像素,代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。
一般可以直接理解成我们在css文件中写的1px,要注意的是,设备独立像素在某些情况下并不等于物理像素。css像素是一个抽象的表达,在不同的设备中,1px所代表的含义并不统一。
所谓的一倍屏,二倍屏,其实指的就是以多少物理像素来显示一个设备独立像素。有时候经验丰富的ui给的图往往也会带有@2x@3x的标识。

设备像素比(device pixel ratio)

设备像素比:物理像素 / 设备独立像素
iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt

viewport

经常做移动开发的话,对下面的一行代码应该是很熟悉的。

<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no minimal-ui, viewport-fit=cover">

viewport其实就是设备的可视范围,一般来说为了让我们的手机不出现横向滚动条,往往会设置如下:
initial-scaleminimum-scalemaximum-scale

至于为什么在浏览器中能正常显示的图片和1px有时候在ios上面就会模糊?

在JavaScript中,可以通过window.devicePixelRatio获取到当前设备的dpr。而在CSS中,可以通过-webkit-device-pixel-ratio-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询

可以尝试一下在控制台查询一下dpr:

//in chrome
window.devicePixelRatio //1
// ios
window.devicePixelRatio //2

主要的原因就是因为retina屏下,默认的设备像素比为2的原因。
所以在retina上,1px其实对应的是 2 x 2 = 4px

回到问题上

对于图片来说:一个位图像素单元是一个图片的最小显示单位,每一个位图像素单元都规定了该像素的颜色,透明度,显示位置。如上文,一个100x100的图片在dpr为2的retina上,一个位图像素的信息要应用到4个物理像素上,由于单个位图像素不可以再进一步分割,所以只能就近取色,导致图片看起来比较模糊。

对于1px来说:retina会把1px认成2个物理像素点进行描绘。

所以重点是,针对每一个设备进行dpr查询是不是就能解决问题?

其实还真是,所以目前业内有一些通用的做法。

viewport强制修改scale进行缩放

手淘在16年左右有着一个自己的开源库,lib-flexible。主要采用的方法为viewport + rem来进行各种终端适配,其中viewport用来解决一下本文中提出的问题:

//类似的代码
document.addEventlistener('DOMContentLoaded', functin() {
  let scale = 1 / window.devicePixelRatio
  document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
})

事实上还做了点其他的事情

  1. <html>元素添加data-dpr属性,并且动态改写data-dpr的值
  2. <html>元素添加font-size属性,并且动态改写font-size的值,配合rem使用,解决由于scale0.5带来的副作用

如果只在意1px的话,由于ios8以上开始支持0.5px的设定,所以可以使用媒体查询单独修改:

@media screen and (-webkit-min-device-pixel-ratio: 2) {
  .borderLine {
    border: 0.5px red solid;
  }
}

transform配合伪类使用:

.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;
}

box-shadow的方式实现0.5px

.box-shadow-1px {
  box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}

总感觉不是很优雅?

border-image,我司主流的解决方案

.border-d8e2e9 {
  -webkit-border-image: url(images/border-d8e2e9.e5eb08.5bbda46c.png) 2 2 2 2 stretch stretch
}

其实border-image不是特别好用,因为更换颜色什么的特别麻烦,必须更换图片。但是由于我司对border的低需求率以及一贯单调的ui,到现在都还能用。。。┑( ̄Д  ̄)┍

@bibi7 bibi7 added the css label Oct 31, 2019
@bibi7
Copy link
Owner Author

bibi7 commented Oct 31, 2019

参考:手淘方案

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant