I give you a way to do it, using the pseudo-element ::before
.
In the html, I would use this structure:
<div class="vineta">
<p class="globo"></p>
</div>
And in the css to the container div we will use it as a reference to position the balloon in some frame coordinates.
.vineta{
position:relative;
width: 100%;
max-width: 600px;
height: 100vh;
max-height: 600px;
/*Opcionalmente con box-shadow, creamos varias sombras, para simular un marco*/
box-shadow:
0 0 0 1px black,
0 0 0 6px white,
0 0 0 7px black;
}
Now would come the balloon, which we position absolutely and some measures (the ones you want), the only weird thing is that I use filter
to generate a shadow, but because this is a little different from how it generates property box-shadow
, you'll see why.
globo{
position: absolute;
width: 200px;
height: 150px;
top: 20px;
left: 80px;
border-radius: 2em;
z-index: 1;
background-color: white;
filter: drop-shadow(0px 0px 1px black) ;
}
Once the balloon is created, we will create the "colita", this is done using ::before
, we create an empty content and position it in reference to the balloon. Here we have to accommodate it according to its measures, being something like this:
Ancho: Xpx;
Alto: =(Ancho);
And depending on how we position it, whether up or down, left or right, is that we play with the coordinates in X
and Y
, like this:
.globo::before{
content: ''; /*o vacío, propiedad necesaria*/
}
.ejemplo-abajo-derecha::before{
left: 50%; /*o lo que consideres*/
bottom: (Ancho) / 2; /*O la mitad del ancho*/
}
.ejemplo-izquierda-arriba::before{
top: 50%; /*o lo que consideres*/
left: (Ancho) / 2; /*O la mitad del ancho*/
}
To add that triangle effect, I prefer to do it with transform: skew (xgrados), like this:
.globo::before{
content: '';
transform: skew(45deg);
}
*, *::before{box-sizing: border-box;}
.vineta{
position:relative;
width: 100%;
max-width: 600px;
height: 90vh;
max-height: 600px;
/*Opcionalmente con box-shadow, creamos varias sombras, para simular un marco*/
box-shadow:
0 0 0 1px black,
0 0 0 6px white,
0 0 0 7px black;
}
.globo{
position: absolute;
width: 200px;
height: 150px;
top: 20px;
left: 80px;
padding: 1.5em;
border-radius: 2em;
font-family: sans-serif;
z-index: 1;
background-color: white;
filter: drop-shadow(0px 0px 1px black) ;
}
.globo::before{
content: '';
position: absolute;
z-index: -1;
width: 10px;
height: 10px;
left: -5px;
top: 50px;
background-color: white;
transform: skewX(45deg);
}
<div class="vineta">
<p class="globo">contenido</p>
</div>
Why use drop-shadow, it is because it covers in shadow the container and what sticks out of it, regardless of the shape, plus that if the element that stands out, has no background color or edges, these are not taken Consider in the shade, an example:
.sombra{
padding: 1em;
display: inline-block;
margin: 10vh;
background-color: whitesmoke;
position: relative;
}
.sombra::before{
content: '';
position: absolute;
display: block;
left: 90%;
top: 10%;
width: 30px;
height: 30%;
border: 10px whitesmoke solid;
border-top: none;
border-radius: 10px;
}
.drop{
filter: drop-shadow(0 0 2px black)
}
.sombra{
box-shadow: 0 0 2px black;
}
<div class="sombra drop">sombra drop</div>
<div class="sombra normal">sombra normal</div>
Update
Now, you can make everything more dynamic, using the custom properties
, to automatically calculate the other measurements based on the width of the tail.
I also discovered how you can achieve the curve, it's just about combining the properties of box-shadow and border-radius, look:
*, *::before{box-sizing: border-box;}
.vineta{
position:relative;
width: 100%;
max-width: 600px;
height: calc(100vh - 30px);
max-height: 600px;
/*Opcionalmente con box-shadow, creamos varias sombras, para simular un marco*/
box-shadow:
0 0 0 1px black,
0 0 0 6px white,
0 0 0 7px black;
}
.globo{
position: absolute;
text-transform: uppercase;
font-size: 12px;
border-radius: var(--borde);
padding: var(--borde);
--borde: 1em;
font-family: sans-serif;
z-index: 1;
background-color: white;
filter: drop-shadow(0px 0px 1px black) ;
}
.globo.i{
width: 150px;
top: 20px;
left: 80px;
}
.globo.ii{
width: 150px;
top: 100px;
left: 20px;
}
.globo.iii{
width: 150px;
top: 60px;
right: 10px;
}
.globo.iv{
width: 150px;
bottom: 10px;
left: 40%;
}
.globo::before{
content: '';
position: absolute;
z-index: -1;
width: var(--colita);
height: var(--colita);
}
.globo.abajo-derecha::before{
--colita: 20px;
left: 50%;
bottom: calc( var(--colita) / -1.5);
transform: skewY(30deg) rotateZ(-30deg);
border-radius: 0 0 0 10em;
box-shadow:
inset calc(var(--colita)/2) calc(var(--colita)/3) 0 0 white;
}
.globo.derecha-arriba::before{
--colita: 20px;
top: 10px;
right: calc( var(--colita) / -1.5);
transform: skewY(30deg) rotateZ(-120deg);
border-radius: 0 0 0 10em;
box-shadow:
inset calc(var(--colita)/2) calc(var(--colita)/3) 0 0 white;
}
.globo.abajo-izquierda::before{
--colita: 50px;
left: 10px;
bottom: calc( var(--colita) / -1.5);
border-radius: 0 0 10em 0;
box-shadow:
inset calc(var(--colita)/-3) calc(var(--colita)/4) 0 0 white;
}
.globo.izquierda-arriba::before{
--colita: 20px;
top: 0;
left: calc( var(--colita) / -1.5);
transform: rotateZ(-60deg);
border-radius: 10em 0 0 0;
color: white;
box-shadow:
inset calc(var(--colita)/3) calc(var(--colita)/-4) 0 0;
}
.globo.yellow::before{
background-color: rgba(255,255,0,.8);
color: rgba(255,2,0,.5);
animation: cambio-color ease 5s infinite both;
}
@keyframes cambio-color{
45%,55% {
background-color: rgba(255,255,255,0);
color: white;
}
}
<div class="vineta">
<p class="globo i abajo-derecha">
abajo-derecha
</p>
<p class="globo ii derecha-arriba">
derecha-arriba
</p>
<p class="globo iii abajo-izquierda">
abajo-izquierda
</p>
<p class="globo iv izquierda-arriba yellow">
izquierda-arriba yellow
</p>
</div>