1px的实现

上周五,从vant库中拷出了hairline的源码,发现有一个他的实现是比较好的,不需要进行额外的media-query

那么他是如何做到的呢?代码再贴一遍:

/* scss */
@mixin border-surround-1px($color, $raduis) {
  &::after {
    position: absolute;
    box-sizing: border-box;
    content: ' ';
    pointer-events: none;

    top: -50%;
    right: -50%;
    bottom: -50%;
    left: -50%;
    border: 0 solid $color;
    transform: scale(0.5);
    border-radius: $raduis;
  }
  &,
  &--top,
  &--left,
  &--right,
  &--bottom,
  &--surround {
    position: relative;
  }
  &--top::after {
    border-top-width: 1px;
  }

  &--left::after {
    border-left-width: 1px;
  }

  &--right::after {
    border-right-width: 1px;
  }

  &--bottom::after {
    border-bottom-width: 1px;
  }
  &--surround::after {
    border-width: 1px;
  }
}

大致的1px的整体结构都是用伪元素+绝对定位实现的,主要的不同在于具体实现1px的方式

慕课网的高仿饿了么课程中的实现方式):

@mixin border-1px($color, $opacity) {
  position: relative;
  &:after {
    display: block;
    position: absolute;
    width: 100%;
    left: 0;
    bottom: 0;
    border-top: 1px solid $color;
    opacity: $opacity;
    content: ' ';
  }
}
/* 进行缩放 */
@media  (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) {
  .border-1px {
    &:after {
      -webkit-transform: scaleY(0.7);
      transform: scaleY(0.7);
    }
  }
}
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
  .border-1px {
    &:after {
      -webkit-transform: scaleY(0.5);
      transform: scaleY(0.5);
    }
  }
}

@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
  .border-1px {
    &:after {
      -webkit-transform: scaleY(0.3);
      transform: scaleY(0.3);
    }
  }
}

采用的是把伪元素after变成一条线,然后定位到元素底部,再进行缩放

主要是利用了伪元素加缩放的这两个功能,在需要1px边框的元素上定义一个伪元素,然后伪元素相对于这个元素是绝对定位,通过伪元素去画一个1px的边框,然后我们把它定位这个元素的下面,然后我们在去应用一个class去对这个伪元素进行缩放(纵轴Y轴进行缩放)

而vant不需要media-query,他采用的是一种比较讨巧的方法:

/* 不设置宽高,然后利用绝对布局+各个方向的-50%实现了 */
xxx {
    position: absolute;
    top: -50%;
    right: -50%;
    bottom: -50%;
    left: -50%;
}

已知top/left/right/bottom,设置百分比是根据父元素的宽高来定的,于是不设置宽高,而采用四个方向的-50%,会相当于把自身相比于父元素扩大了一倍

但是border-width: 1px;,却始终是1px,最后再利用transform: scale(0.5);就实现了缩小一倍,也就是实现了vant文档里面的0.5px(细边框),这也算讨巧的解决了移动端1px的问题吧...

ps:其中的pointer-events: none;可以直接MDN得知,主要是为了避免伪元素变成了鼠标点击事件的target

pointer-events CSS 属性指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target。

100vh在chrome/qq浏览器中的问题

主要参考:在移动前端上避免使用100vh单位

核心问题是移动浏览器,其中地址栏有时可见,有时隐藏,从而改变了视口的可见大小。 这些浏览器没有将100vh高度调整为视口高度变化时屏幕的可见部分,而是将100vh设置为浏览器的高度,并隐藏了地址栏。 结果是,当地址栏可见时,屏幕的底部将被切除

更糟糕的是,当用户首次访问移动设备上的网站时,地址栏将在顶部可见

于是就会出现在chrome/qq浏览器中,当设置100vh的body的时候,页面会出现滚动

文中提出的解决方案是:

页面加载时,将高度设置为window.innerHeight可以将高度正确设置为窗口的可见部分

而我自己使用的height:100%应该也算是误打误撞了...

滚动穿透的处理

记得之前自己也是直接搜的解决,直接参考链接吧...

解决移动端滚动穿透-作者:no-simple

记录一下,相当于做个拷贝(转载需带上参考链接):

分为固定弹窗和滚动弹窗的滚动穿透

固定弹窗的解决办法:

  1. 弹窗时给body设置overflow:hidden;(缺点:ios没用)
  2. 弹窗时给body设置position:fixed;(缺点:滚动位置会丢失,ios没用)
  3. 最佳:给弹窗加上@touchmove.stop.prevent,即可阻止touchmove事件传递到body,也就解决了滚动穿透

滚动弹窗的解决方法:

在弹窗打开的时候给body的全局滚动设置position:fixed属性,并设置top值;由于设置了fixed属性,那在弹窗的时候body就没有滚动条了。此时如果这么设置会发现body虽然没有了滚动穿透,但是原来的位置丢失了。所以再给body设置fixed属性的时候,要把当前的滚动位置赋值给css的top属性,那在视觉上就没有任何变化
 fixedBody () {
     let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
     document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'
 }
弹窗关闭的时候则要清除fixed固定定位和top值;并设置其滚动位置位置top值,则又恢复了滚动功能,而且视觉上没有任何变化,是目前最完美的解决方案!
looseBody () {
    let body = document.body
    body.style.position = ''
    let top = body.style.top
    document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top)
    body.style.top = ''
}

而评论区的redbuck也给出了不使用better-scroll,而是用AlloyTouch的方法:

better-scroller太重了.
可以试试AlloyTouch,只有300多行.

你可以只用它监视dom上的滑动.然后拿到值后自己去做滚动.

<div ref=wrap>
<div :style="{transfrom: `translateY(${offsetY}px)`}"> 
 
<div>
<div>

new AlloyTouch({
    target: this.$refs.wrap,
    change: v => {
    this.offsetY = v
    }
})

标签: none

添加新评论