Part of the Webcore kit
please wait…
HTML
<div class="tv-webcore-hourglass" role="status">
<svg class="tv-webcore-hourglass-cursor" viewBox="0 0 16 16" aria-hidden="true">
<path class="tv-webcore-hourglass-paper" d="M1.5 1.5v12l3-3 2.5 4.5 2-1-2.5-4.5h4.5z" />
</svg>
<svg class="tv-webcore-hourglass-glass" viewBox="0 0 16 16" aria-hidden="true">
<path class="tv-webcore-hourglass-paper" d="M4.5 3.5h7v2l-2.5 2.5 2.5 2.5v2h-7v-2l2.5-2.5-2.5-2.5z" />
<path class="tv-webcore-hourglass-sand tv-webcore-hourglass-top" d="M5 4h6v1.5L8 7.5 5 5.5z" />
<rect class="tv-webcore-hourglass-sand tv-webcore-hourglass-stream" x="7.5" y="7.5" width="1" height="4" />
<path class="tv-webcore-hourglass-sand tv-webcore-hourglass-pile" d="M5 12h6v-1.5L8 8.5 5 10.5z" />
<rect class="tv-webcore-hourglass-cap" x="3" y="1" width="10" height="2" />
<rect class="tv-webcore-hourglass-cap" x="3" y="13" width="10" height="2" />
</svg>
<span class="tv-webcore-hourglass-label">please wait…</span>
</div>
CSS
/* A pixel hourglass: the top sand drains into the pile, then the glass flips and starts over. */
.tv-webcore-hourglass {
display: inline-flex;
align-items: center;
gap: 12px;
color: var(--tv-webcore-navy, #2c2b9f);
font: 14px/1.2 "Lucida Console", "Courier New", ui-monospace, monospace;
letter-spacing: 0.06em;
}
.tv-webcore-hourglass svg {
flex-shrink: 0;
shape-rendering: crispEdges;
overflow: visible;
}
.tv-webcore-hourglass-glass {
width: 64px;
height: 64px;
animation: tv-webcore-hourglass-flip 3s steps(6) infinite;
}
.tv-webcore-hourglass-paper {
fill: var(--tv-webcore-paper, #ffffff);
stroke: var(--tv-webcore-navy, #2c2b9f);
stroke-width: 1;
}
.tv-webcore-hourglass-cap {
fill: var(--tv-webcore-navy, #2c2b9f);
}
.tv-webcore-hourglass-sand {
fill: var(--tv-webcore-pink, #f7b5e4);
transform-box: fill-box;
}
.tv-webcore-hourglass-top {
transform-origin: center bottom;
animation: tv-webcore-hourglass-drain 3s steps(8) infinite;
}
.tv-webcore-hourglass-pile {
transform-origin: center bottom;
animation: tv-webcore-hourglass-fill 3s steps(8) infinite;
}
.tv-webcore-hourglass-stream {
animation: tv-webcore-hourglass-stream 3s steps(1) infinite;
}
/* Sand runs for the first 80% of the cycle; the flip takes the rest. */
@keyframes tv-webcore-hourglass-flip {
0%, 80% { transform: rotate(0deg); }
100% { transform: rotate(180deg); }
}
@keyframes tv-webcore-hourglass-drain {
0% { transform: scaleY(1); }
75%, 100% { transform: scaleY(0); }
}
@keyframes tv-webcore-hourglass-fill {
0% { transform: scaleY(0); }
75%, 100% { transform: scaleY(1); }
}
@keyframes tv-webcore-hourglass-stream {
0%, 74% { opacity: 1; }
75%, 100% { opacity: 0; }
}
.tv-webcore-hourglass-cursor {
display: none;
width: 48px;
height: 48px;
}
/* With cursor: a pixel arrow with a small hourglass tucked under its tip, like a busy desktop. */
.tv-webcore-hourglass--cursor {
gap: 0;
}
.tv-webcore-hourglass--cursor .tv-webcore-hourglass-cursor {
display: block;
}
.tv-webcore-hourglass--cursor .tv-webcore-hourglass-glass {
width: 40px;
height: 40px;
margin: 28px 14px 0 -10px;
}
/* Still: a half-run glass with no stream. */
@media (prefers-reduced-motion: reduce) {
.tv-webcore-hourglass-glass,
.tv-webcore-hourglass-top,
.tv-webcore-hourglass-pile,
.tv-webcore-hourglass-stream {
animation: none;
}
.tv-webcore-hourglass-top,
.tv-webcore-hourglass-pile {
transform: scaleY(0.5);
}
}
Usage & credits
- Use when
- Short waits on Y2K pages: loading a guestbook, sending a form, a fake install.
- Avoid when
- Long waits that need real progress, or more than one busy indicator on screen.
- Requires
- Change the label to describe what is loading; it is announced through role="status".
- From
- Luna UI