PlAspectRatio
A box that keeps a proportion whatever width it is given. It draws nothing. What it does is reserve the space, so a picture that arrives late does not reflow the page around it.
import { PlAspectRatio } from 'plass-ui';
<PlAspectRatio ratio="16 / 9" rounded>
<img src="/cover.jpg" alt="" />
</PlAspectRatio>;import 'package:plass_ui/plass_ui.dart';
PlAspectRatio(
ratio: 16 / 9,
rounded: true,
child: Image(image: cover),
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| ratio | number | string | 1 | The proportion to hold, written the way CSS writes it — a number (1.5) or a ratio ('16 / 9') |
| fit | 'cover' | 'contain' | 'fill' | 'none' | 'cover' | How a single piece of media inside is fitted. Reaches a direct img, video, canvas, svg or iframe only |
| rounded | boolean | false | Rounds the corners to the size step of the house radius ladder |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Which radius step rounded uses — the size of the sheet, never a height or a type scale |
| render | RenderProp | — | Renders something other than a <div> (<figure />, <a href="…" />) |
| children | ReactNode | — | What the proportion holds |
| Prop | Type | Default | Description |
|---|---|---|---|
| child | Widget? | — | What the proportion holds |
| ratio | double | 1 | The proportion, as width over height. Written as the division — 16 / 9 — which is how Flutter states an aspect ratio everywhere else |
| fit | PlAspectFit? | null | How the child is fitted, or null to lay it out normally — Flutter has no "media only" the way a browser does, so a fit applied by default would scale a column of prose |
| rounded | bool | false | Rounds the corners to the size step of the house radius ladder |
| sizeshared | PlassSize | PlassSize.md | Which radius step rounded uses — the size of the sheet, never a height or a type scale |
Every native <div> attribute passes straight through.
ratio is a double written as the division, 16 / 9, which is how Flutter states an aspect ratio everywhere else, and it asserts rather than clamping: a ratio of zero is a mistake, not a shape.
size is the only shared axis here, and it is the size of the sheet, which radius step rounded uses. There is no variant, no color and no elevation: a layout component that drew a surface would make a proportion a visual decision. What the shared axes mean across the library is in prop conventions.
Examples
ratio
CSS's own aspect-ratio, untranslated, a number or a ratio, both reaching the property as written. A caller who already knows 16 / 9 has nothing to look up.
fit
The one convenience on top of the proportion. The four words are object-fit's own: cover fills the box and crops, contain letterboxes, fill stretches, none draws at the content's own size.
cover is the one a thumbnail wants, a thumbnail that letterboxes itself is a thumbnail with two grey bands in it. contain is for the picture whose whole subject matters: a diagram, a logo, a scan.
A single img, video, canvas, svg or picture that is a direct child is stretched to the full box and then fitted, which is the pair of declarations every use of this component would otherwise start with. Anything else is laid out normally and fit does not reach it. An iframe takes the sizing but not the fit: an embed lays its own content out, and object-fit has nothing to act on.
It is null by default here, where React defaults it to cover. In a browser object-fit is a property only a replaced element answers, so React can default it and have it quietly not reach a <div> full of text. Flutter has no such distinction. A fit is a FittedBox around whatever the child happens to be, and one applied by default would scale a column of prose. So it is opt-in, and it applies to everything.
An Image that already carries its own BoxFit needs nothing here.
rounded
Off by default. A photograph with its corners cut is a decision about the photograph, not about the box holding it, but it is such a common one that making the caller reach for a classNamea ClipRRect would be perverse, so it is a boolean and size picks the step.
The box clips whatever it holds either way. Without that, a cover image would spill straight out of the proportion it was just given and the component would only be reserving space rather than holding anything to it.
Accessibility
- The box adds no role and no semantics node of its own. It is a measurement, and a measurement is not something a screen reader should have to announce.
- Nothing here supplies a description of the picture inside. That picture is the caller's, and so is what it means.
renderis how the box becomes the element the content actually calls for, a<figure>around a picture with a caption, an<a>around a card's cover.
Differences from the React build
| React | Flutter | Why |
|---|---|---|
fit defaults to 'cover' | fit defaults to null | object-fit reaches only a replaced element, so React can default it harmlessly. A FittedBox reaches whatever it is given, and one applied by default would scale a column of text. |
ratio takes '16 / 9' | ratio takes 16 / 9 | A double written as the division, which is how Flutter states an aspect ratio everywhere else. There is no string form to parse. |
render | — | There is no element to swap. A widget that has to be a link or a figure is wrapped in one. |
children | child | Flutter's name. |
className, style | — | There is no class list and no style attribute to pass through. |