What's the right way to auto-scale images such that they fit exactly inside the browser window, while preserving their aspect ratio?
The images in the DNA Lounge photo and flyer galleries auto-scale to fit in the window. However, this only works horizontally. If the image is wider than the window, it shrinks, but if the image is still taller than the window, it does not. I'd like to make it scale in both directions, so that on an iPhone, both portrait and landscape images default to being fully visible, regardless of the phone's orientation.
The current (horizontal-only) behavior is is accomplished in CSS. The image has:
- width:100%; height: auto;
max-width:900px; max-height:600px;
I think that there's no way to make the image fit within the window using only CSS (and also preserve the image's aspect ratio). I think the only way to accomplish that is with Javascript.
So I tried this:
function scale_images() {
var maxw = window.innerWidth;
var maxh = window.innerHeight;
var aa = document.images;
for (var i = 0; i < aa.length; i++) {
var img = aa[i];
var w = img.naturalWidth;
var h = img.naturalHeight;
var r = h/w;
if (h > maxh) {
h = maxh;
w = h/r;
}
if (w > maxw) {
w = maxw;
h = w*r;
}
img.style.width = w + "px";
img.style.height = h + "px";
}
}
document.body.onload = scale_images;
document.body.onresize = scale_images;
document.body.onorientationchange = scale_images;
Well, that sort-of works, except that the viewport sizes I'm getting on iPhone are weird. In portrait mode, I am getting a 320x356 viewport (as expected) but when I rotate to landscape, I'm getting 320x139 instead of 480x208, which means the document is scaled up and the font size increases. What's the fix for this, short of disabling all scaling (even pinch-zooming)?
Surely others have solved this problem? Got examples?
Check out image viewing in search.
Yeah well, the AJAX nightmare in there is absolutely no help, unless you can explain what they are doing.
In modern browsers, you could do something like:
<div style="width: 100%; height: 100%; background-image:url(foo.jpg); background-size: 100% 100%;"></div>
Of course if you then want to click on it, you'll want to add a click handler to the div, as well as cursor:pointer.
That screws up the aspect ratio exactly like "width:100%; height:100%" does.
Hm. You're sort of right. It doesn't mess up the aspect ratio, but it does clip in a bad way. Lame.
That's because you said "background-size:100%" instead of "background-size:100% 100%", making it the same as "width:100%; height:auto".
You will want to use CSS3 media queries.
Examples.
I know how media queries work and I don't see how they are even remotely relevant here.
Ouch. While I'm not sure this will work (I avoid web development like the plague), I can at least see how this might be relevant:
If you know the aspect ratio of your image (i.e. it doesn't change from image to image), you could use the media query regarding the aspect ratio of the display area to conditionally make it either width 100% + height auto or vice versa.
E.g. for max-aspect-ratio: 4/3 do one thing
for min-aspect-ratio: 4/3 do the other thing
I'm not sure whether the intersection of the two cases need special handling, or that won't be a problem...
Indeed - that was the wrong target. Instead, simply assign custom CSS classes depending on image aspect ratio:
Tested on iPhone and iPad.
PS: Ahem, forget about
onresize
andonorientationchange
. It's not like your images change upon those events.So, imagine you have a square image. If you have to pick between "width:100%" and "height:100%", it's going to work when the window is portrait, or landscape, but not both. Using portrait versus landscape classes isn't the same as "fit box A inside box B".
Anyway. I have the "fit inside the box" code working in the code I posted, the weird part that I still don't understand is why, when I rotate the phone, my viewport is 320 wide instead of 480.
Out of interest, do you get 320x139 only when loading in portrait mode and rotating (ie, after the orientationchange fires), or also when you load in landscape mode? Observing some pages through orientation change on my iPhone I get the impression that there's a choice made to just scale everything up on changing from portrait to landscape, rather than to reflow the page. Reloading the page after the orientation change gets it reflowed, differently, for the wider width. (Once I noticed this effect I'd occasionally deliberately rotate to portrait before loading then switch back to landscape, in order to get a larger font without having to scroll back and forth as a result of pinch-zooming.) So I'm wondering if the way this is achieved is by keeping the reported viewport width constant through the orientation change, and just applying a scaling factor to what gets rendered.
Ewen
I get 320 wide in landscape even if I hit reload while in landscape, so it seems consistent.
CSS3 media queries would come in handy for figuring out the orientation of the screen, then use height/width auto on the appropriate dimension:
You might make the case that it's not precisely what you asked for, as it won't always fit on the screen without scrolling. I'd make the case that I hate having to pinch-zoom images that are fit to screen, because I've got a pretty, hi-def device, and would rather scroll in one dimension than see some scaled-down version that wastes a ton of screen real estate.
It'll be borked on noncompliant browsers, but it is at least forward-compatible and you can hold out hope that eventually the browsers will catch up.
Actually, it may be even easier than that -- no fancy hackery needed. I've got a test page here:
http://rickosborne.org/test/bigpic.html
It sets the dimensions of the html and body to 100%, then just sets image max-width and max-height, completely ignoring the width and height. I don't have an iPhone to test on, but it does work on my Android, which I hope is pretty close.
Inconsistent behavior in desktop Safari: start with window big; fully shrink horizontally; fully shrink vertically, enlarge vertically; now image has wrong aspect ratio.
Also, you are right, this isn't what I asked for. Many of the images I have are not 4:3 or close to it, because I'm dealing not only with photos but with flyers, and those come in all shapes and sizes.
If you specify "max-width", you always have to specify "max-height: auto" or it does stupid things in MSIE (all versions, I think.) Likewise for width/height, I think.
I would suggest asking at stackoverflow.com. I've got surprisingly good answers to most questions I've asked there, and as a bonus the lame ones are modded down so you don't have to read through annoying and irrelevant stuff.
Try setting initalScale=1.0 on your viewport meta tag.
I think this:
http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html#//apple_ref/doc/uid/TP40006509-SW1
Is trying to tell you what's happening. Of course webkit on android does it slightly differently.
First thing I tried. Setting initial-scale=1.0 does nothing.
Setting "maximum-scale=1.0" gets me proper viewports of 320x356 and 480x268, but disables pinch-zooming.
Oh wait, upon further investigation, initial-scale=1.0 doesn't do nothing... if you load the page in portrait, and then rotate, the viewport is still 320 wide when in landscape. But if you then 1) zoom all the way out and 2) hit reload, now the viewport is 420 wide. So, that's not useful, but at least it's not being ignored...
I'm not clear on what "-webkit-text-size-adjust:none" is supposed to do, but I also haven't seen that do anything at all.
I haven't tested it with MSIE (because I don't want to know, really), but http://pyvore.com/junk/ does what I think you want, on the webkit and mozilla I tested it on.
The scaling works, but using a bg image for that is weak in myriad ways: 1) no context menu with "save image as", etc.; since it's not in document flow, there's no way to put navigation links and stuff at the top that don't overlap the image (e.g.); by not using the IMG tag, it does not degrade gracefully on more primitive phones; and probably other stuff I haven't thought of.
If you do an update, will you please put it in a new post linked from an update here? I don't want to miss what you decide on.
There's some hacky bullshit in http://www.dnalounge.com/gallery/gallery.js and http://www.dnalounge.com/dnalounge.css, specifically the "@media screen and (max-device-width: 480px) and (orientation:landscape)" part.