我的确对 Facebook 聊天行为做了一些钻研。并且我感觉它对各方面的解决极具好看,比方聊天框、图片的解决、援用的解决、头像、状态的变动等。这突破了我“聊天性能太容易了”的固有想法。
解决单张图片
你可能会认为解决不同大小和宽高比的图像所需的工作是一项简略的工作。很多人仿佛会这么做:max-width: 100%
?Facebook 的状况并非如此。
当用户上传图像时,其宽度被增加为内联 CSS,并且利用padding-bottom
(高宽比,当初被广泛应用在元素的本身响应式中)解决图像的响应性。
<a class="image" href="#">
<div class="image__main">
<div class="image__element" style="width: 348.259px;">
<div class="image__aspectRatio" style="padding-bottom: 57.4286%">
<div class="image__wrapper">
<img src="assets/thumb-1.png" alt="">
</div>
</div>
</div>
</div>
</a>
.image {
display: block;
border-radius: 18px;
border: 1px solid #0006;
overflow: hidden;
}
.image__main {max-width: 480px;}
.image__element {
max-width: 100%;
position: relative;
}
.image__aspectRatio {position: relative;}
.image__wrapper {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
.image__wrapper img {
display: block;
max-width: 100%;
max-height: 200px;
width: 100%;
height: 100%;
}
以下是每个图像应遵循的规定:
- 最大宽度为 480px
- 最大高度为 200px
- 调整大小时,图像应放弃雷同的纵横比
- 如果图像小于最大值,则按原样显示它
这里十分 nice 的一点就在于,宽高比是依据所应用的图像动静生成的。
除此之外,重要的是要记住,flexbox 不会将 flex 我的项目放大到其最小内容大小以下。这意味着,如果将浏览器大小调整为特定宽度,flex 项将不会放大到低于其最小内容大小。要解决此问题,咱们须要增加 min-width: 0
。否则,对图片来讲,相对会呈现溢出的状况。
这里若要更进一步钻研,请参考笔者上一篇文章:用户体验思考与 flex 三坑:元素不均分、溢出不省略和垂直不滚动
大的架子根本代码如下:
<div class="message">
<div class="message__outer">
<div class="message__avatar"></div>
<div class="message__inner"> <!-- flex,且 flex: 1,且 row-reverse -->
<div class="message__bubble"></div> <!-- 图片或文字音讯的父元素 -->
<div class="message__actions"></div> <!-- 音讯状态及操作 menu -->
<div class="message__spacer"></div> <!-- 距离元素 -->
</div>
<div class="message__status"></div>
</div>
</div>
其中,flex 项是 message__outer
的间接子项,咱们为其增加message__row
。
.message__row {
min-width: 0;
/* other styles */
}
在笔者和他人探讨时,有人会争执为什么要获取图像的固定宽度并将其增加为内联 CSS?其实很容易想到这与图像的加载无关。否则,如果咱们没有为图像设置固定大小,咱们将留神到布局的变动。
解决多个图像
如果一次性发送多张图片,则不须要思考它们的宽高比。相同,Facebook 将它们作为“一条音讯”。每个图像将蕴含在一个正方形中,并利用 object-fit
防止扭曲或拉伸它们。
.gallery {
display: flex;
flex-wrap: wrap;
flex: 1;
/* Revert the padding to make the gallery aligned
with its siblings. */
margin: -2px;
}
.gallery__item {
/* Add a 2px offset around each image, will result in 4
for two adjacent images. */
padding: 2;
}
.gallery__item--third {flex: 33.33%;}
.gallery__item--half {flex: 50%;}
简略来说,咱们须要这么做:
- 图像网格也是应用 CSS flexbox 构建的。
- 依据图像的数量,图像的宽度值等于其 flexbox 容器的 1 / 3 或 1 /2(有最多可发送图片数量)。
- 间距通过每个图像父级上的填充进行解决。
- 为防止在库的边缘四周呈现不必要的间距,应在 flex 容器上应用等于
padding
的负边距值。
我想强调每个我的项目之间的间距的应用。在这种状况下,padding: 2px
甚至更有用,因为它在 LTR 和 RTL 方向上都无效。
其中,最重要的还是如何高性能的判断图片的展现构造了 —— 尽管不晓得 Facebook 团队是如何解决图片和文字音讯的。然而如果是我,必然是将两者离开,分心打造一个图片选择器组件。这个还在设计中,我仿佛思考了太多以至于难以下手。
文字音讯
除了图片,Facebook 对于文字音讯的展现也是“标新立异”。具体表现在单条音讯、间断多条音讯、混合音讯、援用音讯的款式都有不同。
比方单条音讯时是这样的:
而间断发送多条音讯时,根本是这种状态:
而且,用户体验并非止步于此。如果你应用的是LTR
(从左到右,例如英语)布局,那么发送方是蓝色气泡,接管方是灰色气泡(在你这边看);如果布局是RTL
(从右到左,如阿拉伯语),则反之亦然。
当然还要以下面提到的“大的架子”HTML 构造为基准。它的 css 是这样的:
.message__outer {display: flex;}
.message__inner {
flex: 1;
display: flex;
flex-direction: row-reverse;
}
.message__actions {
width: 67px;
padding-right: 5px;
}
.message__spacer {flex: 1;}
其中 actions
是操作菜单。笔者认为在这里增加固定宽度的起因是:
- 为其保留空间以防止布局偏移。
- 更好地管制外部布局。例如,聊天气泡应具备
max-width
,咱们可能须要从中扣除操作菜单宽度。
为了确保在较小的尺寸上不会呈现问题,咱们须要留神以下几点:
- 思考到默认宽度因空间有余而坍塌的状况;
- 避免音讯操作以较小的大小膨胀;
- 通过突破很长的单词来防止溢出;
.message__bubble {max-width: calc(100% - 67px);
overflow-wrap: break-word;
}
.message__actions {flex-shrink: 0;}
对于文字音讯来说,因为要思考语种的问题,咱们能够为其加上 dir
属性值:
<div dir="auto"></div>
如果第一个文本是用 RTL
语言编写的(例如:阿拉伯语),则文本将从右到左浏览,即便你在此之后输出了 LTR
文本也是如此。
如果以 LTR
格局输出文本(例如:英语),则文本将从左到右浏览。
对于下面说的多个气泡不同的圆度状态的问题,咱们还要留神到对于发送方和接管方而言,它们会有所不同。除此之外,它们将依据页面方向翻转(LTR 与 RTL)。
/* 设置非凡角弧度,个别是 18px,非凡角是 4px */
/* You, blue messages */
/* First message */
.message--first .message__bubble {border-end-end-radius: 4px;}
/* Middle message */
.message--middle .message__bubble {
border-start-end-radius: 4px;
border-end-end-radius: 4px;
}
/* Last message */
.message--last .message__bubble {border-start-end-radius: 4px;}
这里用到了 css 某些属性的“双精度写法”。因为在布局发生变化时,内联开始和内联完结将翻转。这样,咱们就不用关怀其方向 —— 所以,其实你还能够用这样的写法:border-radius: 左上 右上 右下 左下;
对于文字音讯来说,须要有操作按钮用以进行撤回等行为。就像这样:
Facebook 采纳了这样的伎俩:
- 它的右侧有填充,以防您发送音讯。否则,填充位于左侧;
- 它通过
flex-direction: row-reverse
和发送方音讯的默认程序进行翻转;
如果音讯太长,或者是图像或视频,则操作菜单应垂直居中。这能够通过应用弹性框对齐来实现。
<div class="message__actions">
<ul class="menu"></ul>
</div>
.message__actions {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 67px;
padding-right: 5px;
}
当邮件具备长文本或图像时,元素将拉伸以填充其父高度。
留神,这里是“垂直居中”,而并非“垂直排列”。这一点让我有些费解。这个时候变为垂直排列难道不会更好一点么?
说到这了,有一个并没有说到然而仿佛很容易就想到的问题:距离元素是干嘛的?不便翻转!
最初,作为 Facebook,怎么能没有主题色性能呢?他们的工程师仿佛对在气泡上加渐变色十分看好,尽管在我看来,,,一言难尽。然而十分牛逼!
这是通过 css 实现的!笔者一开始认为是依附相似滚动视差或者纯 js 实现的,但起初发现我小了,格局小了~
如果说咱们有这样的背景色:
.messages-parent {
background-color: #3a12ff;
background-image: linear-gradient(#faaf00, #ff2e2e, #3a12ff);
}
对,没错。就是对整个父元素增加的。
而后从每个邮件气泡中删除背景色和边框半径。
下一步,咱们须要将红色背景增加到 UI 中除聊天气泡之外的所有内容。
.message__actions,
.message__status,
.spacer-xs,
.spacer-lg,
.message__spacer,
.message__avatar {background-color: #fff;}
当初咱们曾经解决了聊天气泡,咱们如何将圆角增加回去?伪元素!!!
.custom-theming .message__bubble {
position: relative;
border-radius: 0;
background: transparent;
}
.custom-theming .message__bubble::after {
content: "";
position: absolute;
left: -36px;
right: -36px;
top: -36px;
bottom: -36px;
border: 36px solid #fff;
}
当初有 border
了,然而外面的局部还是直角。接下来,咱们须要编辑内圆角。家喻户晓,它有一个公式:内半径 = 边框半径 – 边框宽度
这意味着,即便加上上述内容,内角仍将为零。如果没有自定义主题,边框半径为 border-radius: 36px 18px
。为了在内半径上反映这一点,咱们须要给伪元素增加border-radius
。使得 内半径 = 54px - 36px = 18px
于是有:
.custom-theming .message__bubble {
position: relative;
border-radius: 0;
background: transparent;
}
.custom-theming .message__bubble::after {
content: "";
position: absolute;
left: -36px;
right: -36px;
top: -36px;
bottom: -36px;
border-radius: 54px;
border: 36px solid #fff;
}
最初,咱们须要在音讯气泡范畴内限度伪元素大小。
.custom-theming .message__bubble {
position: relative;
border-radius: 0;
background: transparent;
overflow: hidden; /** !!! **/
}
最初一步是将 border-color
更改为红色,这里咱们的确该当借助 background-attachment
因为咱们须要让色彩在滚动中绝对放弃。
.messages-parent {
background-color: #3a12ff;
background-image: linear-gradient(#faaf00, #ff2e2e, #3a12ff);
background-attachment: fixed;
border-left: 2px solid #fff;
borfer-right: 2px solid #fff;
}
最初的最初,拜拜~