1px 问题
border-image
需要单独准备图片,而且圆角不是很好处理,但是可以应对大部分场景。
基于 media查询判断不同的设备像素比给定不同的 border-image:
.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
需要单独准备图片,而且圆角不是很好处理,但是可以应对大部分场景。
和 border-image类似,准备一张符合条件的边框背景图,模拟在背景上。
.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
借助 PostCSS的 postcss-write-svg我们能直接使用 border-image和 background-image创建 svg的 1px边框:
@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;
}
伪类 + transform
基于 media查询判断不同的设备像素比对线条进行缩放:
.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);
}
}
伪类 + transform(升级版)
原理:
- 主要是通过给目标元素添加
position:relative
; - 然后再用其伪类
:after
或者:before
画一个2倍或者3倍宽高的元素; - 然后给伪类元素画一个1px的边框;
- 通过
media query
决定缩放伪类元素到1/2或者1/3; - 给伪类元素增加
pointer-events: none;
, 这样伪类元素可以点击穿透, 也就是能看到, 但是不触发任何默认事件(click等);
封装
经过 scss 封装后:
@mixin thinBorder($directionMaps: bottom, $color: #ccc, $radius:(0, 0, 0, 0), $position: after)
$directionMaps
: 是个list类型可以传入多个方向, 也就是可以生成多个防线边框, 默认值为bottom, 你可以根据需要传入(top, left, bottom, right) 4个方向;$color
: 边框的颜色, 默认#ccc
;$radius
: 圆角半径, 默认0;$position
是一个高级设置, 一般都不需要改动, 由于细边框的实现使用了css的伪类, 所以为了规避可能出现的样式冲突, 我们可以自己指定使用:after
还是:before
, 默认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);
}
}
}
使用
- 单侧边框
@each $dir in (top,right,bottom,left) { .border-#{$dir}-#{1}px { @include thinBorder( $dir); } }
- 多侧边框
.border-top-left-red-1px{ @include thinBorder((top,left), red); }
- 圆角边框
.border-top-left-red-1px{ @include thinBorder(top, red, 100px); }
- 使用:before去生成边框
.border-top-before{ @include thinBorder(top, red, 0, before); }