1

I've written coded some speech bubble for displaying hints on what to do in a smartphone app. It shall be responsive, hence I chose to use CSS ... However, there are some issues with it. The "pointing" part of the speech bubble (which is added with a ::before or ::after) has a little gap, when it's animated. And the invisible region of the pointing part is also quite huge. Since this is on top of the elements to be clicked/touched on, it prevents the action, if the user touches exactly where the pointer points to.

This is issue #1 (Gap between rounded box and triangle/pointing part; only during animation.. because both parts seem to be moved separately):

enter image description here

This is issue #2 (Too large invisible bounding box, that overlays the button; Yellow region in the following image, this prevents the button to be clicked if the user touches that invisible region):

enter image description here

I mainly need to reduce this invisible region (Issue #2).

My current solution can be found at: https://jsfiddle.net/1mw0g79a/ or just below. Please keep the usage of "vh", "vw" and "%" for size related measures in the CSS, as this is how I ensure a similar look of the app on different devices... This is also the reason why I cannot simply use 'any' open source solution for speech bubbles out there.

The HTML:

<html><head><title>...</title></head><body>
  <div id="button" class="button">Button</div>
  <div id="hint" class="bubble downwards">
    Hello! I'm a hint message...
  </div>
</body></html>

And the CSS:

.bubble {
  position: fixed;
  top: 33.5vh;
  left: 3vw;
  max-width: 90vw;
  width: 90vw;
  z-index: 10000;

  background-color: #00000088;
  color: white;
  font-size: 2.3vh;
  padding: 2vh 2vw;
  border-radius: 2vh;
  box-shadow:   0 1vh 1vw rgba(0, 0, 0, .3), 0 0.1vh 0.2vw rgba(0, 0, 0, .2);

  display: flex;
  align-content: center;

  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-name: bounce;
  animation-timing-function: ease;
}
.bubble.downwards::after {
  content: '';
  position: absolute;
  width: 0;
  height: 3vh;
  bottom: -9vh;
  border-top: none;
  left: 40vw;
  border: 3vh solid transparent;
    z-index: 10001;

  border-top-color: #00000066;
  filter: drop-shadow(0 1vh 1vw rgba(0, 0, 0, .3)), drop-shadow(0 0.1vh 0.2vw rgba(0, 0, 0, .2));
}
@keyframes bounce {
    0%   { margin-top: -0vh; }
    50%  { margin-top: -1vh; }
    100% { margin-top: 0vh; }
}
.button {
  border-radius: 0.5vh;
  background-color: #aaa;
  font-size: 2.3vh;
  padding: 1vh;
  text-align: center;
}

#button {
  position: absolute;
  top: 40vh;
  width: 20vw;
  left: auto;
  right: auto;
}

#hint {
  top: 30vh;
  left: 3vw;
}
#hint::after {
  left: 5vw;
}
SDwarfs
  • 3,189
  • 5
  • 31
  • 53
  • 1
    I would advice considering a different idea to create the arrow, example: https://stackoverflow.com/a/61985194/8620333 – Temani Afif Jun 01 '20 at 23:19
  • @TemaniAfif Thank you for the Link. I'll have a closer look at it. This seems even to work fine together with the shadow, which did not work for the arrow/triangle part for some reason. – SDwarfs Jun 02 '20 at 01:41

1 Answers1

1

I used transform because I wanted it to be smoot when using animation. And that's how you can make triangle. It will also be responsive and will be positioned in the middle for each dimension. Triangle will now take up just as much space as its own and will not have a negative impact on the button.

  
.bubble {
    position: fixed;
    top: 33.5vh;
    left: 3vw;
    max-width: 90vw;
    width: 90vw;
    z-index: 10000;
  
    background-color: #00000088;
    color: white;
    font-size: 2.3vh;
    padding: 2vh 2vw;
    border-radius: 2vh;
    box-shadow:   0 1vh 1vw rgba(0, 0, 0, .3), 0 0.1vh 0.2vw rgba(0, 0, 0, .2);
  
    display: flex;
    align-content: center;
  
    animation-duration: 2s;
    animation-iteration-count: infinite;
    animation-name: bounce;
    animation-timing-function: linear; /* changed  */
 
  }

  @keyframes bounce { /* created  */

    0%   { transform: translateY(0) }
    50%  { transform: translateY(-20px) } 
    100% { transform: translateY(0) }
}


  .bubble.downwards::after { /* created */
    content: '';
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 30px 30px 0 30px; /* you can adjust it for any size you want*/
    border-color: gray transparent transparent transparent;
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
  };
  
  

  .button {
    border-radius: 0.5vh;
    background-color: #aaa;
    font-size: 2.3vh;
    padding: 1vh;
    text-align: center;
  }
    
<div id="button" class="button">Button</div>
  <div id="hint" class="bubble downwards">
    Hello! I'm a hint message...
  </div>
CanUver
  • 1,756
  • 2
  • 6
  • 19
  • Nice! the "transform: translateY()" fixes the rendering (Issue #1). I used "-1vh" instead of your "-20px" to keep it relative to viewport size. On mobile devices the screen resolution seems crazily different. So this works better for me than "px"-measures. I kind of selectively copy&pasted your solution for issue #2 (bounding box), without totally understanding it. Could you explain your adaptions, please? – SDwarfs Jun 02 '20 at 02:00
  • 1
    Sure. The "yellow parts" you mentioned for the solution you made were because of the height of your shape. I have created a shape that is completely bound to the border that you give dimensions that are not your own self height. So it'll only work on the scale we set. Actually, what caused the triangle shape is all about border colors. There are shapes, but I just set them up so they don't show. To see this better and to test what border colors do, you can change each one and look at the result, so I'm sure you'll understand more clearly how it works. I hope I could hopefully descriptive. – CanUver Jun 02 '20 at 10:36
  • Thanks for the description. Used your solution as a template. Seems the important part is to set width/height to 0, and only use the border width setting to change the size, use the border-color to only enable the needed part of the border (which are in fact 4 triangles due to the width/height of 0) and set the other 3 triangles to transparent. The "border-bottom-width: 0" removes unneeded space of the unneeded triangle. Then use top/left/transform to use %-measures to place it correctly, so it adapts to the size of the div with the text. Works perfect (except for the still missing shadow). – SDwarfs Jun 03 '20 at 16:29