如何创建类似Facebook Messenger的聊天气泡

18

enter image description here

如何创建像这样的聊天气泡。更具体地说,如何将一个用户类型的两个或多个连续消息作为一个整体分组到一个气泡中。例如:对于发送者 - 第一条消息具有右下角边框 0,中间的消息具有右上、右下为0的边缘半径,最后一条消息具有顶部右侧为0的边缘半径。我必须使用JavaScript还是可以使用CSS实现。

HTML结构可以是:

<ul>
 <li class="him">By Other User</li>
 <li class="me">By this User, first message</li>
 <li class="me">By this User, secondmessage</li>
 <li class="me">By this User, third message</li>
 <li class="me">By this User, fourth message</li>
</ul>

我应该使用什么样的CSS类和样式?


只是想确认一下,您是否能够接受我的答案? - Serg Chernata
4个回答

40

这只是一个基本示例,但应该说明您所需的所有基础知识。

大部分解决方案都在于 + 相邻兄弟选择器。在这种情况下,它被用来为同一人的多条消息中相邻的一行应用不同的边框半径。

ul{
  list-style: none;
  margin: 0;
  padding: 0;
}

ul li{
  display:inline-block;
  clear: both;
  padding: 20px;
  border-radius: 30px;
  margin-bottom: 2px;
  font-family: Helvetica, Arial, sans-serif;
}

.him{
  background: #eee;
  float: left;
}

.me{
  float: right;
  background: #0084ff;
  color: #fff;
}

.him + .me{
  border-bottom-right-radius: 5px;
}

.me + .me{
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
}

.me:last-of-type {
  border-bottom-right-radius: 30px;
}
<ul>
 <li class="him">By Other User</li>
 <li class="me">By this User, first message</li>
 <li class="me">By this User, secondmessage</li>
 <li class="me">By this User, third message</li>
 <li class="me">By this User, fourth message</li>
</ul>


嗨,这正是我想要的...但我想保持简单。有很多嵌套类。但就像你说的,我只想要方向。不过,我会尝试并更新您@SergChernata。 - Raj Nandan Sharma
1
不好意思,这是一个AngularJS项目,所以我无法区分“我”的消息和“他”的消息。它是一个对象数组。我唯一能做的就是添加“他”和“我”的类。 - Raj Nandan Sharma
谢谢大家。我想我明白了,让我试一下。如果我的问题有误导的地方,对不起。我已经有太多的观察者了,所以想要一个 CSS 的解决方案。但是,我想我将不得不使用一些 AngularJS 观察程序来修复这个问题,以及你们提供的 CSS。 - Raj Nandan Sharma
你不能使用类选择器来选取 last-of-type,这样是行不通的。 - Daniel Cooke

2
你需要一个起始和结束类,就像这样:

li {
  border: 1px solid black;
  list-style-type: none;
  margin: 2px 0;
  padding: 2px 5px;
}
.him {
  float: left;
  border-radius: 0 10px 10px 0;
  clear: both;
}
.me {
  float: right;
  border-radius: 10px 0 0 10px;
  clear: both;
}
.him.start {
  border-top-left-radius: 10px;  
}
.him.end {
  border-bottom-left-radius: 10px;  
}
.me.start {
  border-top-right-radius: 10px;  
}
.me.end {
  border-bottom-right-radius: 10px;  
}
<ul>
 <li class="him start">By Other User</li>
 <li class="him">By Other User</li>
 <li class="him end">By Other User</li>
    
 <li class="me start">By this User, first message</li>
 <li class="me">By this User, secondmessage</li>
 <li class="me">By this User, third message</li>
 <li class="me end">By this User, fourth message</li>

 <li class="him start">By Other User</li>
 <li class="him">By Other User</li>
 <li class="him end">By Other User</li>
    
 <li class="me start">By this User, first message</li>
 <li class="me">By this User, secondmessage</li>
 <li class="me">By this User, third message</li>
 <li class="me end">By this User, fourth message</li>

</ul>


2
这里有一个纯CSS的解决方案,但它依赖于您能够检测并应用 chat__bubble--stop 类,当一组中的最后一条消息被发送时。不幸的是,伪类 :last-of-type 不能使用;正如其他人指出的那样,一组中的最后一条消息不一定是对话的最后一条。它还使用了相邻兄弟选择器(+)。

.chat {
  list-style-type: none;
  width: 20em;
}

.chat__bubble {
  margin-bottom: 3px;
  padding: 5px 10px;
  clear: both;
  border-radius: 10px 10px 2px 2px ;
}

.chat__bubble--rcvd {
  background: #f2f2f2;
  color: black;
  float: left;
  border-bottom-right-radius: 10px;
}

.chat__bubble--sent {
  background: #0066ff;
  color: white;
  float: right;
  border-bottom-left-radius: 10px;
}

.chat__bubble--sent + .chat__bubble--sent {
  border-top-right-radius: 2px;
}

.chat__bubble--rcvd + .chat__bubble--rcvd {
  border-top-left-radius: 2px;
}

.chat__bubble--stop {
  border-bottom-right-radius: 10px;
  border-bottom-left-radius: 10px;
}
<ul class="chat">
 <li class="chat__bubble chat__bubble--rcvd chat__bubble--stop">What are you up to?</li>
 <li class="chat__bubble chat__bubble--sent">Not much.</li>
 <li class="chat__bubble chat__bubble--sent">Just writing some CSS.</li>
 <li class="chat__bubble chat__bubble--sent">I just LOVE writing CSS.</li>
 <li class="chat__bubble chat__bubble--sent chat__bubble--stop">Do you?</li>
 <li class="chat__bubble chat__bubble--rcvd">Yeah!</li>
 <li class="chat__bubble chat__bubble--rcvd">It's super fun.</li>
 <li class="chat__bubble chat__bubble--rcvd chat__bubble--stop">... SUPER fun.</li>
</ul>


2
我建议您在创建文本气泡时可以参考以下文章: https://www.templatemonster.com/blog/chat-bubbles-css-ui-tutorial/ 至于起始和结束的气泡,可以使用JQuery来识别并更改它们基于其父容器的CSS属性。 如果您想要发送图片,您需要将它们包裹在li标签内并向右浮动,或者在相对对象(li标签)内使用绝对定位。
<ul class="ulContainer">
  <li>test1</li>
  <li>test1</li>
  <li>test1</li>
</ul>

Css:

.ulContainer li{
  width:200px;
  height:20px;
  background-color:#9abff9;
  list-style-type:none;
  margin:10px 0 10px 0;
  padding: 3px 3px 3px 5px;
  border-radius: 10px 2px 2px 10px;
}

请使用以下脚本更改第一个和最后一个li元素:
$('.ulContainer li:first').css('border-top-right-radius','10px');
$('.ulContainer li:last').css('border-bottom-right-radius','10px');

这是JSFiddle链接:https://jsfiddle.net/s60dgfw2/

根据您的评论更新:

我认为这是在不使用JQuery的情况下实现您想要达到的最接近的方法。您需要使用高级选择器,只有通过JQuery中的.each()语句进行分组才能获得。或者通过向列表添加多个CSS类。

请参见LGSon的回答,了解如何使用多个CSS类来实现。

或者查看以下内容:

https://jsfiddle.net/5dcto0td/

.fancyContainer{
  border: 1px solid #555;
  position:relative;
  width:300px;
  padding:5px;
  overflow:hidden;
}
.chatBox {
  width: 300px;
  list-style: none;
  margin: 0 0 0 -40px;
  position:0;
}

.chatBox li {
  margin: 5px 0 5px 0;
  padding: 3px 5px 3px 5px;
}

/*Set up initial chat element for .me*/
.chatBox .me {
  min-height: 20px;
  float:right;
  clear: both;
  background-color: #34a1ef;
  border-radius: 10px 2px 2px 10px;
}

/*Set up initial chat element for .him*/
.chatBox .him {
  min-height: 20px;
  float:left;
  clear: both;
  background-color: #ddd;
  border-radius: 2px 10px 10px 2px;
}
/*Set up grouped radius*/
.him + .me {
  border-top-right-radius:10px;
}
.me + .him {
  border-top-left-radius:10px;
}
.me + .me {
  border-bottom-right-radius:2px;
}
.him + .him {
  border-bottom-left-radius:2px;
}


/*Set up First and Last radius for .me*/
.chatBox > .me:first-child {
  border-top-right-radius:10px;
}
.chatBox > .me:last-child{
  border-bottom-right-radius:10px;
}

/*Set up First and Last radius for .him*/
.chatBox > .him:first-child{
  border-top-left-radius:10px;
}
.chatBox > .him:last-child{
  border-bottom-left-radius:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="fancyContainer">
  <ul class="chatBox">
    <li class="him">Hello... This is a chatbox.</li>      
    <li class="me">Well well. I guess this is a chatbox.</li>
    <li class="me">I'll have to talk about this some other time.</li>
    <li class="me">No wait. I might change my mind</li>
    <li class="him">Nonesense good sir! We'll have this talk right now and here.</li>
    <li class="him">I Like...</li>
    <li class="him">popsicles.</li>
    <li class="me">I can't believe you've done this to me!</li>
  </ul>
</div>


从外观上看,您所建议的可能需要不同的父<ul>,因为它是一个连续的聊天...并且它具有适当的结构。我无法使用js动态地分组相同的侧面消息。而且这是一个angular js项目。 - Raj Nandan Sharma
你想要实现的目标无法仅通过使用CSS来完成。它需要对每个li元素进行高级分组,包括“我”和“他”。CSS本身不能够在没有像SASS这样的扩展程序的情况下使用单一类别来完成这项任务。但是,你可以通过将多个类别应用于li元素来实现。我已经更新了我的帖子,并提供了最佳解决方案,而不需要使用任何超出单一类别CSS的内容。 - MrAmazing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接