Aspect fit vs aspect fill
Both keep the image's proportions. Aspect fit scales until the whole image fits inside the view and leaves empty bars. Aspect fill scales until the view is completely covered and cuts off whatever sticks out. The difference is one word in the formula: min or max.
The short answer
In UIKit the two modes are UIView.ContentMode.scaleAspectFit and .scaleAspectFill. Put a 1200 × 800 photo (3:2) into a 400 × 300 image view (4:3) and you get this:
- Aspect fit (
.scaleAspectFit): nothing is cropped, nothing is distorted, but the view may show empty bands (letterboxing on top and bottom, pillarboxing on the sides). The bands show the image view'sbackgroundColor. - Aspect fill (
.scaleAspectFill): no empty space and no distortion, but part of the image is outside the view. You must setclipsToBounds = true, or UIKit happily draws the overflow over neighboring views. - Scale to fill (
.scaleToFill): fills the view exactly by scaling width and height independently. The image is distorted whenever the two ratios differ. This is the default forUIImageView.
If the image and the view have the same aspect ratio, all three give the identical result. The modes only matter when the ratios differ, which is most of the time with user photos.
The math, step by step
Every aspect mode starts from the same two ratios: how much the image would need to scale to match the view's width, and how much to match its height.
ratioX = viewWidth / imageWidth
ratioY = viewHeight / imageHeight
aspect fit: scale = min(ratioX, ratioY)
aspect fill: scale = max(ratioX, ratioY)
scale to fill: scaleX = ratioX, scaleY = ratioY (two scales, so the ratio changes)
drawnWidth = imageWidth * scale
drawnHeight = imageHeight * scale
x = (viewWidth - drawnWidth) / 2 // negative x means cropped on both sides
y = (viewHeight - drawnHeight) / 2For the 1200 × 800 photo in the 400 × 300 view: ratioX = 400 / 1200 = 0.3333 and ratioY = 300 / 800 = 0.375.
- Fit takes the smaller one, 0.3333. The photo becomes 400 × 266.67, so 300 − 266.67 = 33.33 points of height are left over, 16.67 above and 16.67 below.
- Fill takes the larger one, 0.375. The photo becomes 450 × 300, so 50 points of width stick out, 25 on each side. In the source image that is 25 / 0.375 = 66.67 pixels cut from the left and the right: only the middle 1066.67 of 1200 pixels are visible, which hides 11.1% of the photo.
Choosing the smaller ratio guarantees that neither side is larger than the view; choosing the larger one guarantees that neither side is smaller. That is the entire difference. You can try any numbers in the visualizer on the home page, which shows each of these steps as you drag the box.
One UIKit detail: UIImage.size is in points, not pixels. A 1200-pixel-wide image loaded as @3x reports a width of 400 points, and the formulas run on those point values.
All thirteen UIView.ContentMode cases
contentMode is declared on UIView, so it is not only for images; but UIImageView is where it is used most. The default is .scaleToFill for both UIView and UIImageView.
| Case | Scales? | Keeps ratio? | What you see |
|---|---|---|---|
.scaleToFill | yes | no | Image stretched to exactly the view's bounds. The default. |
.scaleAspectFit | yes | yes | Whole image, centered, empty bands where the ratios differ. |
.scaleAspectFill | yes | yes | View fully covered, centered, overflow cropped only if clipsToBounds is on. |
.redraw | no | n/a | For views that draw themselves in draw(_:): asks for a fresh draw(_:) when the bounds change instead of scaling the old drawing. |
.center | no | yes | Image at its own size, centered. |
.top, .bottom, .left, .right | no | yes | Image at its own size, pinned to the middle of that edge. |
.topLeft, .topRight, .bottomLeft, .bottomRight | no | yes | Image at its own size, pinned to that corner. |
The position modes never scale, so a large photo in .center mode shows only its middle, and a small icon stays small. The three scaling modes always center the result; there is no built-in "aspect fill, anchored to the top".
In Interface Builder the same list appears as Content Mode in the Attributes inspector: Scale To Fill, Aspect Fit, Aspect Fill, Redraw, Center, Top and so on.
Why aspect fill spills outside the view
clipsToBounds is false by default, and aspect fill draws an image larger than its view by design. Without clipping, the extra 25 points on each side in the example are drawn over whatever is next to the image view. This is the most common aspect fill bug, and it often goes unnoticed until a photo with a different ratio comes along.
let avatar = UIImageView(image: photo)
avatar.contentMode = .scaleAspectFill
avatar.clipsToBounds = true // same as avatar.layer.masksToBounds = true
// round avatar: clipping also makes cornerRadius apply to the image
avatar.layer.cornerRadius = 32In Interface Builder the switch is Clips to Bounds in the Drawing section of the Attributes inspector. In a UICollectionViewCell, clip the image view itself, not only the cell's content view, if other subviews sit on top of the image.
Aspect fit and Auto Layout
A UIImageView reports its image's size as its intrinsic content size. If you only pin its leading and trailing edges, Auto Layout uses the image's own height, and on a narrow phone the view ends up far taller than the picture it shows: aspect fit then draws large empty bands above and below. If the view should simply take the image's shape, give it an aspect ratio constraint and let the content mode do nothing interesting:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
let ratio = image.size.height / image.size.width
NSLayoutConstraint.activate([
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: ratio),
])When the image changes, replace that constraint with one for the new ratio. If the view must keep a fixed shape (a 4:3 card, a square thumbnail), use fixed constraints instead and let aspect fit or aspect fill decide how the image sits inside.
Which one to use
A useful rule of thumb: use aspect fit when losing any part of the image would be wrong, and aspect fill when empty space would look wrong.
- Aspect fit suits product shots on a plain background, logos, documents and receipts, screenshots, charts, and full-screen photo viewers where people expect to see the whole picture.
- Aspect fill suits avatars, grid thumbnails, cards, headers and background images: places where the layout has a fixed shape and a little cropping is acceptable.
- Scale to fill is rarely right for photos. It is fine for solid colors, gradients, and stretchable images made with
resizableImage(withCapInsets:resizingMode:), where only the middle stretches.
Aspect fill crops symmetrically, so a tall portrait in a wide header loses equal amounts at top and bottom, which can mean the top of someone's head. If the subject matters, crop the image yourself before showing it, for example with CGImage.cropping(to:) and a rectangle computed from the same formulas with the offset moved to where you want it.
The same modes on other platforms
Every UI toolkit has these behaviors, under different names and with different defaults:
| UIKit | SwiftUI | CSS | Android View | Compose | Flutter |
|---|---|---|---|---|---|
.scaleAspectFit | .scaledToFit() | object-fit: contain | fitCenter | ContentScale.Fit | BoxFit.contain |
.scaleAspectFill | .scaledToFill() | object-fit: cover | centerCrop | ContentScale.Crop | BoxFit.cover |
.scaleToFill | .resizable() | object-fit: fill | fitXY | ContentScale.FillBounds | BoxFit.fill |
The details differ, especially around clipping and defaults. The guides cover each one: SwiftUI aspectRatio and scaledToFit, CSS object-fit, Android scaleType and Compose ContentScale, and Flutter BoxFit.
Questions
What is the difference between aspect fit and aspect fill?
Both keep the image's aspect ratio. Aspect fit scales by the smaller of the two ratios (view width ÷ image width, view height ÷ image height) so the whole image is visible, with empty bars where the ratios differ. Aspect fill scales by the larger ratio so the view is fully covered and the overflow is cropped.
Why does my scaleAspectFill image draw outside the image view?
Because clipsToBounds is false by default. Aspect fill makes the image larger than the view on one axis; set imageView.clipsToBounds = true (or check Clips to Bounds in Interface Builder) to cut off the overflow.
What is the default contentMode of UIImageView?
scaleToFill, which stretches the image to the view's bounds without keeping its aspect ratio. Set contentMode to scaleAspectFit or scaleAspectFill to keep the proportions.
Want your own numbers? The visualizer draws any box and image, shows each step of the math and writes the code for six toolkits.