TML 5.2<dialog>为本机模态对话框引入了一个新元素。乍一看,它看起来相当简单(而且确实如此),但是当我一直在玩它时,我发现它有一些很容易错过的好功能。
在本文末尾提供了一个完整的工作演示,
这是基本对话框的标记:
该open属性表示该对话框可见。没有它,对话框将被隐藏,直到您使用JavaScript来显示它。在添加任何样式之前,对话框呈现如下:
它绝对位于页面上,因此它会像您期望的那样出现在其他内容的前面,并且水平居中。默认情况下,它与内容中的内容一样宽。
基本操作
JavaScript有一些方法和属性可以轻松地使用<dialog>元素。你可能最需要的两种方法是showModal()和close()。
当您使用showModal()打开对话框时,会向页面添加背景,阻止用户与模态外部的内容进行交互。默认情况下,此背景是完全透明的,但您可以使用CSS显示它(更多信息如下)。
按Esc将关闭对话框,您可以提供关闭按钮来触发该close()方法。
还有第三种方法,show()也可以使模态出现,但没有伴随的背景。用户仍然可以与对话框外可见的元素进行交互。
目前,<dialog>Chrome只支持行为。Firefox提供默认样式,但JavaScript API仅在标志后面启用。我怀疑Firefox很快会默认启用它。
值得庆幸的是,有既提供JavaScript行为,又提供具有默认样式的样式表。dialog-polyfill在npm中安装以使用它 - 或使用常规旧<script>标签。它适用于IE9及以上版本。
使用polyfill时,页面上的每个对话框都需要初始化:
这不会取代拥有它的浏览器的本机行为。
打开和关闭模态很不错,但最初它看起来不太专业。添加样式就像设置任何其他元素一样简单。可以使用新的::backdrop伪元素设置背景样式。
对于使用polyfill的旧浏览器,此伪元素选择器将不起作用。在其位置,polyfill会.backdrop在对话框后立即添加元素。您可以使用CSS来定位它:
添加一点标记以提供样式挂钩。对话框的常用方法是将其分解为标题,正文和页脚:
为此添加一些CSS,您可以根据需要制作模态外观:
通常,我们希望从对话框中获得某种用户反馈。关闭对话框时,可以将字符串值传递给close()方法。此值分配给returnValue对话框DOM元素的属性,因此可以在以后读取:
还有一些你可以听的活动。两个有用的是close(当模态关闭cancel时触发)和(当用户按下Esc以关闭模态时触发)。
似乎缺少的一件事是在单击背景时关闭模态的能力,但有一种解决方法。单击背景会触发具有<dialog>事件目标的单击事件。如果构造模态以使子元素填充对话框的整个空间,那么这些子元素将成为对话框内任何单击的目标。这样,您可以侦听对话框上的单击,并在对话框本身是click事件的目标时关闭它:
这并不完美,但它确实有效。如果您找到更好的方法来检测背景上的点击次数,请与我们联系。
下面是演示地址:http://www.ikinsoft.com/demo/dialog/dialog.html
通讯应用和聊天界面中,当你正在与对方交谈时对方正在输入一条信息,会有一个小的气泡动画或者文案提示。本文将探讨使用现代 CSS 来实现这一动画效果,首先会实现一个 Blink 效果的动画,然后实现一个波浪效果动画,最后实现一个语音气泡效果。
1)Blink 效果:
2)Wave 效果:
3)语音气泡效果:
通过 html:5 和 div.container>(div.dot)*3 快速创建页面及容器。
<div class="container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
1)容器居中:
body {
display: grid;
place-content: center;
min-height: 100vh;
margin: 0;
}
2)容器样式:
注意:此处使用了现代CSS 原生嵌套(参考链接:)
.container {
display: flex;
justify-content: center;
align-items: center;
gap: 0.25rem;
background: #e2e8f0;
border-radius: 9999px;
padding: 1rem;
.dot {
border-radius: 9999px;
height: 0.5rem;
width: 0.5rem;
background: #93a2b7;
}
}
1)Blink 效果:
核心思想是通过给dot 元素设置 opacity 设置属性来改变其透明度,同时对 3 个 dot 的透明度变化设置不同的动画延迟 animation-delay 属性来实现闪烁的效果。
.container {
.dot {
opacity: 0;
animation: blink 1s infinite;
&:nth-child(1) {
animation-delay: 0.3333s;
}
&:nth-child(2) {
animation-delay: 0.6666s;
}
&:nth-child(3) {
animation-delay: 0.9999s;
}
}
}
@keyframes blink {
50% {
opacity: 1;
}
}
2)Wave 效果:
核心思想:给 dot 元素增加 transform 属性,设置 translateY 的值将目标元素从下至上垂直重新定位,同时在动画关键帧 keyframes 中对颜色进行调整。
.container {
.dot {
animation: wave 1s infinite;
}
}
@keyframes wave {
0% {
transform: translateY(0px);
background: rgba(148 163 184 / 0);
}
25% {
transform: translateY(-0.25rem);
background: rgba(148 163 184 / 0.8);
}
50% {
transform: translateY(0px);
background: rgba(148 163 184 / 0);
}
75% {
transform: translateY(0.25rem);
background: rgba(148 163 184 / 0.8);
}
100% {
transform: translateY(0);
background: rgba(148 163 184 / 0);
}
}
2)语音气泡效果:
语音气泡是以可视化方式显示对话或思想的一种流行而有效的方法。你可能在漫画、卡通、广告和社交媒体文章中见过它们。它们为设计增添了幽默、情感和个性,同时也为观众提供了语境。此外,语音气泡布局还可以将文字较多的设计分割开来,使其更加吸引人。
核心思想:在 wave 效果的基础上,对 .contianer 容器增加 ::before 和 ::after 两个伪元素来实现左下角的圆圈,同时动画中增加对整个容器的放大和缩小 scale 动画,并采用 ease-out 函数。
.container {
animation: 2s zoom infinite ease-out;
position: relative;
&::before,
&::after {
content: '';
position: absolute;
border-radius: 9999px;
background: rgb(226 232 240);
bottom: 0;
left: 0;
}
&::before {
height: 1rem;
width: 1rem;
transform: translate(-0.125rem, 0.125rem);
}
&::after {
height: 0.5rem;
width: 0.5rem;
transform: translate(-0.5rem, 0.5rem);
}
.dot {
border-radius: 9999px;
height: 0.5rem;
width: 0.5rem;
background: rgba(148 163 184 / 1);
animation: wave 1.2s infinite;
&:nth-child(1) {
animation-delay: 0.4s;
}
&:nth-child(2) {
animation-delay: 0.8s;
}
&:nth-child(3) {
animation-delay: 1.2s;
}
}
}
@keyframes zoom {
50% {
transform: scale(1.1);
}
}
如果本文对您有帮助,欢迎关注、点赞和转发,感谢您的支持!
日常工作中,如下图的聊天场景是不是很熟悉,没错就是我们再熟悉不过的 QQ 和微信,一个正常的聊天界面大致上是长这个样子的:
这种聊天窗口的消息流有两个明显的特点:
一般来说要实现这样的功能,对于前端开发来说都不是难事,只要两步就可以了:
这样的 demo 只需要随手撸二三十行代码就实现了:
一开始渲染消息 1~20,滚到顶部后渲染第二屏消息 ABCDEFGHIJK,看上去前后两屏消息的衔接很平滑很流畅。目前开源社区中也有很多现成的用 React 和 Vue 开发的聊天组件或者示例,他们基本也是用上面提到的思路或者借助 iScroll 实现的。
用上面这种思路跑在 Web 中是没有任何问题的,但是在小程序中的表现却大失所望,看一下用同样的方式应用到小程序后的实际效果:
从第一段视频(左)可以看到从列表进入到聊天页面后设置滚动条位置到底部发生了明显的跳动,先看到停留在顶部然后瞬间再去到底部;
第二段视频(右)滚动到顶部加载后,下一屏消息与当前消息的衔接出现了一个明显的跳动,也是先看到在顶部然后才去到预期的位置。
为什么这个思路在 Web 端体验这么好,到了小程序上体验就如此糟糕呢?原因其实很简单,这是由于小程序底层通信逻辑和视图更新机制造成的:
由于小程序跨线程通信和异步更新的特点,内容的渲染和滚动位置的设置无法保证完成的先后顺序,所以必然会先看到上一个位置一闪而过的画面。
既然是底层的问题,那么这种聊天场景在小程序中难道就玩不了了吗?当然也有尝试过用 opacity 过渡和滚动动画去缓解这种跳动,但都无法从根本上解决这两个体验问题。
当各种常规方案尝试都不尽满意的时候,那就换个思路:从本质上来说,聊天窗口的消息流实际上是一个 “反自然” 的列表,因为在计算机的 “自然界” 和人们习以为常的使用方式上,列表的初始位置都是在最顶部,想要浏览列表更多的内容需要向下滚动,而聊天场景的特点是完全反常规的!
再回到这两个体验问题:为什么需要手动设置最新消息和滚动条到最底部,为什么不让它一开始就在底部?为什么需要要在列表顶部追加数据,为什么不让它在底部追加数据?所以有没有可能颠倒常规,做一个 “反向渲染” 的滚动列表呢?答案是肯定的!
首先像常规的列表一样去渲染,不需要做任何处理,第一条最新消息和滚动条的初始位置是自然地在最上面:
然后把整个列表区域的包裹容器用 CSS 旋转 180°,这样第一条最新消息和滚动条初始位置就在最下面下了:
不过此时整个列表是倒置渲染的,最后再把每一条消息组件用同样的方式旋转 180° 使它们显示回正常的视角,这样就实现了一个 “反向渲染” 的列表:
虽然是 “反向渲染”,但视觉上和正常的一模一样。此时顶部就变成了底部,向上追加数据变成了向下追加数据。最后看一下聊天列表使用 “反向渲染” 之后的体验效果:
可以看到,下拉加载消息与当前消息的衔接非常平滑没有任何的跳动,实际上这个时候历史消息是在底部渲染的,只不过反向渲染让它看上去是在顶部渲染的;此外,页面一进来最新消息和滚动条位置无需任何处理自然地停留在最底部,接近原生体验。
这种 “反向渲染” 的思路用最少的代码就解决了消息场景在小程序上这种几乎无解的问题,并且达到了最优的体验,而实际上核心代码只有两行 CSS:
transform: rotate(180deg);
direction: rtl;
整个过程无需任何手动设置滚动位置和计算第二屏总高度(实际上都不用关心它们),同样这种思路用在 Web 上也是 OK 的。当然用了反向渲染也有一些牺牲,比如 iOS 双击顶部栏回到顶部这个特点就不能用了,但总体来说获得体验上的优化是更多的。
此外,聊天场景中的消息流通常也有这样的布局:
如果视觉上需要将自己和别人的消息方向分别位列两边对齐,那么利用这种 “反向渲染” 的思路,实现起来也非常容易,只需要对消息组件应用不同的 CSS 样式即可:
消息流的每一条消息都是一个单独的组件,此时不需要为了区分不同的视角而去新写一个组件,也不需要改变现有组件的结构布局。
?? 最后
如果你觉得这篇文章对你有帮助,点个「关注/转发」,让更多的人也能看到你的分享!
*请认真填写需求信息,我们会在24小时内与您取得联系。