移动端 1px 边框问题通用解决方案:scss mixin 版本

注意:本方案采用伪元素 + **transform** 的解决方案,在设置边框的元素有交互动作时,请设置子元素定位以及 **z-index** 值。

border.scss

  1. @mixin genBorderRaidus ($radius: null, $ratio: 1) {
  2. @if ($radius != null) {
  3. @if (type-of($radius) == list) {
  4. border-radius: nth($radius, 1)*$ratio nth($radius, 2)*$ratio nth($radius, 3)*$ratio nth($radius, 4)*$ratio;
  5. } @else {
  6. border-radius: $radius*$ratio;
  7. }
  8. }
  9. }
  10. @mixin genBorderRules ($rule: width, $directions: null, $values: null) {
  11. // 默认 border-style 为 solid
  12. @if ($rule == style and $values == null) {
  13. $values: solid;
  14. }
  15. @if ($values != null) {
  16. // directions 为列表,分别设置 top/right/bottom/left 等位置的样式
  17. @if (type-of($directions) == list) {
  18. $dirMap: (
  19. top: 1,
  20. right: 2,
  21. bottom: 3,
  22. left: 4
  23. );
  24. @if (type-of($values) == list) {
  25. @each $dir in $directions {
  26. border-#{$dir}-#{$rule}: nth($values, map-get($dirMap, $dir));
  27. }
  28. } @else {
  29. @each $dir in $directions {
  30. border-#{$dir}-#{$rule}: $values;
  31. }
  32. }
  33. }
  34. // dierections 为 null,默认为全边框
  35. @else if ($directions == null) {
  36. @if (type-of($values) == list) {
  37. border-#{$rule}: nth($values, 1) nth($values, 2) nth($values, 3) nth($values, 4);
  38. } @else {
  39. border-#{$rule}: $values;
  40. }
  41. }
  42. // directions 其余情况为单边设置
  43. @else {
  44. @if (type-of($values) == list) {
  45. border-#{$directions}-#{$rule}: nth($values, 1) nth($values, 2) nth($values, 3) nth($values, 4);
  46. } @else {
  47. border-#{$directions}-#{$rule}: $values;
  48. }
  49. }
  50. }
  51. }
  52. @mixin genBorder (
  53. $directions: null,
  54. $style: solid,
  55. $color: null,
  56. $radius: null,
  57. $position: after
  58. ) {
  59. @media (max--moz-device-pixel-ratio: 1.49), (-webkit-max-device-pixel-ratio: 1.49), (max-device-pixel-ratio: 1.49), (max-resolution: 143dpi), (max-resolution: 1.49dppx) {
  60. @include genBorderRules(width, $directions, 1px);
  61. @include genBorderRules(style, $directions, $style);
  62. @include genBorderRules(color, $directions, $color);
  63. @include genBorderRaidus($radius, 1);
  64. }
  65. @media (min--moz-device-pixel-ratio: 1.5) and (max--moz-device-pixel-ratio: 2.49), (-webkit-min-device-pixel-ratio: 1.5) and (-webkit-max-device-pixel-ratio: 2.49), (min-device-pixel-ratio: 1.5) and (max-device-pixel-ratio: 2.49), (min-resolution: 144dpi) and (max-resolution: 239dpi), (min-resolution: 1.5dppx) and (max-resolution: 2.49dppx) {
  66. & {
  67. position: relative;
  68. // 移除 border 采用伪类实现
  69. border: 0;
  70. border-radius: 0;
  71. }
  72. &::#{$position} {
  73. content: '';
  74. display: block;
  75. position: absolute;
  76. left: 0;
  77. top: 0;
  78. width: 200%;
  79. height: 200%;
  80. transform-origin: 0 0;
  81. transform: scale(0.5);
  82. @include genBorderRules(width, $directions, 1px);
  83. @include genBorderRules(style, $directions, $style);
  84. @include genBorderRules(color, $directions, $color);
  85. @include genBorderRaidus($radius, 2);
  86. }
  87. }
  88. @media (min--moz-device-pixel-ratio: 2.5), (-webkit-min-device-pixel-ratio: 2.5), (min-device-pixel-ratio: 2.5), (min-resolution: 240dpi), (min-resolution: 2.5dppx) {
  89. & {
  90. position: relative;
  91. // 移除 border 采用伪类实现
  92. border: 0;
  93. border-radius: 0;
  94. }
  95. &::#{$position} {
  96. content: '';
  97. display: block;
  98. position: absolute;
  99. left: 0;
  100. top: 0;
  101. width: 300%;
  102. height: 300%;
  103. transform-origin: 0 0;
  104. transform: scale(0.33333);
  105. @include genBorderRules(width, $directions, 1px);
  106. @include genBorderRules(style, $directions, $style);
  107. @include genBorderRules(color, $directions, $color);
  108. @include genBorderRaidus($radius, 3);
  109. }
  110. }
  111. }

测试代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
  <title>1px border</title>
  <link rel="stylesheet" href="./index.scss" />
</head>
<body>
  <div class="wrapper">
    <div class="border"></div>
    <div class="border-left"></div>
    <div class="border-left-right"></div>
    <div class="border-top-right"></div>
    <div class="border-top-right-bottom"></div>

    <div class="border-left-right-radius-10"></div>
    <div class="border-tob-bottom-blue-radius-10"></div>
    <div class="border-blue"></div>
    <div class="border-dashed-red"></div>
    <div class="border-red-radius-10"></div>
  </div>
</body>
</html>

css

@import './border.scss';

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  width: 100%;
  color: orange;

  > * {
    width: 50px;
    height: 50px;
    margin: 10px;
    background-color: #f8f8f8;
  }

  .border {
    @include genBorder();
  }
  .border-left {
    @include genBorder(left);
  }
  .border-left-right {
    @include genBorder((left,right));
  }
  .border-top-right {
    @include genBorder((top,right));
  }
  .border-top-right-bottom {
    @include genBorder((top,right,bottom))
  }

  .border-left-right-radius-10 {
    @include genBorder((left,right), solid, null, 10px)
  }
  .border-tob-bottom-blue-radius-10 {
    @include genBorder((top,bottom), solid, blue, 10px)
  }
  .border-blue {
    @include genBorder(null, solid, blue);
  }
  .border-dashed-red {
    @include genBorder(null, dashed, red);
  }
  .border-red-radius-10 {
    @include genBorder(null, solid, red, 10px);
  }
}