Reputation: 15
What I'm trying to do is to center and resize an image that's inside of a viewport (or a parent element), without stretching it.
To make a very long story short, I want the images to keep their aspect ratio and be resized so that they cover up the viewport completely.
This is my HTML layout:
<div class="media-area" data-size="b" data-type="2">
<ul class="content-slider">
<li class="cs-item">
<img class="cs-background" src="assets/img/backgrounds/top-slider-1.jpg" alt="slider-element">
</li>
<li class="cs-item">
<img class="cs-background" src="assets/img/backgrounds/top-slider-2.jpg" alt="slider-element">
</li>
<li class="cs-item">
<img class="cs-background" src="assets/img/backgrounds/top-slider-3.jpg" alt="slider-element">
</li>
</ul>
</div>
This is my CSS:
.media-area {
width: 100%;
height: 100%; /* Standard height */
position: relative;
overflow: hidden;
}
.media-area .content-slider {
position: relative;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.media-area .content-slider .cs-item {
position: relative;
display: block;
float: left;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.media-area .content-slider .cs-item img {
display: block;
}
.media-area .content-slider .cs-background {
-webkit-transition: all .1s ease-in-out;
-moz-transition: all .1s ease-in-out;
-o-transition: all .1s ease-in-out;
transition: all .1s ease-in-out;
}
And this is my JS:
function mediazone() {
var defaults = {
elem: ".media-area",
elemWrap: ".media-area .content-slider",
elemSlide: ".media-area .content-slider .cs-item",
vh: $(window).height(),
vw: $(window).width()
};
$(defaults.elemSlide).find(".cs-background").each(function () {
var bkndImgW = $(this).width(); // Current image width
var bkndImgH = $(this).height(); // Current image height
var mediaViewPortW = $(this).parents(defaults.elem).width(); // Current media viewport width
var mediaViewPortH = $(this).parents(defaults.elem).height(); // Current media viewport height
// Used for viewport aspect ratio
var viewportratio = Math.round((mediaViewPortW / mediaViewPortH) * 100000 ) / 100000;
// Used for image aspect ratio
var imageratio = Math.round((bkndImgW / bkndImgH) * 100000 ) / 100000;
// Negative margins for when the height is larger than the width
var bkndImgPosW = ((bkndImgW - mediaViewPortW) / 2)*-1;
// Negative margins for when the width is larger than the height
var bkndImgPosH = ((bkndImgH - mediaViewPortH) / 2)*-1;
bkndImgPosW = Math.min(0, Math.max(bkndImgPosW, bkndImgPosW));
bkndImgPosH = Math.min(0, Math.max(bkndImgPosH, bkndImgPosH));
if (viewportratio > imageratio) {
$(this).removeAttr("style");
$(this).css("min-height", "100%");
$(this).css("width", "100%");
$(this).css("margin", bkndImgPosH+"px 0px");
} else if (viewportratio < imageratio){
$(this).removeAttr("style");
$(this).css("height", "100%");
$(this).css("min-width", "100%");
$(this).css("margin", "0px "+bkndImgPosW+"px");
} else if (viewportratio == imageratio) {
$(this).removeAttr("style");
}
});
}
The function is initialized here:
$(document).ready(function () {
mediazone();
});
$(window).resize(function () {
mediazone();
console.log('window resize event');
});
The problem I'm faced with right now is that when the page loads, the image is half-way out of the viewport, but when I resize the browser window, it fits perfectly.
Another problem I can't really find a way around right now is the one with the two aspect ratio's being equal ( i couldn't find a way to make the image cover the screen without having to deal with some white spaces). This makes the image flicker when the aforementioned scenario is under way.
It is important that I use the IMG tag in the DOM, otherwise maybe there would have been a way to make use of the "background-image" property in CSS.
Can anyone point out what I'm missing/ doing wrong/ I should delete?
Kind regards,
Alex
* Later Edit *
This is what I have right now:
http://jsfiddle.net/LexEckhart/Z5cjx/
After resizing, it seems to work fine and maintain the image balanced in the middle but when the page loads, the items are not positioned properly.
Upvotes: 1
Views: 487
Reputation: 1127
Since the OP specifically said he didn't want to use background-image as the image must be present in the DOM as an image, here's a jsfiddle showing a solution. I've dimmed the images using opacity to show the borders of the li's beneath it. I think the OP was overthinking the problem a bit. Anyway, hope this helps.
if (viewportratio > imageratio) {
$(this).removeAttr("style");
$(this).css("width", "100%");
$(this).css("margin", bkndImgPosH+"px 0px");
} else if (viewportratio < imageratio){
$(this).removeAttr("style");
$(this).css("height", "100%");
$(this).css("margin", "0px "+bkndImgPosW+"px");
} else if (viewportratio == imageratio) {
$(this).removeAttr("style");
}
Keep in mind that images retain their aspect ratio if you only provide one attribute / property (width OR height). That's the key to the solution.
EDIT: Updated fiddle. I played around with the math logic until it worked for the images I had, replacing your images which I used before. The math logic below the first section is possibly wrong, so it'll need further testing, but this works for what I had.
Upvotes: 1
Reputation: 413712
You can take advantage of the fact that percentage padding is always figured from the element's width. You can therefore use vertical padding with a percentage width to enforce an aspect ratio.
<div id=img></div>
// ... then in CSS:
#img {
background: url("http://placekitten.com/1280/720") no-repeat center center;
background-size: cover;
height: 0;
padding-bottom: 56.25%; /* 9:16, or 720/1280 */
}
Here is a jsfiddle to demonstrate. If you don't know the aspect ratio in advance, you can of course compute it and set the "padding-bottom" dynamically via JavaScript.
Thanks are due to the inimitable Dave Rupert for this technique.
edit ah, the <img>
tag in that ending paragraph was hidden. You can employ a variation of this trick if you really need an <img>
tag:
<div class=image-centerer>
<img src='http://whatever.com/your/image.png'>
</div>
// ... then in CSS:
.image-centerer {
position: relative;
height: 0;
padding-bottom: 56.25%;
}
.image-centerer img {
position: absolute;
display: block;
height: 100%;
}
Fiddle demo, and here is one demonstrating the handling of arbitrarily-proportioned images.
Upvotes: 0
Reputation: 385
You can give try for
"background-size" and "align-items" properties from css3.
set "background-size:100% 100%;"; it will cover (parent window);
For aligning contents in center you could use "align-items:center".
Upvotes: 0