Aspect Ratio

ui-aspect-ratio is a block that sizes its height from its width with the CSS aspect-ratio property and clips anything that overflows. It fills the width of its container, so size it with a wrapper. A slotted <img>, <video> or <iframe> is stretched to fill the box with object-fit: cover. Put the radius and background on the content, not on the box.

Previewindex.html
16 / 9
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Aspect Ratio demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
  <style>
    .demo-medium {
      width: min(100%, calc(var(--spacing) * 120));
    }
    .demo-tile {
      display: grid;
      place-items: center;
      box-sizing: border-box;
      height: 100%;
      min-height: calc(var(--spacing) * 16);
      padding: calc(var(--spacing) * 4);
      border-radius: var(--radius-lg);
      background: var(--muted);
      font-size: var(--text-sm);
      font-weight: var(--font-weight-medium);
    }
  </style>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/aspect-ratio.html"></import-element>

  <div class="demo-medium">
    <ui-aspect-ratio ratio="16 / 9">
      <div class="demo-tile">16 / 9</div>
    </ui-aspect-ratio>
  </div>
</body>
</html>

Examples

Ratios

ratio takes any value the CSS aspect-ratio property accepts, such as 1 / 1, 4 / 3 or 2.35.

Previewindex.html
21 / 9
4 / 3
1 / 1
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Aspect Ratio demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
  <style>
    .demo-narrow {
      width: min(100%, calc(var(--spacing) * 88));
    }
    .demo-stack {
      display: grid;
      gap: calc(var(--spacing) * 4);
    }
    .demo-tile {
      display: grid;
      place-items: center;
      box-sizing: border-box;
      height: 100%;
      min-height: calc(var(--spacing) * 16);
      padding: calc(var(--spacing) * 4);
      border-radius: var(--radius-lg);
      background: var(--muted);
      font-size: var(--text-sm);
      font-weight: var(--font-weight-medium);
    }
  </style>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/aspect-ratio.html"></import-element>

  <div class="demo-narrow demo-stack">
    <ui-aspect-ratio ratio="21 / 9">
      <div class="demo-tile">21 / 9</div>
    </ui-aspect-ratio>
    <ui-aspect-ratio ratio="4 / 3">
      <div class="demo-tile">4 / 3</div>
    </ui-aspect-ratio>
    <ui-aspect-ratio ratio="1 / 1">
      <div class="demo-tile">1 / 1</div>
    </ui-aspect-ratio>
  </div>
</body>
</html>

Image

A slotted image covers the whole box and is cropped to the ratio.

Previewindex.html
A mountain range at sunset
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Aspect Ratio demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
  <style>
    .demo-narrow {
      width: min(100%, calc(var(--spacing) * 88));
    }
    .demo-image {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
      border-radius: var(--radius-lg);
    }
  </style>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/aspect-ratio.html"></import-element>

  <div class="demo-narrow">
    <ui-aspect-ratio ratio="4 / 3">
      <img class="demo-image" alt="A mountain range at sunset" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 200'%3E%3Crect width='400' height='200' fill='%23f4a261'/%3E%3Cpath d='M0 200 120 70l70 80 60-50 150 100z' fill='%23264653'/%3E%3Ccircle cx='300' cy='60' r='28' fill='%23e9c46a'/%3E%3C/svg%3E">
    </ui-aspect-ratio>
  </div>
</body>
</html>

Video embed

<ui-aspect-ratio ratio="16 / 9">
  <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID" title="Product tour" allowfullscreen></iframe>
</ui-aspect-ratio>

API

Parts

Part Slot Renders
ui-aspect-ratio (default) A full-width block at the given ratio that clips overflow. Its default slot takes any content. <img>, <video> and <iframe> fill the box and use object-fit: cover.

Attributes

Attribute Type Default Description
ratio string "16 / 9" Width-to-height ratio, as a CSS aspect-ratio value.

CSS parts

None. The box renders only a slot.

CSS states and custom properties

The ratio is applied through the reactive custom property --attr-ratio, which mirrors the ratio attribute.

Accessibility

The element adds no semantics. Give images an alt text and iframes a title.

Edit this page on GitHub · View as Markdown