likes
comments
collection
share

小程序如何优雅的实现半页面弹窗

作者站长头像
站长
· 阅读数 14

背景

半页面弹窗是前端移动端中非常常用的组件,效果如下:

小程序如何优雅的实现半页面弹窗

一个用户体验好的半页面弹窗,应该有如下特点:

  1. 出现弹窗时,背景有个黑色半透明遮罩层,应该是逐渐出现的,透明度渐变。
  2. 出现弹窗时,弹窗是从下至上移动出现的,而不是闪现的。
  3. 关闭弹窗时,背景色也要逐渐消失,弹窗从上至下移动走。

一个好用的半页面弹窗,应该有如下特点:

  1. 动画样式实现不耦合弹窗的高度。无论里面放多少内容,弹窗有多高,不改样式的情况下,渐入渐出的动画都表现正常,且出现时,底部应该贴合屏幕底部。
  2. 控制出现/隐藏的方法简单,自动播放出现/隐藏的渐变动画,而非手动调用API播放渐变动画。

本文参考WeUI的实现,介绍如何优雅的实现半页面弹窗

遮罩层样式

.mask {
    position: fixed;
    z-index: 1000;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background: rgba(0,0,0,.6);
}

遮罩层动画

我们可以让遮罩层默认是隐藏状态(opacity为0),当要展示时,需要开发者设置一个新的class(比如叫show)给mask对应的标签。

然后,我们给遮罩层设置个transition即可。代码如下:

.mask{
    opacity: 0;
    visibility: hidden;
    transition: opacity .3s;
}
.mask.show {
    opacity: 1;
    visibility: visible;
}

注意,我们必须设置visibility属性。因为当你设置opacity后,只是修改了透明度,它会在顶部挡住所有的交互事件。所以我们需要修改visibility,这样它就不会挡住那些交互事件了。

弹窗样式

为了让弹窗无论什么高度都可贴紧屏幕底部,我们直接设置bottom: 0即可。

.dialog {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    min-height: 255px;
    max-height: 75%;
    z-index: 5000;
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    overflow: hidden;
    padding: 0 24px;
    padding: 0 24px constant(safe-area-inset-bottom) 24px;
    padding: 0 24px env(safe-area-inset-bottom) 24px;
}

也许你会好奇为什么设置3个padding:下面的合法的padding会覆盖前面的,constantenv可能在一些浏览器并不支持,这时候下面的就不合法了,会使用兜底的0 24px这个padding值。

为什么要用env(safe-area-inset-bottom)呢?主要是iPhone最近几年的产品,底部有一个条带,如下图:

小程序如何优雅的实现半页面弹窗

如果你贴紧底部放置文本,用户是看不清的。所以就有了「安全区域」概念,给弹窗设置底部的安全区域到padding里,保证了弹窗内容不会跟这个条带重合,保障了iOS用户体验。

在近代iPhone系列产品中,env(safe-area-inset-bottom)通常是34px,其它产品中,这个值是0。

弹窗动画

如果没有.show,就隐藏,把他放在屏幕底下,通过transform的translateY实现。为了让动画跟元素高度像素值无关,我们使用100%,代表元素整体高度。

.dialog {
    transform: translateY(100%);
    transition: transform .3s;
}
.dialog.show {
    transform: translateY(0);
}

看看wxml怎么写

这里以小程序为例:

<view aria-role="dialog" aria-modal="true" aria-hidden="{{!showDialog}}">
  <view class="mask {{showDialog ? 'show' : ''}}" catchtouchmove="return"></view>
  <view class="dialog {{showDialog ? 'show' : ''}}" catchtouchmove="return">
    弹窗内容
  </view>
</view>

注意这里的catchtouchmove="return",是为了在打开弹窗后,拦截了用户滑动事件,避免弹窗下面的文档被滑动。

看看html怎么写

我写了个demo,可以参考下:

写在最后

推荐阅读: