移动端 1px border 最佳实践

在移动端Retina屏,我们用CSS定义1px的边框时,会发现边框线条很粗。实际的原因是CSS中的px单位定义的是逻辑像素值,而实际显示的效果会以物理像素呈现,在Retina屏下,1px不止占了一个像素。

具体1px占了多少个像素,我们可以通过window.devicePixelRatio来获取,devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例,公式表示就是:devicePixelRatio = 物理像素 / dips。如iPhone 4s, 纵向显示的时候,屏幕物理像素640像素。当用户设置的时候,其视区宽度并不是640像素,而是320像素。这样,在视网膜屏幕的iPhone上,屏幕物理像素640像素,独立像素是320像素,因此,window.devicePixelRatio等于2,1px在iPhone 4s就占了2个像素。

如果在Retina屏幕上显示1个物理像素的边框线条,方法有很多种:包括设置border-width: 0.5px、border-image、动态viewport,这些方法有兼容、不支持圆角等问题,不够方便。通过个人实践,目前兼容较好且副作用较少的方式是通过:伪对象 + transform 缩放。

原理:在 Retina 屏幕上,去掉容器的原有 border,利用 :before 或 :after 制造容器尺寸 2 倍或 3 倍的绝对定位伪对象,使用 1px 的 border 定义伪对象边框后,用 transform 的 scale 把伪对象缩小到一半或 1/3,这样看上去伪对象就和容器一样大了,border也相应缩小到单个物理像素。

具体实现方式及主要实现代码如下:

/* 在头部获取设置devicePixelRatio */
!function(win) {
	var doc = win.document;
	var dpr = win.devicePixelRatio;
	if (dpr > 2) {
		dpr = 3
	} else {
		if (dpr > 1) {
			dpr = 2
		} else {
			dpr = 1
		}
	}
}(window);
/*根据dpr缩放border*/
@mixin dpr-border($class, $color, $radius:0, $position:all) {
%border {
  @if $position == 'all' {
    border: 1px solid $color;
  } @else if $position == 'right' {
    border-right: 1px solid $color;
  } @else if $position == 'left' {
    border-left: 1px solid $color;
  } @else if $position == 'top' {
    border-top: 1px solid $color;
  } @else if $position == 'bottom' {
    border-bottom: 1px solid $color;
  }
}
.#{$class} {
  @extend %border;
  border-radius: $radius;
  position: relative;
}
$dpr: (2, 3);
@each $value in $dpr {
  [data-dpr^='#{$value}'] .#{$class} {
    border: none;
    $rValue: 1/$value;
    &:before{
   content: ' ';
   position: absolute;
   left: 0;
   top: 0;
   width: 100%*$value;
   height: 100%*$value;
   @extend %border;
   border-radius: $radius;
   -webkit-transform: scale($rValue) translate(-50% * ($value - 1),-50% * ($value - 1));
    transform: scale($rValue) translate(-50% * ($value - 1),-50% * ($value - 1));
  }
}
}
}
/* 引用方法,设border */
@import '../base/mixins';
@import '../base/function';
.border {
  width: 100px;
  height: 100px;
  margin: 20px auto;
  border: 1px solid #999;
}
.border2,.border3 {
  margin: 20px auto;
  width: 100px;
  height: 100px;
}
@include dpr-border(border2,#999);
@include dpr-border(border3,#999,20px);

最终效果:点击查看
二维码扫一扫:

1border

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>