Aspect ratio

The height is known from the width before anything has loaded, so an image or an embed arriving late does not shove the rest of the page down. The child fills the box and is cropped rather than letterboxed.

Basic aspect ratio

aspectRatio({ ratio: '16 / 9', style: 'background: var(--su-surface-2)' },
  '<img src="/logo.svg" alt="" style="object-fit: contain; padding: 2rem">',
)

Common ratios

16 / 9
4 / 3
1 / 1
3 / 4
grid({ min: '9rem' },
  ...['16 / 9', '4 / 3', '1 / 1', '3 / 4'].map((ratio) =>
    stack({ gap: 'xs' },
      aspectRatio({ ratio, style: 'background: var(--su-surface-2); border-radius: 0.5rem' },
        '<img src="/logo.svg" alt="" style="object-fit: contain; padding: 1rem">'),
      text({ variant: 'caption', tone: 'muted', align: 'center' }, ratio),
    ),
  ),
)

Embeds

The reason this component exists: an <iframe> has no intrinsic size, so without a ratio it collapses or needs a hard-coded height.

an <iframe> would go here
aspectRatio({ ratio: '16 / 9', style: 'background: var(--su-surface-2); border-radius: 0.6rem' },
  '<div style="display: grid; place-items: center; color: var(--su-text-subtle)">an &lt;iframe&gt; would go here</div>',
)

In a card

cardMedia() already does this for the top of a card. Reach for aspectRatio() when the box is somewhere else.

cardMedia — built in

aspectRatio — anywhere else

grid({ min: '12rem' },
  card(
    cardMedia({ src: '/logo.svg', alt: '', style: 'background: var(--su-surface-2); object-fit: contain; padding: 1rem' }),
    cardBody(text({ variant: 'small' }, 'cardMedia — built in')),
  ),
  card(
    cardBody(
      stack({ gap: 'sm' },
        aspectRatio({ ratio: '1 / 1', style: 'background: var(--su-surface-2); border-radius: 0.5rem' },
          '<img src="/logo.svg" alt="" style="object-fit: contain; padding: 1rem">'),
        text({ variant: 'small' }, 'aspectRatio — anywhere else'),
      ),
    ),
  ),
)

Cropping

The child is stretched to fill and cropped with object-fit: cover. For something that must not be cropped — a logo, a diagram — set object-fit: contain on the child, as every demo on this page does.

Props

PropTypeDefaultDescription
ratiostring'16 / 9'Any CSS aspect-ratio value.
asstring'div'Element to render.