The following is a guest post by Parker Bennett where he explores some different ways to approach the behavior of fluid and responsive images.
Sometimes you want an image to resize responsively but restrict its height — cropping it then as it widens. Here, we explore three options with various trade-offs.
background-position: center bottom
.Option One: background-image
Here, in place of an <img>
, we create a div with a background-image
and use CSS3’s dandy new background-size: cover
to have it size proportionally. As a bonus, we can easily crop from the top, center, or bottom using background-position
.
One potential issue is we need to specify a height for the div
to show up. This gives it a fixed height that doesn’t scale proportionally (at least not without CSS media queries). When it gets narrow enough, the sides start cropping (this might be preferable, it depends).
Also, a quick check with caniuse.com shows this will fail conspicuously in IE8 (showing the image full size), but thanks to Louis-Rémi Babé, there’s a background-size polyfill workaround (though it does require a relative or fixed position, and a z-index). IE8 also needs a polyfill for CSS media queries. There are a couple options.
.bg-image {
/* image specified in separate class below */
height: 240px;
width: 100%;
}
.bg-image-wedding {
background-image: url(img/photo-wedding_1200x800.jpg);
/* lt ie8 */
-ms-background-position-x: center;
-ms-background-position-y: bottom;
background-position: center bottom;
/* scale bg image proportionately */
background-size: cover;
/* ie8 workaround - http://louisremi.github.io/background-size-polyfill/ */
-ms-behavior: url(/backgroundsize.min.htc);
/* prevent scaling past src width (or not) */
/* max-width: 1200px; */
}
/* example media queries */
@media only screen and (min-width : 768px) {
.bg-image { height: 320px; }
}
@media only screen and (min-width : 1200px) {
.bg-image { height: 400px; }
}
background-position: center center
.Something to note, background-size: cover
will readily upscale larger than the src image’s native size (or not, if you set a max-width).*
Still, there are some downsides to using a background-image
. It’s not as semantic or modular as an img
, so it’s less straightforward to maintain. You’re seemingly stuck with a fixed height or cumbersome CSS media queries. Also, users can’t save the image as easily (sometimes preferable).
Option Two: img with a Twist
Here, we use an img
with max-width
set to a percentage of the containing element so it scales responsively, then wrap it in a div with overflow: hidden
and a specified height or max-height
.

.crop-height {
/* max-width: 1200px; /* img src width (if known) */
max-height: 320px;
overflow: hidden;
}
img.scale {
/* corrects inline gap in enclosing div */
display: block;
max-width: 100%;
/* just in case, to force correct aspect ratio */
height: auto !important;
width: auto\9; /* ie8+9 */
/* lt ie8 */
-ms-interpolation-mode: bicubic;
}
As you can see, the bottom of the image now gets cropped as it widens. But what if you want it to crop from the top? Surprisingly, you can — using CSS3’s transform:rotate()
we add a “flip” class to both img.scale
and div.crop-height
— flipping the img all the way around.

/* apply to both img.scale and div.crop-height */
.flip {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
/* needed? not sure */
zoom: 1;
}
img.flip {
/* if native or declared width of img.scale
is less than div.crop-height, this will
flipped img left */
float: right;
/* add clearfix if needed */
}
Novel, but limited to top-cropping only. And, as you might expect, this doesn’t work in IE8, either — perhaps failing less conspicuously (it will just crop from the bottom as before). The bad news is, I haven’t found any polyfill options that work because they need a specified height and width.
Option Three: Hybrid Approach
What if we could have the advantages of specifying an img
(e.g., using max-height
so we get proportional vertical scaling below a certain height), but also the flexible cropping and IE8 polyfill support afforded a background-image
? We can!

visibility: hidden
, the background-image has background-position: center center
.
The trick is to make the responsively-sizing img
invisible. With visibility: hidden
it retains layout, so we see the background-image
behind it. (Since it’s the same image source it shouldn’t have to download twice.) If you want user-friendly access, you could instead use opacity: 0
. Now users can drag the image or right-click to save. (Opacity and background-size need some extra IE8 workaround bits.)

opacity: 0
. A background-image you can drag or right-click to save. Works in IE8 (with help).
Another thought is to use a more compressed proxy img
, and use CSS media queries to serve a higher-resolution background-image
as needed. This img could even be a proportionately smaller size (e.g., matching your max-height), or watermarked. Check out this CSS-Tricks post on media queries, and this helpful resolution mixin for Sass.

img
is holding the space for the higher-res background-image
.
.crop-height {
/* max-width: 1200px; /* img src width (if known) */
max-height: 320px;
overflow: hidden; }
.bg-image-wedding {
/* for small devices */
background-image: url(img/photo-wedding_1200x800.jpg);
/* lt ie8 */
-ms-background-position-x: center;
-ms-background-position-y: bottom;
background-position: center bottom;
/* scale bg image proportionately */
background-size: cover;
/* ie8 workaround - http://louisremi.github.io/background-size-polyfill/ */
-ms-behavior: url(/backgroundsize.min.htc);
*/ prevent scaling past src width (or not) */
/* max-width: 1200px; */ }
.invisible {
visibility: hidden; }
.transparent {
/* trigger hasLayout for IE filters below */
zoom: 1;
/* 0 opacity in filters still displays layout */
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=10);
opacity: 0; }
/* example media query for smaller non-retina devices */
@media
only screen and (max-device-width : 600px) and (-webkit-max-device-pixel-ratio: 1),
only screen and (max-device-width : 600px) and ( max-device-pixel-ratio: 1) {
.bg-image-wedding {
background-image: url(img/photo-wedding_600x400.jpg);
}
}
/* example media query for retina ipad and up */
@media
only screen and (min-device-width : 768px) and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-device-width : 768px) and ( min-device-pixel-ratio: 1.5) {
.bg-image-wedding {
background-image: url(img/[email protected]);
}
}
Wrapping Up
Until the day where CSS3’s object-fit
is supported, which may be a while, this hybrid option seems like the best approach to me. Still, it’s nice to have options. I hope you got something out of my way-too-thorough exploration. You can take a look at the source code for more (Option One, Two, or Three), or download the example files here. If you have any questions, comments, or corrections, drop me a line: parker@parkerbennett.com.
* You can make an img upscale like a background-image if you want. You just need to “pre-enlarge” it, adding a proportionately larger width and height to the img element itself: <img width="2400px" height="1600px" src="img/photo-wedding_1200x800.jpg />
(edit on CodePen).
Looks like someone’s about to get bludgeoned to death in the background :S
lmfaooo! well spotted :)
Made me look closer at the image. A couple of other interesting people there to.
Would have loved to see the snap a second or so later…
Hey Parker,
Nice post! I follow this website on my feed reader, and I enjoy it a lot.
About your post:
What about using background-size:100% and background-position:bottom center ?
< div style=”display:block; width:100%; height:300px; background-image:url(http://cdn.css-tricks.com/wp-content/uploads/2013/06/photo-wedding_1200x800.jpg); background-position:bottom center; background-size:100%;”>
http://jsfiddle.net/gomidefabio/BVXGj/1/
Thanks, Fabio! You can see how
background-size:100%
differs by resizing the pane smaller than the aspect-ratio of the image. In your example the image repeats vertically. We can addbackground-repeat: no-repeat
, but with the image bottom center, we see a gap above the image because the div remains 300px in height as the image gets smaller. Withbackground-size:cover
, the image fills that gap but crops on the sides.Thank you for this great post. I’m building a piece as we speak and with just one line of your example you fixed about 5 problems for me. Great post.
Great article about css, quality content for front-end engineer!!!
Is there an easy way to pan this image with mouse (to see rest of the photo)?
Or you can use the padding trick to keep a responsive aspect ratio and center the image within that.
Thanks, Corey! I added this “padding trick” to the CodePen for Option One for comparison.
The problem with this is it doesn’t restrict the height of the image, which was how I started down this path (I had a client who wanted things “above the fold”). It acts a lot like
max-width:100%
on an img, except you have some cropping flexibility usingbackground-position
and varying thepadding-bottom
.^ this.
You can even do this on the img element itself to avoid using an extra wrapper DIV.
And how about replacing img src in hybrid option with inline 1x1px size transparent image to avoid loading both http://parkerbennett.com/croptop/img/photo-wedding_1200x800.jpg and http://parkerbennett.com/croptop/img/photo-wedding_600x400.jpg on startup (chrome loads both images). It might be not quite semantic-friendly, but reduces one request.
You can — and you can eliminate the http request entirely by coding the 1-pixel gif as a data uri:
img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
But apart from being less semantic and user-friendly, it doesn’t work to set an aspect ratio by declaring a height and width — as your image scales down it becomes a square. I appended the CodePen for Option Three to demonstrate this. (You could create a transparent gif with a matching aspect ratio, e.g., 3px by 2px, if maintaining that is important.)
Hi Parker,
You are right. I noticed that a few seconds after I sent the comment. Sorry about that. So I immediately created a JSFIDDLE test and posted it here, but for some reason it didn’t save the last version of the code. I put it there again, in case you want to take a look. However that fix is only suitable if the images used into those boxes keep a specific aspect ratio.
Ps.: I’m not sure if you wanted anybody to keep filling you comment area with extra ideas (like I’m doing), but I just liked the question involving your post, so tried to see how I would do it myself. Maybe someone can improve the approach I gave to the question.
http://jsfiddle.net/gomidefabio/BVXGj/15/
Hey, this is great, Fabio — this is exactly the kind of exchange of ideas I was hoping for!
To sum up, Fabio suggested a refinement of Option One: When the image width is in proportion to the declared height, use a media query to switch the height to auto. Now the image will continue to scale down in proportion. Smart!
Ah. I should clarify, Fabio. Your approach works, but it’s basically duplicating what
max-height:500px
would do, without needing a media-query. That’s the advantage of using a transparent placeholder img — it provides the height we would otherwise need to specify for the background-image to display, and we can restrain it with min-width, max-width, min-height or max-height.Great post Chris – it came in at the right time as I was working on something similar. I admit it, I am going to bite the code but give credit where it’s due :-)
Hey, I neglected to mention that you can fine-tune cropping with
background-position
by using percentages, e.g.,background-position: 30% 60%
. I revised the CodePen on Option Three to demonstrate.Oh boy! Thanks a lot for this post! It saved me a ton of work. The
background-size:cover
property is awesome. Thanks again!