Bocadillo con flecha

Resuelto jbutler483 asked hace 9 años • 3 respuestas

Tengo un proyecto en el que necesito insertar bocadillos/cuadros de mensajes . La forma general que estoy tratando de lograr es esta:

Bocadillo CSS con flecha o triángulo

.bubble {
  height: 100px;
  width: 200px;
  border: 3px solid gray;
  background: lightgray;
  position: relative;
  cursor:pointer;
}
.triangle {
  width: 0;
  border-top: 20px solid black;
  border-left: 20px solid transparent;
  border-right: 20px solid transparent;
  cursor:pointer;
}
<div class="bubble">Speech bubble
</div>
<div class="triangle">
</div>
Expandir fragmento

Actualmente, esto no pasa una prueba de impacto ya que también se puede hacer clic en el borde transparente.

Objetivos

  • El cuadro de impacto (áreas en las que se puede hacer clic o sobre el que se puede hacer clic) debe atenerse a los límites de la forma (los bordes transparentes aquí también se pueden colocar sobre el cursor, lo que invalida esto).

  • Necesito mostrar la forma sobre varios contenidos (imágenes, calificaciones, texto...),

Asuntos

Los principales problemas que tengo al manipular esta forma son:

  • Tener la capacidad de mover el triángulo alrededor del bocadillo. según la posición del elemento al que se refiere (lados superior/izquierdo/derecho/inferior).
  • agregar un borde o un cuadro de sombra alrededor cuando se necesita énfasis

¿Existe alguna forma de abordar estas cuestiones?

jbutler483 avatar May 18 '15 16:05 jbutler483
Aceptado

Para lograr esto, debería considerar modificar su marcado para que su html sea más eficiente. Esto se puede lograr utilizando un pseudoelemento. Abordaré cada punto individualmente y lo juntaré todo al final de mi respuesta.

En primer lugar,

Utilice pseudoelementos para evitar elementos adicionales.

Podrías usar un pseudo elemento para eliminar el .trianglediv adicional. Esto no solo reduce los números de div, sino que también ayuda con el posicionamiento, ya que puede usar las propiedades top: left: right:y bottom:css para posicionar de acuerdo con su elemento principal. Esto se puede ver a continuación:

.oneAndOnlyDiv {
  height: 100px;
  width: 200px;
  border: 3px solid gray;
  background: lightgray;
  position: relative;
}
.oneAndOnlyDiv:before {
  content: "";
  position: absolute;
  top: 100%;
  left: 20px;
  width: 0;
  border-top: 20px solid black;
  border-left: 20px solid transparent;
  border-right: 20px solid transparent;
}
<div class="oneAndOnlyDiv">Main div</div>
Expandir fragmento


Prueba de éxito

Para crear su "prueba de acierto", es posible que desee utilizar un elemento rotado en lugar de un corte de borde.

Algo como:

Mostrar fragmento de código

o utilice un pseudoelemento sesgado:

Mostrar fragmento de código

que mostrará el puntero solo cuando se coloque el cursor sobre el cuadrado o elemento principal. Pero espera, ¿eso estropea el posicionamiento? ¿Cómo puedes lidiar con eso?

Hay algunas soluciones para eso. Uno de los cuales es utilizar la calcpropiedad CSS.

Mostrar fragmento de código

Agregar un borde

Ahora puedes agregar un borde con bastante facilidad, simplemente agregando una declaración de borde al elemento principal y estableciendo el border-bottomy border-rightdel pseudoelemento eninherit

Borde

Mostrar fragmento de código

Sombra de la caja:

Para tener una sombra de cuadro, he usado el :afterpseudo elemento para ocultar la sombra del cuadro sobre el otro pseudo, haciendo que el elemento parezca un solo elemento.

Mostrar fragmento de código

Poniendolo todo junto

También puedes agregar un radio de borde a tu cuadro de mensaje o bocadillo nuevamente, usando la propiedad border-radius:

div {
  height: 100px;
  width: 200px;
  background: gray;
  position: relative;
  cursor:pointer;
  border:3px double black;
  border-radius:10px;
}
div:before {
  content: "";
  position: absolute;
  top: -webkit-calc(100% - 10px); /*may require prefix for old browser support*/
  top: calc(100% - 10px); /*i.e. half the height*/
  left: 20px;
  height: 20px;
  width: 20px;
  background: gray;
  transform: rotate(45deg);
  border-bottom:inherit;
  border-right:inherit;
  box-shadow:inherit;
}
<div>Only element</div>
Expandir fragmento

Esto incluso te permite crear no sólo un triángulo, sino ¿qué tal un círculo?

Mostrar fragmento de código

Si tiene problemas con el contenido que se desborda y se "oculta" detrás de este pseudoelemento, y no le preocupa tener un borde, puede usar un índice z negativo que resolverá este problema.

¿No te gusta usar 'números mágicos'?

Si no le gusta la idea de usar un valor de cálculo, en el que se usa actualmente la posición en mi respuesta (mientras funciona), es posible que desee usar transform:translate(50%)

Este sería un enfoque mucho mejor, ya que:

  • No necesitas saber el tamaño del borde, ni la mitad del ancho.
  • Hará que su cuadro de mensaje/burbuja sea mucho más dinámico en su posicionamiento y admitirá tamaños adicionales.

div {
  height: 100px;
  width: 200px;
  background: gray;
  position: relative;
  cursor: pointer;
  border: 3px double black;
  border-radius: 10px;
}
div:before {
  content: "";
  position: absolute;
  top: 100%;
  left: 30px;
  height: 20px;
  width: 20px;
  background: gray;
  box-sizing:border-box;
  transform: rotate(45deg) translate(-50%);
  border-bottom: inherit;
  border-right: inherit;
  box-shadow: inherit;
}
<div>Only element</div>
Expandir fragmento

¿Quieres moverlo? ¡Puede!

Mostrar fragmento de código

¿Lo quieres uno correcto?

Mostrar fragmento de código

¿Quieres que tenga una forma diferente de triángulo?

Mostrar fragmento de código

jbutler483 avatar May 18 '2015 09:05 jbutler483

Podemos confiar en clip-pathun filtro de sombra paralela para lograr esto fácilmente:

.box {
  margin: 50px;
  width: 200px;
  height: 100px;
  border-radius: 15px;
  background: red;
  position: relative;
  filter:  /* the more shadow you add the thicker the border will be */
    drop-shadow(0px 0px 1px green) 
    drop-shadow(0px 0px 1px green) 
    drop-shadow(0px 0px 1px green) 
    drop-shadow(0px 0px 1px green) 
    drop-shadow(0px 0px 1px green) 
    drop-shadow(0px 0px 1px green);
}

.box::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 20%;
  height: 30px;
  width: 50px;
  background: inherit;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

.box:hover {
  background:blue;
}

body {
  background:linear-gradient(to right, pink,grey);
}
<div class="box"></div>
Expandir fragmento

Podemos ampliar este ejemplo básico para considerar cualquier tipo de posición y forma de triángulo:

Mostrar fragmento de código

bocadillo con flecha CSS

También podemos considerar cualquier tipo de fondo para toda la forma. El truco funciona para un ancho/alto fijo. La idea es crear un fondo que tenga el mismo tamaño tanto para el elemento principal como para el pseudoelemento, luego simplemente ajustamos la posición del que está dentro del pseudoelemento para que coincida con el del elemento principal (para tener una superposición perfecta).

Mostrar fragmento de código

Bocadillo CSS con fondo aleatorio

Temani Afif avatar Jan 12 '2021 11:01 Temani Afif

SVG

Esto no pasa una prueba de impacto ya que también se puede hacer clic en el borde transparente

Esto se puede hacer usando eventos de puntero en svg.
pointer-events:visibleFill;Sólo seleccionará la parte donde hay pintura.

Este ejemplo usa filter_box-shadow y no es compatible con IE.
También utiliza dos formas.

Mostrar fragmento de código

ingrese la descripción de la imagen aquí

Este ejemplo utiliza una ruta.
IE debería ser totalmente compatible.

Mostrar fragmento de código

ingrese la descripción de la imagen aquí

Persijn avatar May 18 '2015 11:05 Persijn