JSFiddle - React, Tailwind, and code Playground
by Soviut
HTML
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>BR</div>
<div class="bubble br" style="top: 25%; left: 25%;">testing bubble<br/>BR</div>
</div>
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>BM</div>
<div class="bubble bm" style="top: 25%; left: 25%;">testing bubble<br/>BM</div>
</div>
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>BL</div>
<div class="bubble bl" style="top: 25%; left: 25%;">testing bubble<br/>BL</div>
</div>
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>TR</div>
<div class="bubble tr" style="top: 25%; left: 25%;">testing bubble<br/>TR</div>
</div>
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>TM</div>
<div class="bubble tm" style="top: 25%; left: 25%;">testing bubble<br/>TM</div>
</div>
<div class="panel">
<div class="bubble ghost" style="top: 25%; left: 25%;">testing bubble<br/>TL</div>
<div class="bubble tl" style="top: 25%; left: 25%;">testing bubble<br/>TL</div>
</div>
CSS
* {
box-sizing: border-box;
}
.panel {
position: relative;
width: 480px;
height: 270px;
background: #CCC;
}
.panel + * {
margin-top: 10px;
}
.ghost {
opacity: 0.5;
}
.bubble {
position: absolute;
padding: 5px;
background: #FFF;
text-align: center;
}
.bubble:after {
content: '';
position: absolute;
border-style: solid;
border-width: 10px;
border-color: transparent;
}
.br {
-webkit-transform: translate(calc(-100% + 10px + 5px), calc(-100% - 10px));
}
.br:after {
bottom: -10px;
right: 5px;
width: 0;
height: 0;
border-top: 10px solid #FFF;
border-bottom: 0;
}
.bm {
-webkit-transform: translate(-50%, calc(-100% - 10px));
}
.bm:after {
bottom: -10px;
left: 50%;
width: 0;
height: 0;
border-top: 10px solid #FFF;
border-bottom: 0;
-webkit-transform: translate(-50%, 0);
}
.bl {
-webkit-transform: translate(calc(0% - 10px - 5px), calc(-100% - 10px));
}
.bl:after {
bottom: -10px;
left: 5px;
width: 0;
height: 0;
border-top: 10px solid #FFF;
border-bottom: 0;
}
.tr {
-webkit-transform: translate(calc(-100% + 10px + 5px), 10px);
}
.tr:after {
top: -10px;
right: 5px;
width: 0;
height: 0;
border-top: 0;
border-bottom: 10px solid #FFF;
}
.tm {
-webkit-transform: translate(-50%, 10px);
}
.tm:after {
top: -10px;
left: 50%;
width: 0;
height: 0;
border-top: 0;
border-bottom: 10px solid #FFF;
-webkit-transform: translate(-50%, 0);
}
.tl {
-webkit-transform: translate(calc(0% - 10px - 5px), 10px);
}
.tl:after {
top: -10px;
left: 5px;
width: 0;
height: 0;
border-top: 0;
border-bottom: 10px solid #FFF;
}