Aspect Ratio
stimeo--aspect-ratio
Supplies a ratio as a CSS custom property so consumer styles keep the box proportional.
The stimeo--aspect-ratio controller is a pure layout helper with no role or state. It supplies the requested ratio as the --stimeo-aspect-ratio custom property on the host, so consumer CSS can drive the box with aspect-ratio: var(--stimeo-aspect-ratio) (or a padding-hack fallback). The value accepts the CSS ratio forms 16/9 and a bare number; it is normalized to w / h and an unparseable value falls back to 1 / 1, and the reflection re-runs whenever the value changes. Behavior only — the drawing itself (aspect-ratio, object-fit, cropping) stays in this Playground's stylesheet.
<%# Markup for the aspect-ratio demo.
The library only supplies the ratio Value as the --stimeo-aspect-ratio custom
property; demo.css does the actual ratio rendering
(aspect-ratio: var(--stimeo-aspect-ratio)). %>
<div class="aspect-ratio-demo">
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="16/9">
<div class="ratio-box__content" data-stimeo--aspect-ratio-target="content">16 / 9</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.wide") %></figcaption>
</figure>
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="1/1">
<div class="ratio-box__content" data-stimeo--aspect-ratio-target="content">1 / 1</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.square") %></figcaption>
</figure>
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="3/4">
<div class="ratio-box__content" data-stimeo--aspect-ratio-target="content">3 / 4</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.portrait") %></figcaption>
</figure>
</div>
/* Presentation CSS for aspect-ratio. The library only supplies
--stimeo-aspect-ratio, so this CSS reads it with var() and draws the ratio. */
.aspect-ratio-demo {
display: flex;
gap: 1.5rem;
flex-wrap: wrap;
align-items: flex-start;
}
.aspect-ratio-demo__item {
margin: 0;
font-size: 0.85rem;
color: var(--color-text-muted);
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/* Feed the ratio the library supplies straight into CSS aspect-ratio. */
.ratio-box {
width: 200px;
aspect-ratio: var(--stimeo-aspect-ratio);
border: 2px dashed var(--border-interactive);
border-radius: 8px;
background: repeating-linear-gradient(
45deg,
var(--surface-subtle),
var(--surface-subtle) 10px,
var(--surface-subtle) 10px,
var(--surface-subtle) 20px
);
}
.ratio-box__content {
width: 100%;
height: 100%;
display: grid;
place-items: center;
font-weight: 600;
color: var(--color-text);
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--aspect-ratio"
Targets
| Name | Description | Attribute |
|---|---|---|
content
|
The element whose box is constrained to the configured aspect ratio. | data-stimeo--aspect-ratio-target="content" |
Values
| Name | Description | Attribute |
|---|---|---|
ratio
|
The CSS <ratio> to apply (e.g. 16/9 or a bare number); defaults to 1/1 and falls back to it when unparseable. |
data-stimeo--aspect-ratio-ratio-value |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
--stimeo-aspect-ratio |
Host element | The ratio (e.g. 16 / 9). Consumer CSS reads it. |