Cartoon Balloon with CSS?

6

I am looking to generate a cartoon balloon with CSS, that is, a dialogue balloon with text and a "tail" of the style that appears in comics. The solution where possible, so that the "tail" of the globe has a rounded look, as shown in the image:

I found a way that I'm posting as an answer . But how could the proposed Cartoon Globe design be improved?

    
asked by Leandro hereñu 12.02.2018 в 22:04
source

3 answers

5

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>
    
answered by 12.02.2018 / 23:08
source
1

You really would not need so many elements to be able to make the tab of the bullet. It would be enough to use the pseudo-element :before on the div on which you have the bullet.

In this case, to simulate the triangle, I used margins, since using width: 0 and height: 0 each of the margins tends to form a triangle the larger we do it.

Finally, to center the text within the div both vertically and horizontally you could use flexbox to centen it vertically using the property align-items: center and, as it is a text, you can center it using text-align: center; .

Note: I have used transform: rotate() to give you an inclination that will be consistent with the corner of your balloon.

Example:

#historieta{
  display: flex;
  text-align: center;
  align-items: center;
  position: relative;
  top: 40px;
  width: 120px;
  height: 80px;
  background-color: blue;
  border-radius: 25px;
}

#historieta:before{
  content: "";
  position: absolute;
  top: 65px;
  left: 95px;
  width: 0px;
  height: 0px;
  border-top: 20px solid blue;
  border-right: 20px solid transparent;
  border-left: 20px solid transparent;
  transform: rotate(75deg);
}
<div id="historieta">
  <span>Esto es una prueba</span>
</div>
    
answered by 12.02.2018 в 23:15
0

I leave here my answer as a response but I would like to know how you would do it, especially with the Delta (Cola) of the Globe, since in this case I had to use several Div in order to create it ...

.globo-historieta-container {
  position: relative;
  width: 250px;
  height: 150px;
  margin: 0 auto;
}

.globo-historieta {
  position: relative;
  width: 250px;
  height: 150px;
  background-color: darkblue;
  color: white;
  border-radius: 75px;
  text-align: center;
  padding: 60px 0px 0px 0px;
}

.globo-historieta-dialogo {
  position: absolute;
  bottom: 5px;
  right: 5px;
  content: '';
  width: 0;
  height: 0;
  border-top: 60px solid transparent;
  border-right: 60px solid darkblue;
  font-size: 0px;
  border-bottom-left-radius: 60px;
}

.border-rigth {
  position: absolute;
  bottom: -6px;
  right: -42px;
  width: 60px;
  height: 60px;
  background-color: white;
  border-bottom-left-radius: 40px;
}
<!-- PRUEBAS FORMAS -->

<div class="container">
  <!-- GLOBO DE HISTORIETA -->
  <div class="row">


    <div class="globo-historieta-container">
      <div class="globo-historieta-dialogo"></div>
      <div class="border-rigth"></div>
      <div class="globo-historieta">
        <span>Esta es una historieta</span>
      </div>
    </div>

  </div>
</div>
    
answered by 12.02.2018 в 22:05