1px pixel problem on mobile

1px question

border-image

The picture needs to be prepared separately, and the rounded corners are not very easy to handle, but it can handle most scenes.

Judging different device pixel ratios based on media queries given different border-images:

.border_1px {
    
    
  border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
    
    
  .border_1px {
    
    
    border-bottom: none;
    border-width: 0 0 1px 0;
    border-image: url(../img/1pxline.png) 0020 stretch;
  }
}

background-image

The picture needs to be prepared separately, and the rounded corners are not very easy to handle, but it can handle most scenes.

Similar to border-image, prepare a qualified border background image and simulate it on the background.

.border_1px {
    
    
  border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
    
    
  .border_1px {
    
    
    background: url(../img/1pxline.png) repeat-x left bottom;
    background-size: 100% 1px;
  }
}

svg

With PostCSS's postcss-write-svg we can directly use border-image and background-image to create a 1px border of svg:

@svg border_1px {
    
    
    height: 2px;
    @rect {
    
    
        fill: var(--color, black);
        width: 100%;
        height: 50%;
    }
}

.example {
    
    
    border: 1px solid transparent;
    border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; 
}

Pseudo class + transform

Based on the media query, it is judged that different device pixel ratios are used to scale the lines:

.border_1px:before {
    
    
  content: '';
  position: absolute;
  top: 0;
  height: 1px;
  width: 100%;
  background-color: #000;
  transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
    
    
  .border_1px:before {
    
    
    transform: scaleY(0.5);
  }
}
@media only screen and (-webkit-min-device-pixel-ratio: 3) {
    
    
  .border_1px:before {
    
    
    transform: scaleY(0.33);
  }
}

Pseudo class + transform (upgraded version)

principle:

  1. Mainly by adding to the target element position:relative;
  2. Then use its pseudo class :afteror :beforedraw an element with 2 times or 3 times the width and height;
  3. Then draw a 1px border for the pseudo-class element;
  4. By media querydeciding to scale pseudo-class elements to 1/2 or 1/3;
  5. Add pseudo-class elements pointer-events: none;, so that pseudo-class elements can be clicked through, that is, can be seen, but do not trigger any default events (click, etc.);

encapsulation

After scss encapsulation:

@mixin thinBorder($directionMaps: bottom, $color: #ccc, $radius:(0, 0, 0, 0), $position: after)
  • $directionMaps: It is a list type that can be passed in multiple directions, that is, multiple defense borders can be generated. The default value is bottom, and you can pass in (top, left, bottom, right) 4 directions according to your needs;
  • $color: Border color, default #ccc;
  • $radius: Corner radius, default 0;
  • $positionIt is an advanced setting, and generally does not need to be changed. Since the realization of the thin border uses the pseudo-class of css, in order to avoid possible style conflicts, we can specify whether to use it :afteror :beforedefault after;
@mixin thinBorder($directionMaps: bottom, $color: #ccc, $radius:(0, 0, 0, 0), $position: after) {
    // 是否只有一个方向
    $isOnlyOneDir: string==type-of($directionMaps);

    @if ($isOnlyOneDir) {
        $directionMaps: ($directionMaps);
    }

    @each $directionMap in $directionMaps {
        border-#{$directionMap}: 1px solid $color;
    }

    // 判断圆角是list还是number
    @if(list==type-of($radius)) {
        border-radius: nth($radius, 1) nth($radius, 2) nth($radius, 3) nth($radius, 4);
    }

    @else {
        border-radius: $radius;
    }

    @media only screen and (-webkit-min-device-pixel-ratio: 2) {
        & {
            position: relative;

            // 删除1像素密度比下的边框
            @each $directionMap in $directionMaps {
                border-#{$directionMap}: none;
            }
        }

        &:#{$position} {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            display: block;
            width: 200%;
            height: 200%;
            transform: scale(0.5);
            box-sizing: border-box;
            padding: 1px;
            transform-origin: 0 0;
            pointer-events: none;
            border: 0 solid $color;

            @each $directionMap in $directionMaps {
                border-#{$directionMap}-width: 1px;
            }

            // 判断圆角是list还是number
            @if(list==type-of($radius)) {
                border-radius: nth($radius, 1)*2 nth($radius, 2)*2 nth($radius, 3)*2 nth($radius, 4)*2;
            }

            @else {
                border-radius: $radius*2;
            }

        }
    }

    @media only screen and (-webkit-min-device-pixel-ratio: 3) {
        &:#{$position} {

            // 判断圆角是list还是number
            @if(list==type-of($radius)) {
                border-radius: nth($radius, 1)*3 nth($radius, 2)*3 nth($radius, 3)*3 nth($radius, 4)*3;
            }

            @else {
                border-radius: $radius*3;
            }

            width: 300%;
            height: 300%;
            transform: scale(0.3333);
        }
    }
}

use

  • single border
    @each $dir in (top,right,bottom,left) {
        .border-#{$dir}-#{1}px {
            @include thinBorder( $dir);
        }
    }
    
  • Multi-Side Border
    .border-top-left-red-1px{
        @include thinBorder((top,left), red);
    }
    
  • rounded border
    .border-top-left-red-1px{
        @include thinBorder(top, red, 100px);
    }
    
  • Use: before to generate borders
    .border-top-before{
        @include thinBorder(top, red, 0, before);
    }
    

Guess you like

Origin blog.csdn.net/var_deng/article/details/130559244