J'ai un projet dans lequel j'ai besoin d'insérer bulles de dialogue/boîtes de message . La forme générale que j'essaie d'obtenir est la suivante:
.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>
Cela ne passe actuellement pas un test de réussite car la bordure transparente est également cliquable.
Objectifs
La zone de texte (zones cliquables/survolables) doit coller aux limites de la forme (les limites transparentes ici sont également survolables, ce qui l'invalide).
J'ai besoin d'afficher la forme sur différents contenus (images, dégradés, texte ...),
Problèmes
Les principaux problèmes que je rencontre lors de la manipulation de cette forme sont les suivants:
Est-il possible de résoudre ces problèmes?
Pour ce faire, vous devriez envisager de modifier votre balisage afin de rendre votre code html plus efficace. Ceci peut être réalisé en utilisant un pseudo-élément. Je vais aborder chaque point individuellement et les regrouper à la fin de ma réponse.
Tout d'abord,
Vous pouvez utiliser un pseudo-élément pour supprimer le supplément .triangle
div. Cela réduit non seulement vos nombres div, mais aide également au positionnement car vous pouvez utiliser les propriétés top:
left:
right:
et bottom:
css afin de vous positionner en fonction de votre élément principal. Cela peut être vu ci-dessous:
.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>
Pour créer votre "test de frappe", vous souhaiterez peut-être utiliser un élément pivoté au lieu d'un hack de bordure.
Quelque chose comme:
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor:pointer;
}
div:before {
content: "";
position: absolute;
top: 100%;
left: 20px;
height: 20px;
width: 20px;
background: black;
transform: rotate(45deg);
transform-Origin:top right;
}
<div>Only element</div>
ou utilisez un pseudo-élément asymétrique:
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor:pointer;
}
div:before {
content: "";
position: absolute;
top: 90%;
left: 20px;
height: 30%;
width: 20px;
background: black;
transform: skewY(-45deg);
transform-Origin:bottom left;
z-index:-1;
}
<div>Only element</div>
qui affichera le pointeur uniquement lorsque le carré ou l'élément principal est survolé . Mais accrochez-vous, cela gâche le positionnement? comment pouvez-vous gérer cela?
Il y a quelques solutions à cela. L'une d'entre elles consiste à utiliser la propriété CSS calc
.
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor:pointer;
}
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);
}
<div>Only element</div>
Vous pouvez maintenant ajouter une bordure assez facilement, simplement en ajoutant une déclaration de bordure à l'élément principal et en définissant les border-bottom
et border-right
du pseudo-élément sur inherit
.
Frontière
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor:pointer;
border:3px double black;
}
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>
Boîte ombre:
Afin d’avoir une ombre de boîte, j’ai utilisé le pseudo-élément :after
afin de masquer l’ombre de la boîte sur l’autre pseudo, faisant ainsi apparaître l’élément comme un élément unique.
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor:pointer;
box-shadow: 5px 5px 10px 2px black;
}
div:before,div:after {
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);
z-index:-1;
box-shadow:inherit;
}
div:after{
box-shadow:none;
z-index:8;
}
<div>Only element</div>
Vous pouvez également ajouter un rayon de bordure à votre boîte de message ou à votre bulle en utilisant à nouveau la propriété 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>
Cela vous permet même de créer non seulement un triangle, mais aussi un cercle.
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% - 13px); /*may require prefix for old browser support*/
top: calc(100% - 13px); /*i.e. half the height + border*/
left: 20px;
height: 20px;
width: 20px;
background: gray;
transform: rotate(45deg);
border:3px double transparent;
border-bottom:inherit;
border-right:inherit;
box-shadow:inherit;
border-radius:50%;
}
<div>Only element</div>
Si vous rencontrez des problèmes de contenu débordant et que vous êtes "caché" derrière ce pseudo-élément et que vous n'êtes pas inquiet au sujet de la présence d'une bordure, vous pouvez utiliser un index z négatif qui résoudra ce problème.
Si vous n'aimez pas l'idée d'utiliser une valeur de calcul, dans laquelle le positionnement dans ma réponse utilise actuellement (pendant que vous travaillez), vous pouvez utiliser transform:translate(50%)
Ce serait une bien meilleure approche, puisque:
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>
Voulez-vous le déplacer? Vous pouvez!
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: 10%;
height: 20px;
width: 20px;
background: gray;
box-sizing: border-box;
transform: rotate(45deg) translate(-50%);
border-bottom: inherit;
border-right: inherit;
box-shadow: inherit;
transition: all 0.8s;
}
div:hover:before {
left: 90%;
}
<div>Only element</div>
Voulez-vous un le droit?
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor: pointer;
border: 3px double black;
border-radius: 10px;
}
div:before {
content: "";
position: absolute;
top: 15%;
left: 100%;
height: 20px;
width: 20px;
background: gray;
box-sizing:border-box;
transform: rotate(45deg) translate(-50%);
border-top: inherit;
border-right: inherit;
box-shadow: inherit;
transition:all 0.8s;
}
div:hover:before{
top:80%;
}
<div>Only Element</div>
Voulez-vous que ce soit une forme de triangle différente?
div {
height: 100px;
width: 200px;
background: gray;
position: relative;
cursor: pointer;
border-radius: 10px;
}
div:before {
content: "";
position: absolute;
top: 70%;
left: 100%;
height: 20px;
width: 20px;
background: gray;
box-sizing:border-box;
transform: translate(-50%) skewX(45deg);
box-shadow: inherit;
transition:all 0.8s;
z-index:-1;
}
div:hover:before{
transform: translate(-50%);
border-radius:50%;
top:20%;
}
<div>Only Element</div>
Cela ne passe pas un test de réussite car la bordure transparente est également cliquable
Cela peut être fait en utilisant les événements de pointeur dans svg.pointer-events:visibleFill;
Ne sélectionnera que la partie où il y a Paint.
Cet exemple utilise filter_box-shadow et n'est pas pris en charge par IE.
Utilise également deux formes.
html,
body {
margin: 0;
padding: 0;
}
.bubble {
width: 150px;
height: 150px;
-webkit-filter: drop-shadow(5px 5px 0px #aaa);
filter: drop-shadow(5px 5px 0px #aaa);
}
.bubble-shape {
fill: #1e1;
}
.shape-text {
color: black;
}
<svg class="bubble" viewBox="0 0 110 110" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
<g class="bubble-shape" style="cursor:pointer; pointer-events:visibleFill;">
<rect x="10" y="10" width="90" height="90" rx="15" ry="15" />
<polygon points="20,94 40,94 30,105" />
</g>
</svg>
Cet exemple utilise un chemin
Devrait être entièrement pris en charge par IE.
html,
body {
margin: 0;
padding: 0;
}
.bubble {
width: 150px;
height: 150px;
}
.bubble-shape {
stroke-width: 15;
stroke: #ddd;
fill: #1e1;
}
.shape-text {
color: black;
}
<svg class="bubble" viewBox="-70 -10 390 370" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
<g style="cursor:pointer; pointer-events:visible;">
<path class="bubble-shape" d="m 0,0 250,0 c 25,0 50,20 50,50 l 0,225 c 0,25 -25,50 -50,50 l -175,0 -25,20 -20,-20 -40,0 c -25,0 -50,-25 -50,-50 l 0,-225 C -50,25 -50,0 0,0 Z" />
</g>
</svg>
J'ai trouvé ce service formidable pour créer des flèches CSS personnalisables . Générez-le et utilisez-le avec n'importe quel bloc.