8.0「裂开」「」的特效代码
8.0 更新的⼀⼤特⾊就是⽀持动画表情,如果发送消息只有⼀个内置的表情图标,这个表情会有⼀段简单的动画,⼀些特殊的表情还有全屏特效,例如烟花表情有全屏放烟花的特效,表情有爆炸动画并且消息和头像也会随之震动。本着作为前端⼯程师的职业精神,我就想看看能不能实现⼀个类似的特效。折腾许久之后,做出来的效果如下:
项⽬的核⼼是使⽤到了 lottie 动画库。Lottie 是 Airbnb 出品的、全平台(Web、Android、IOS、React Native)的动画库,它的特点在于能够直接播放使⽤ Adobe After Effects 制作的动画。设计师在 After Effects 中,利⽤ Bodymovin 插件把动画导出为 JSON 格式之后,开发者就能够通过相应平台的 SDK 进⾏播放。
在做完这个项⽬之后我感觉到⾃⼰的前端储备⼜丰富了⼀层,在以后应对复杂特效时⼜有了新的思路,如果你也想进⼀步提升前端开发技能,可以跟着这篇⽂章实践⼀下。本篇⽂章除了使⽤ lottie 库之外,全部都是使⽤原⽣ HTML/CSS/JavaScript 实现的,这样⽆论你是React、Vue 还是其它⼯程师,都可以快速掌握。
⼀、编写界⾯
本来想跳过 HTML/CSS 部分,但是想到 CSS 可能是⼤部分⼈的弱项,所以我决定还是把实现界⾯的思路写⼀下,想看核⼼部分的可以直接跳到:⼆、发送普通消息部分。
1. HTML 部分
⾸先看 HTML 部分,从效果图来看:
上边有⼀个标题栏,显⽰与 XXX 聊天。
中间是聊天信息⾯板,包含着双⽅发送的消息,每条消息由发送者头像和消息内容组成,我发送的在右侧,对⽅发送的在左侧。
下⽅是底部信息,有表情选择按钮、编辑消息⽂本框和发送按钮。
那么根据这个结构编写的 HTML 代码如下所⽰:
<div class="chat">
<div class="titleBar">与 XXX 聊天</div>
<div class="panel">
<div class="message mine">
<img src="./me.png"alt=""/>
<p><span>你好</span></p>
</div>李响个人资料
<div class="message yours">
<img class="avatar"src="./you.png"alt=""/>
<p><span>Hi</span></p>
</div>
<!-- 省略其它消息 -->
</div>
<footer>
<button class="chooseSticker">
<img src="./emoji.svg"alt=""/>
<div class="stickers"></div>
</button>龙俊亨 具荷拉
<input
class="messageInput"
type="text"
name=""
id=""
无领导小组面试
placeholder="请输⼊聊天信息"
/>
<button class="send">发送</button>
</footer>
</div>
</main>
各个元素所对应的界⾯部分为:
<main /> 元素是⼀个整体的容器,⽤于把聊天窗⼝居中对齐
<div class="chat"> 是聊天应⽤的容器,⽤于布局标题栏、聊天⾯板和底部发送框。
<div class="titleBar"> ⽤于显⽰标题栏。
<div class="panel"> 是消息⾯板,⽤于布局其中的消息。
<div class="message"> 为消息容器,使⽤不同的 class 来区分发送⽅, mine 代表我发送的, yours 代表对⽅发送的。每条消息⾥边使⽤ <img class="avatar" > 来展⽰头像,使⽤ <p> 元素来显⽰⽂本, <p> 元素⾥边的 <span> 元素将会作为 lottie 的容器来播放表情动画。
<footer> ⽤于布局底部操作按钮和消息发送框。其中:
<button class="chooseSticker"> 是表情选择按钮,使⽤⼀个笑脸 svg 图⽚表⽰,⾥边的
立冬问候语短句
是表情选择框弹出层,⾥边的表情将在 JS 中动态加载,⽬的是为了实现动画预览。
<input class="messageInput" /> 是聊天消息输⼊框,没什么特别的。
<button class="send"> 是发送按钮
这个是 HTML 的基本结构,接下来看⼀下 CSS 样式。
2. CSS 部分
在项⽬根⽬录下创建⼀个 style.css ⽂件并在 index.html 的 标签中引⼊:
<link rel="stylesheet"href="style.css"/>
1)全局样式
⾸先定义⼀些 CSS 变量,CSS 变量是为了⽅便我们引⽤同⼀属性值的,后边如果更新样式时,可以避免多次修改:
赵本山杀人被抓--primary-color:hsl(200, 100%, 48%);
--inverse-color:hsl(310, 90%, 60%);
--shadow-large: 0 0px 24px hsl(0, 0%, 0%, 0.2);
--shadow-medium: 0 0 12px hsl(0, 0%, 0%, 0.1);
}
这些变量的含义分别是:
primary-color: hsl(200, 100%, 48%) ,主⾊调,例如我发送的消息的蓝⾊背景。
inverse-color: hsl(310, 90%, 60%) ,反⾊调,或强调⾊调,与主⾊调形成鲜明对⽐,例如发送按钮的背景⾊。
shadow-large: 0 0px 24px hsl(0, 0%, 0%, 0.2) ,⼤阴影,例如标题栏、底部栏的阴影。
shadow-medium: 0 0 12px hsl(0, 0%, 0%, 0.1) ,⼩阴影,例如输⼊框和表情选择弹出层。
接下来是⼀些重置样式:
*{
box-sizing: border-box;
padding: 0;
margin: 0;
font-family: Helvetica, "PingFang SC", "Microsoft Yahei", sans-serif;
}
这些样式对所有元素都有效,设置盒⼦模型为 border-box ,这样内边距、边框都算在宽⾼之内,设置内间距和外间距为 0,最后设置默认字体。
2)Main 容器
Main 容器⽤于定位聊天应⽤容器到浏览器中间,使⽤ grid 布局,宽⾼分别设置为浏览器可视区域的 100%,并把背景⾊设置为⿊灰⾊:
main{
display: grid;
place-items: center;
width: 100vw;
height: 100vh;
background-color:hsl(0, 0%, 10%);
}
3)聊天应⽤容器
聊天应⽤容器设置了固定宽⾼,模拟⼿机屏幕,并使⽤ grid 布局来控制标题栏、聊天⾯板和底部操作栏的位置:
.chat{
width: 375px;
height: 700px;
background:hsl(0, 0%, 100%);
border-radius: 8px;
display: grid;
grid-template-rows: max-content 1fr max-content;
}
这⾥使⽤了 grid-template-rows 把聊天应⽤分成了 3 ⾏,第⼀⾏的标题栏和最后⼀⾏的标底部操作栏的⾼度分别为内容的最⼤⾼度,中间的聊天⾯板则是浮动⾼度。战魂铭人合成
4)标题栏
标题栏简单的设置了⼀个内间距、⽂字居中⽅式和阴影:
padding: 24px 0;
text-align: center;
box-shadow:var(--shadow-large);
}
界⾯优化提⽰:内间距⽤来增加留⽩,在视觉上引起放松,阴影则为了和下边的聊天⾯板区分开
5)聊天⾯板
聊天⾯板使⽤ flex 布局对其中的消息进⾏排列,并设置⽅向为按列排布,然后设置 overflow 为 auto,在消息整体⾼度超出⾯板⾼度时,出现滚动条:
.panel{
display: flex;
flex-direction: column;
padding: 24px 12px;
overflow: auto;
}
界⾯优化提⽰:这⾥的 padding 同样是为了留出⾜够多的空⽩,来与其它元素隔开⼀段距离,以避免拥挤感。
6)消息
消息分为消息容器、头像和消息体 3 个部分。其中消息体和头像包含在消息容器中,先来看消息容器的样式。消息容器使⽤ flex 布局来把消息体和头像放在⼀⾏,宽度最⼤为⾯板宽度的 80%,并设置字体和外边距:
.message{
display: flex;
max-width: 80%;
font-size: 14px;
margin: 8px 0;
position: relative;
}
这⾥的 position 设置为 relative 是为了定位后边的全屏特效动画。
头像简单设置了宽⾼、圆⾓和距离消息体的间距:
.message img{
width: 40px;
height: 40px;
border-radius: 12px;
margin-right: 12px;
}
界⾯优化提⽰:这⾥不得不再提⼀下间距的重要性,⼀定不要把各个元素安排的太过紧凑,否则⼗分影响视觉效果,最直接的影响就是引起视觉上的拥挤感,造成视觉疲劳。
消息体同样的设置了间距和圆⾓,这⾥的圆⾓和头像的保持⼀致,以增加和谐感。它还设置了阴影,并使⽤ flex 布局,把⾥边的⽂字或表情消息居中对齐:
.message p{
padding: 8px 12px;
border-radius: 12px;
box-shadow:var(--shadow-large);
display: flex;
align-items: center;
}
这些样式默认都是基于对⽅的消息的,如果是我发送的消息需要放到右边,并作⼀些调整。⾸先对于我发送的消息,把 flex-flow 改为
row-reverse 这样头像和消息体的位置就互换了,然后使⽤ align-self 对齐到⾯板的右边:
.message.mine{
flex-flow: row-reverse;
align-self: flex-end;
}
调整头像的外边距,现在应该是距离左边的消息体的边距了:
.message.mine img{
margin-right: 0;
margin-left: 12px;
}
设置消息体的背景⾊为蓝⾊,⽂字为⽩⾊:
.message.mine p{
background-color:var(--primary-color);
color: white;
}
7)底部操作栏
先看底部操作栏容器的整体布局,使⽤ grid 布局把表情选择按钮、消息发送框和发送按钮分成 3 列,其中除消息发送框为浮动宽度外,其它的两个按钮为固定宽度,默认居中对齐,最后设置阴影和间距:
footer{
display: grid;
grid-template-columns: 48px 1fr 75px;
justify-items: center;
padding: 12px;
box-shadow:var(--shadow-large);
}
表情选择按钮把⾃⼰进⾏了靠左对齐,并设置相对定位,⽤于定位表情选择弹出层,然后设置按钮图标的⼤⼩:
.chooseSticker{
justify-self: start;
position: relative;
}
.chooseSticker img{
width: 36px;
height: 36px;
}
表情选择弹出层的 CSS 代码⽐较多但都很简单,先看⼀下代码:
.stickers{
display: grid;
grid-template-columns:repeat(auto-fill, 24px);
column-gap: 18px;
border-radius: 8px;
background-color: white;
box-shadow:var(--shadow-medium);
padding: 6px 12px;
font-size: 24px;
position: absolute;
top:calc(-100% - 18px);
width: 300px;
opacity: 0;
}