Navigation

v0.0.4
Media

Figure

An image or a video with its caption, finished at the edge.

On this page

A figure is an image, a video or a drawing with its caption. The media takes a surface's corner and a hairline ring just inside its own edge, so a pale image does not dissolve into the page and a dark one does not end in a hard cut. The caption sits close under it, quiet. A picture a reader may want to see large opens in a lightbox.

Figure

<figure class="figure max-w(360) mx-auto">  <img class="figure-media" src="/demo/moonstone.svg" alt="A pale stone with a band of light across it" style="--figure-ratio: 3 / 2">  <figcaption class="figure-caption">Moonstone under a north light, the stone the light theme is named for.</figcaption></figure>

Set --figure-ratio on the media to hold its shape before it loads; the media then covers that shape. Without it the media keeps its own proportions. Write width and height on the <img> either way, so the browser reserves the space.

#Framed

figure-framed rests the media in a tray, 4px in, like a print in a mat, and the caption moves inside the frame. The tray's corner is the media's corner plus that inset, so the gap keeps one width around the bend.

Framed

<figure class="figure figure-framed max-w(360) mx-auto">  <img class="figure-media" src="/demo/moonstone.svg" alt="A pale stone with a band of light across it" style="--figure-ratio: 16 / 9">  <figcaption class="figure-caption">Figure 2. The same stone, framed.</figcaption></figure>

#Centered

figure-center centers and balances the caption, for a figure that stands alone in a column of text.

Centered

<figure class="figure figure-center max-w(240) mx-auto">  <img class="figure-media" src="/demo/portrait-2.svg" alt="Alan Turing" style="--figure-ratio: 1">  <figcaption class="figure-caption">Alan Turing, drawn for the avatar examples.</figcaption></figure>

#Accessibility

  • Use <figure> with a <figcaption>: the caption is then the figure's accessible name.
  • The caption does not replace alt. The alternative text says what the image shows; the caption says why it is here. When the caption already says everything, an empty alt="" avoids reading it twice.
  • The ring inside the media's edge is decoration and follows the color scheme; in forced colors a framed figure takes a system outline.

#Classes

ClassDescription
figureThe figure: media over a caption
figure-framedThe media rests in a tray, 4px in, with the caption inside the frame. With figure
figure-centerA centered, balanced caption, for a figure that stands alone in a column of text. With figure
figure-mediaThe img, video, svg or any block, with a surface's corner and a hairline ring inside its edge
figure-captionThe caption, small and muted under the media

#Custom properties

PropertyDefaultDescription
--figure-radiusvar(--radius-surface)The media's corner
--figure-ratioThe media's aspect ratio, held before it loads; the media then covers that shape. Without it the media keeps its own proportions. On figure-media

#Source

@master/ui/components/figure.css
/* * Figure: an image, a video or a drawing with its caption. * The media takes a surface's corner and a hairline ring inside its own edge, so a pale image does not * dissolve into the page and a dark one does not end in a hard cut. The caption sits close under it, quiet. */@layer components {  .figure {    --figure-radius: var(--radius-surface);    display: grid;    gap: .625rem;    min-width: 0;    margin: 0;    /*     * Framed: the media rests in a tray, 4px in, like a print in a mat. The tray's corner is the media's     * corner plus that inset.     */    &.figure-framed {      padding: 4px;      border-radius: calc(var(--figure-radius) * var(--corner-scale) + 4px);      corner-shape: var(--corner-shape);      background: var(--color-surface-tray);      box-shadow: inset 0 0 0 .5px var(--color-line-hair), inset 0 1px 2px -1px var(--color-shade-2);      gap: 0;      .figure-media {        box-shadow: var(--shadow-raised);        outline: 0;      }      .figure-caption {        padding: .5rem .625rem .375rem;      }    }    @media (forced-colors: active) {      &.figure-framed {        outline: 1px solid CanvasText;        outline-offset: -1px;      }    }  }  /* Set --figure-ratio to hold a shape before the media loads; the media then covers that shape. */  .figure-media {    display: block;    width: 100%;    max-width: 100%;    height: auto;    aspect-ratio: var(--figure-ratio, auto);    border-radius: calc(var(--figure-radius) * var(--corner-scale));    corner-shape: var(--corner-shape);    background: var(--color-surface-inset);    object-fit: cover;    outline: .5px solid var(--color-line-image-strong);    outline-offset: -.5px;  }  .figure-caption {    margin: 0;    color: var(--color-text-muted);    font-size: .8125rem;    line-height: 1.5;    text-wrap: pretty;    overflow-wrap: anywhere;  }  /* Centered: for a figure that stands alone in a column of text. */  .figure-center .figure-caption {    text-align: center;    text-wrap: balance;  }}