The dialog
A part several examples share, shown once, running elsewhere.
The photo viewer needs one <dialog> on its page. It isn’t part of what that example
demonstrates, so it lives in assets/examples/dialog/ and runs bare there, with frame="false". This page only shows
its files, with run="false":
<dialog class="box" aria-label="Photo viewer">
<div data-dlb-viewport></div>
<div class="box-bar">
<span class="box-count"><span data-dlb-counter></span> / <span data-dlb-total></span></span>
<button type="button" data-dlb-zoom>Zoom</button>
<button type="button" data-dlb-close>Close</button>
</div>
<button class="box-side" type="button" data-dlb-prev aria-label="Previous">←</button>
<button class="box-side" type="button" data-dlb-next aria-label="Next">→</button>
<p class="box-caption"></p>
<template data-dlb-overlay="video">
<div class="box-video">
<button type="button" data-dlb-play aria-label="Play"></button>
<button type="button" data-dlb-mute aria-label="Sound off"></button>
<button type="button" data-dlb-fullscreen>Fullscreen</button>
</div>
<span data-dlb-progress></span>
</template>
</dialog>/* Transparent, so the photo sits on the backdrop, which fades in with --dlb-opacity */
.box {
background: transparent;
color: #fff;
font:
0.8rem / 1 ui-monospace,
Menlo,
Consolas,
monospace;
}
.box::backdrop {
background: rgb(10 10 12 / calc(var(--dlb-opacity) * 0.94));
}
/* Room above for the bar and below for the caption */
.box [data-dlb-viewport] {
padding: 3rem 0;
}
.box button {
padding: 0.45rem 0.7rem;
border: 1px solid rgb(255 255 255 / 0.3);
border-radius: 0.25rem;
background: rgb(10 10 12 / 0.4);
color: inherit;
font: inherit;
text-transform: uppercase;
letter-spacing: 0.06em;
cursor: pointer;
}
.box button:hover {
border-color: #fff;
}
.box button:disabled {
opacity: 0.3;
cursor: default;
}
.box-bar {
position: absolute;
inset: 0 0 auto;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.6rem 1rem;
}
/* "3 / 16" pushes the buttons to the right */
.box-count {
margin-right: auto;
}
.box-side {
position: absolute;
top: 50%;
translate: 0 -50%;
}
.box [data-dlb-prev] {
left: 1rem;
}
.box [data-dlb-next] {
right: 1rem;
}
.box-caption {
position: absolute;
inset: auto 1rem 0.9rem;
margin: 0;
text-align: center;
line-height: 1.4;
}
/* The video overlay: copied over each video, so it moves with it */
.box [data-dlb-overlay] {
pointer-events: none;
}
.box-video {
position: absolute;
inset: 0.5rem 0.5rem auto;
display: flex;
gap: 0.4rem;
}
.box-video button {
pointer-events: auto;
}
.box [data-dlb-play]::after {
content: "Pause";
}
.box[data-dlb-paused] [data-dlb-play]::after,
.box [data-dlb-slide]:not([data-dlb-current]) [data-dlb-play]::after {
content: "Play";
}
.box [data-dlb-mute]::after {
content: "Sound off";
}
.box[data-dlb-muted] [data-dlb-mute]::after {
content: "Sound on";
}
.box [data-dlb-fullscreen] {
margin-left: auto;
}
.box [data-dlb-progress] {
position: absolute;
inset: auto 0 0;
height: 3px;
background:
linear-gradient(#fff, #fff) left / calc(var(--dlb-progress, 0) * 100%) 100% no-repeat,
rgb(255 255 255 / 0.25);
}
/* Zoom only on photos; a tap on a photo hides the controls */
.box[data-dlb-type="video"] [data-dlb-zoom] {
display: none;
}
.box[data-dlb-ui-hidden] :is(.box-bar, .box-side, .box-caption) {
opacity: 0;
pointer-events: none;
}
/* On touch screens people swipe */
@media (pointer: coarse) {
.box-side {
display: none;
}
}