<div class="notes">New & Improved! If there are multiple images, they work independently. So you can open a label in
both images below.</div>
<div class="container">
<div class="lg-container">
<img class="lg-image"
src="https://images.pexels.com/photos/162616/coffee-work-desk-mug-keyboard-162616.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260" height="750" width="1260" />
<div style="top: 20%; left: 19.9%;" class="lg-hotspot lg-hotspot--top-left">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>This is the title</h4>
<p>This is some text that goes in the label. It describes the item. Here is a <a href="/abcretrograde/pens/showcase" target="_blank">link</a> to another page.</p>
</div>
</div>
<div style="top: 25%; left: 88%;" class="lg-hotspot lg-hotspot--top-right">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Keyboard</h4>
<p>
A keyboard has letters, and it can write letters. Let's say some more things about keyboards so the text wraps
to multiple lines.
</p>
</div>
</div>
<div style="top: 15.5%; left: 66%;" class="lg-hotspot lg-hotspot--top-right">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Envelopes</h4>
<p>These can hold letters, bills, and junk mail.</p>
</div>
</div>
<div style="top: 62%; left: 15%;" class="lg-hotspot lg-hotspot--bottom-left">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Coffee</h4>
<p>Yay coffee!</p>
</div>
</div>
<div style="top: 85%; left: 73%;" class="lg-hotspot lg-hotspot--bottom-right">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<p>This is a label without a title.</p>
</div>
</div>
</div>
<div class="lg-container">
<img class="lg-image"
src="https://images.pexels.com/photos/39317/chihuahua-dog-puppy-cute-39317.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260" height="750" width="1260" />
<div style="top: 21%; left: 93%;" class="lg-hotspot lg-hotspot--top-right">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Fence</h4>
<p>
It's a fence to keep pupper safe.
</p>
</div>
</div>
<div style="top: 60%; left: 25%;" class="lg-hotspot lg-hotspot--top-left">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Grass</h4>
<p>Feels good on pupper's paws.</p>
</div>
</div>
<div style="top: 13.5%; left: 58%;" class="lg-hotspot lg-hotspot--top-right">
<div class="lg-hotspot__button"></div>
<div class="lg-hotspot__label">
<h4>Smol boi</h4>
<p>
Smol boi is a good pupper.
</p>
</div>
</div>
</div>
</div>
@import url("https://fonts.googleapis.com/css?family=Open+Sans");
$buttonRadius: 24px;
$labelPaddingX: $buttonRadius * 1;
$labelBorderRadius: 2px;
$labelFade: 0.1s;
$colorButton: #ff6000;
$colorButtonHover: #ff774c;
$colorText: #333;
$colorHeadingBackground: #555;
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.notes {
margin: auto;
padding: 2rem 1.2rem 0;
max-width: 35rem;
font-family: Open Sans, sans serif;
text-align: center;
}
.container {
width: 100%;
padding: 1em;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: center;
}
.lg-container {
max-width: 550px;
position: relative;
margin: 1rem;
padding: 0;
}
.lg-image {
display: block;
height: 100%;
width: 100%;
object-fit: scale-down;
}
.lg-hotspot {
position: absolute;
margin: 0;
padding: 0;
transform: translate(-50%, -50%);
z-index: 0;
&:hover,
&:active {
.lg-hotspot__button {
border-color: $colorButtonHover;
&:after {
background-color: $colorButtonHover;
}
}
}
&--selected {
z-index: 999;
.lg-hotspot__label {
opacity: 1;
}
}
&__button {
height: $buttonRadius * 2;
width: $buttonRadius * 2;
padding: 0px;
border-radius: 100%;
border: 1px solid $colorButton;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 999;
animation: button-pulse 7s ease-in-out infinite;
cursor: pointer;
&:after {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
content: "";
display: block;
height: $buttonRadius * 0.7;
width: $buttonRadius * 0.7;
border-radius: 100%;
border: 3px solid white;
background-color: $colorButton;
transition: border-color 1s linear;
}
}
&__label {
position: absolute;
padding: 0 0 1.1em 0;
width: 16em;
max-width: 50vw;
background-color: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
font-family: "Open Sans", sans-serif;
font-size: 14.5px;
line-height: 1.45em;
z-index: -1;
border-radius: $labelBorderRadius;
user-select: none;
opacity: 0;
transition: all $labelFade linear;
h4 {
margin: 0;
padding: 0.65em $labelPaddingX;
background-color: $colorHeadingBackground;
font-size: 1.1em;
font-weight: normal;
letter-spacing: 0.02em;
color: white;
border-radius: $labelBorderRadius $labelBorderRadius 0 0;
}
p {
margin: 0;
padding: 1.1em $labelPaddingX 0 $labelPaddingX;
color: $colorText;
}
}
}
.lg-hotspot--top-left .lg-hotspot__label {
top: $buttonRadius;
left: $buttonRadius;
}
.lg-hotspot--top-right .lg-hotspot__label {
top: $buttonRadius;
right: $buttonRadius;
}
.lg-hotspot--bottom-right .lg-hotspot__label {
right: $buttonRadius;
bottom: $buttonRadius;
}
.lg-hotspot--bottom-left .lg-hotspot__label {
bottom: $buttonRadius;
left: $buttonRadius;
}
@keyframes button-pulse {
0% {
transform: scale(1, 1);
opacity: 1;
}
40% {
transform: scale(1.15, 1.15);
opacity: 1;
}
100% {
transform: scale(1, 1);
opacity: 1;
}
}
View Compiled
const selectHotspot = (e) => {
const clickedHotspot = e.target.parentElement;
const container = clickedHotspot.parentElement;
// only include hotspots within same image to allow one open hotspot per image; change "container" to "document" to allow only one open hotspot for entire page:
const hotspots = container.querySelectorAll(".lg-hotspot");
hotspots.forEach(hotspot => {
if (hotspot === clickedHotspot) {
hotspot.classList.toggle("lg-hotspot--selected");
} else {
hotspot.classList.remove("lg-hotspot--selected");
}
});
}
(() => {
const buttons = document.querySelectorAll(".lg-hotspot__button");
buttons.forEach(button => {
button.addEventListener("click", selectHotspot);
});
})();
This Pen doesn't use any external CSS resources.