# Aspect ratio

> Hold a box at a fixed shape, so nothing on the page moves when the content loads.

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

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

## Common ratios

```javascript
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.

```javascript
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.

```javascript
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

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `ratio` | `string` | `'16 / 9'` | Any CSS aspect-ratio value. |
| `as` | `string` | `'div'` | Element to render. |
