Aspect ratio fit and fill visualizer
See how an image fits, fills or crops inside a container, then copy the code. Choose one of seven content modes and resize the box: the drawing measures the empty bars and cropped edges, and the code panel writes CSS, UIKit, SwiftUI, Android View, Compose or Flutter.
Visualizer
box empty space cropped off
The math for fit
Scale = min(400 ÷ 1200, 300 ÷ 800) = 0.3333. Drawn at 400 × 266.67, 16.67 empty above and below.
The code
let imageView = UIImageView(image: UIImage(named: "photo"))
imageView.frame = CGRect(x: 0, y: 0, width: 400, height: 300)
imageView.contentMode = .scaleAspectFitOne behavior, six spellings
The same seven ways of putting an image in a box exist in every toolkit, under different names. A dash means there is no built-in value; the visualizer's code panel writes a workaround.
| Behavior | UIKit contentMode | SwiftUI | CSS object-fit | Android scaleType | Compose ContentScale | Flutter BoxFit |
|---|---|---|---|---|---|---|
| Fit: whole image, empty bars | .scaleAspectFit | .scaledToFit() | contain | fitCenter | Fit | contain |
| Fill: box covered, edges cropped | .scaleAspectFill + clipsToBounds | .scaledToFill() + .clipped() | cover | centerCrop | Crop | cover |
| Stretch: ratio ignored | .scaleToFill | .resizable() | fill | fitXY | FillBounds | fill |
| No scaling | .center, .top, .topLeft … | Image without .resizable() | none | center | None | none |
| Shrink only, never enlarge | no built-in equivalent | no built-in equivalent | scale-down | centerInside | Inside | scaleDown |
| Fit width | no built-in equivalent | no built-in equivalent | no built-in equivalent | no built-in equivalent | FillWidth | fitWidth |
| Fit height | no built-in equivalent | no built-in equivalent | no built-in equivalent | no built-in equivalent | FillHeight | fitHeight |
Two formulas cover almost everything
Work out how much the image would have to scale to match the box's width, and how much to match its height:
ratioX = boxWidth / imageWidth
ratioY = boxHeight / imageHeight
fit: scale = min(ratioX, ratioY)
fill: scale = max(ratioX, ratioY)The smaller ratio guarantees nothing sticks out, so you get bars. The larger one guarantees nothing is left empty, so you get cropping. Stretch uses both ratios, one per axis, which is why it distorts. Multiply the image size by the scale for the drawn size; whatever is left over (or sticks out) is split according to the anchor, half and half by default.
The full walk-through, with the UIKit side of things, is in aspect fit vs aspect fill.
Each toolkit has a different default
Many "my image looks wrong" bugs come from the default, not from the mode someone chose. If you never set a mode, this is what you get:
| Toolkit | View | Default | Effect |
|---|---|---|---|
| UIKit | UIImageView | .scaleToFill | stretches |
| SwiftUI | Image | natural size until .resizable() | ignores the frame's size |
| CSS | <img> / <video> | fill / contain | img stretches, video letterboxes |
| Android View | ImageView | fitCenter | aspect fit |
| Compose | Image | ContentScale.Fit | aspect fit |
| Flutter | Image / FittedBox | scaleDown / contain | small images stay small / aspect fit |
Guides
- Aspect fit vs aspect fill
The formulas with worked numbers, all thirteen UIView.ContentMode cases, clipsToBounds and Auto Layout.
- CSS object-fit
contain, cover, fill, none and scale-down; object-position as an anchor; aspect-ratio, video and background-size.
- SwiftUI aspectRatio and scaledToFit
Why .resizable() comes first, filling and clipping a frame, tap areas, square grid thumbnails, AsyncImage.
- Android scaleType and Compose ContentScale
All eight scale types, the adjustViewBounds trap, cropToPadding, anchored crops with a matrix.
- Flutter BoxFit
Seven fits, why Image defaults to scaleDown, FittedBox clipping, Alignment math, applyBoxFit.
- Aspect ratio calculator
Simplify any width and height to W:H, find a missing side, and fit an image into a box.
Fit for clothes, too
The rest of this site is about fitting pictures into boxes. The same team builds FitInView, an AI virtual try-on for the other kind of fit. Upload a photo of yourself and a photo or shop link of a garment, and FitInView generates an image of you wearing it. It helps when you are about to order a jacket online and want to see it on you first.
Your first try-on is included with a free account. No card needed. Your photos are private to your account, and you can delete them.

Questions
What is the difference between aspect fit and aspect fill?
Both keep the image's aspect ratio. Aspect fit scales the image by the smaller of the two ratios (box width ÷ image width, box height ÷ image height), so the whole image is visible and empty bars appear where the shapes differ. Aspect fill scales by the larger ratio, so the box is completely covered and the parts that stick out are cropped.
Is scaleAspectFill the same as object-fit: cover?
Yes, they compute the same size and position: UIKit's scaleAspectFill, CSS object-fit: cover, SwiftUI's scaledToFill(), Android's centerCrop, Compose's ContentScale.Crop and Flutter's BoxFit.cover all scale by the larger ratio and center the result. They differ in clipping: in UIKit and SwiftUI you must clip the overflow yourself.
Which mode stretches the image?
UIKit scaleToFill (the UIImageView default), SwiftUI resizable() without an aspect modifier, CSS object-fit: fill (the initial value), Android fitXY, Compose ContentScale.FillBounds and Flutter BoxFit.fill. They scale width and height separately, so the image is distorted whenever the box has a different shape.
How do I calculate the letterbox size?
Compute scale = min(boxWidth / imageWidth, boxHeight / imageHeight), then the drawn size is the image size times the scale. The leftover on each axis is box size minus drawn size; centered, half goes to each side. A 1200 × 800 image in a 400 × 300 box is drawn at 400 × 266.67, leaving 16.67 above and below.
Does the visualizer upload my image?
No. Your image is read by your browser and never leaves your device. The page has no analytics and makes no network requests for your files.