1. 原因

在 Retina 屏幕中,css 中的 1px,它会以 2px 的形式呈现。所以设置 1px,手机端看到的不是 1 像素,显得粗一些。
在不同的屏幕中,dpr 的值不相同,所以手机中呈现的 1 像素也会不一样。

2. 解决方法

1) 伪元素 + transform

思路:

  • 使用伪元素来实现边框效果
  • 使用 media query 针对不同的 dpr 值,将这个伪元素进行缩放

scss 中的 minxin

  1. @mixin border-1px($color,$position) {
  2. position: relative;
  3. @if ($position == "bottom"){
  4. &:after {
  5. content: "";
  6. position: absolute;
  7. left: 0;
  8. bottom: 0;
  9. border-top: 1px solid $color;
  10. width: 100%;
  11. }
  12. }
  13. @if ($position == "top"){
  14. &:before {
  15. content: "";
  16. position: absolute;
  17. left: 0;
  18. top: 0;
  19. border-top: 1px solid $color;
  20. width: 100%;
  21. }
  22. }
  23. @if ($position == "left"){
  24. &:before {
  25. content: "";
  26. position: absolute;
  27. left: 0;
  28. top: 0;
  29. border-left: 1px solid $color;
  30. height: 100%;
  31. }
  32. }
  33. @if ($position == "right"){
  34. &:after {
  35. content: "";
  36. position: absolute;
  37. left: 0;
  38. top: 0;
  39. border-left: 1px solid $color;
  40. height: 100%;
  41. }
  42. }
  43. }
  1. @media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) {
  2. .border-1px {
  3. &::after {
  4. -webkit-transform: scaleY(0.7);
  5. transform: scaleY(0.7);
  6. }
  7. }
  8. }
  9. @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
  10. .border-1px {
  11. &::after {
  12. -webkit-transform: scaleY(0.5);
  13. transform: scaleY(0.5);
  14. }
  15. }
  16. }

CSS 实现

  1. .scale-1px{
  2. position: relative;
  3. border:none;
  4. }
  5. .scale-1px:after{
  6. content: '';
  7. position: absolute;
  8. bottom: 0;
  9. background: #000;
  10. width: 100%;
  11. height: 1px;
  12. -webkit-transform: scaleY(0.5);
  13. transform: scaleY(0.5);
  14. -webkit-transform-origin: 0 0;
  15. transform-origin: 0 0;
  16. }

四条boder样式设置:

  1. .scale-1px{
  2. position: relative;
  3. margin-bottom: 20px;
  4. border:none;
  5. }
  6. .scale-1px:after{
  7. content: '';
  8. position: absolute;
  9. top: 0;
  10. left: 0;
  11. border: 1px solid #000;
  12. -webkit-box-sizing: border-box;
  13. box-sizing: border-box;
  14. width: 200%;
  15. height: 200%;
  16. -webkit-transform: scale(0.5);
  17. transform: scale(0.5);
  18. -webkit-transform-origin: left top;
  19. transform-origin: left top;
  20. }

优点:

  • 所有场景都能满足
  • 支持圆角(伪类和本体类都需要加border-radius)

缺点:

  • 对于已经使用伪类的元素(例如 clearfix),可能需要多层嵌套

    2) 使用 box-shadow 模拟边框

    利用 css 对阴影处理的方式实现 0.5px 的效果
    样式设置:

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

    优点:

  • 代码量少

  • 可以满足所有场景

缺点:

  • 边框有阴影,颜色变浅

    3) viewport + rem 实现

    同时通过设置对应viewport的rem基准值,这种方式就可以像以前一样轻松愉快的写1px了。
    在devicePixelRatio = 2 时,输出viewport:
    1. <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

在devicePixelRatio = 3 时,输出viewport:

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

这种兼容方案相对比较完美,适合新的项目,老的项目修改成本过大。
对于这种方案,可以看看《使用Flexible实现手淘H5页面的终端适配》
优点:

  • 所有场景都能满足
  • 一套代码,可以兼容基本所有布局

缺点: