Maintain aspect ratio of background-image - javascript

I need to present images in a container using the CSS property background-image
The problem here is that I need to present every image keeping the aspect ratio of it, and maximize the presentation of the image to the height or width of the image centered inside the container.
HTML:
<div class="fotowind shadow"></div>
EDIT:
Initial CSS properties of the .fotowind container:
.fotowind {
overflow:hidden;
margin-left:10px;
background:#333;
margin-bottom:5px;
z-index:30;
background-position: center center !important;
background-repeat: no-repeat;
}
Code to build the properties dynamically based in the size of the window - I need to resize the image keeping the ratio, even of some empty space as to remain on the sides:
jQuery:
windowWidth = $(window).width();
windowHeight = $(window).height();
if (windowWidth <= 1200 && windowWidth > 768 || windowHeight < 900)
{
$('.fotowind').css('width', '650px').css('height', '425px');
}
else if (windowWidth > 1200 || windowHeight > 900)
{
$('.fotowind').css('width', '950px').css('height', '650px');
}
if (windowWidth <= 768)
{
$('.fotowind').css('width', '450px').css('height', '425px');
}
Resulting HTML:
<div class="fotowind shadow" style="background-image: url(http://localhost/AdPictures/25/2c/c2/4c/-9/77/1-/4b/77/-b/ff/a-/57/e5/10/2b/31/b1/7516_1_xl.jpg); background-size: 100%; width: 950px; height: 650px; background-position: 50% 50%; background-repeat: no-repeat no-repeat;"></div>
In some situations where an image has size 800x600, for example, I can't present it with this size, or when the image has 200x650, for example, it deforms to the container size.

As I saw that you are already using jQuery, so I assume that you are open to jQuery solution, because, as I read your comment which says
I want to center the background-image if the viewport size exceeds
the original image size, and if it's equal to or less than the real
size, than you want a responsive background
So here, I am using jQuery to detect the windows height and width and accordingly am resizing your background-image
Demo
$(window).on('resize', function() {
if($(window).width() < 300) { //original idth of your background image
$('div.fotowind').css('background-size', '100% auto');
} else if($(window).height() < 300) { //original height of your background image
$('div.fotowind').css('background-size', 'auto 100%');
} else {
$('div.fotowind').css('background-size', 'auto');
}
});
There is no CSS solution as such because we don't have max-width and max-height for background-size so if you are looking for a pure CSS solution, than you will need an absolute positioned img tag, with max-height and max-width defined with a z-index set to negative, but still you will face some issues regarding the element center positioning...
After you commented, you said that the images will be dynamic in dimensions, and the container will be fixed so..
Here, now the code is completely compatible with your fixed width container elements.. you need to do nothing now and it's completely dynamic, also thanks to this answer which helped me to fetch the height and width of the image
$(document).on('ready', function() {
var image_url = $('div.fotowind').css('background-image'), image;
// Remove url() or in case of Chrome url("")
image_url = image_url.match(/^url\("?(.+?)"?\)$/);
if (image_url[1]) {
image_url = image_url[1];
image = new Image();
image.src = image_url;
}
// just in case it is not already loaded
$(image).load(function () {
imgwidth = image.width;
imgheight = image.height;
if($('div.fotowind').width() < imgwidth) {
$('div.fotowind').css('background-size', '100% auto');
} else if($('div.fotowind').height() < imgheight) {
$('div.fotowind').css('background-size', 'auto 100%');
} else {
$('div.fotowind').css('background-size', 'auto');
}
});
});
Few demos to illustrate the above code in action...
Demo 1 (Where image size > than the elements size)
Demo 2 (Where container size > image size)
Demo 3 (Where image height > container height)
Demo 4 (Where image height > container height [2])
Demo 5 (Where image width > container width)

You can use background-size: cover
body {
margin: 0
}
.fotowind {
background: url(//placehold.it/400) fixed no-repeat center / cover;
min-height: 100vh /*demo purposes*/
}
<div class="fotowind shadow"> </div>
See more info on this article

I tried to propose two different solution, one with a background-image and the other one with an image tag.
Here is the code:
HTML
<div class="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/e/e2/Mei_Foo_Station_2.JPG" alt="foo" />
<div class="bg"></div>
<div class="bg bg_h_s"></div>
<div class="bg bg_h_m"></div>
<div class="bg bg_h_l"></div>
<div class="bg bg_w_s"></div>
<div class="bg bg_w_m"></div>
<div class="bg bg_w_l"></div>
</div>
CSS
.container {
text-align: center;
background-color: grey;
}
.bg {
background: url(https://upload.wikimedia.org/wikipedia/commons/e/e2/Mei_Foo_Station_2.JPG) no-repeat center center blue;
-webkit-background-size: contain;
background-size: contain;
height: 480px
}
img, .bg {
width:100%;
max-width:640px;
margin: 30px auto;
}
.bg_h_s {
height:100px;
}
.bg_h_m {
height:200px;
}
.bg_h_l {
height:300px;
}
.bg_w_s {
width:200px;
}
.bg_w_m {
width:400px;
}
.bg_w_m {
width:600px;
}
Here is the working codepen

Related

CSS/JS: mimic background-image cover using image element with known width and height

I am trying to create letterboxes for video thumbnails in css. Thumbnails can be any size but I want them to fit within a box with a fixed aspect ratio of 16:9. This is easy to accomplish if I use the background-image properties. See the example below:
.container {
background-color: gray;
position: relative;
width: 100%;
padding-top: 56.25%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.container1 {
background-image: url("https://bulma.io/images/placeholders/640x480.png");
}
.container2 {
background-image: url("https://bulma.io/images/placeholders/720x240.png");
}
<div class="container container1">
</div>
<br/>
<div class="container container2">
</div>
However, using background-image introduces a few problems. I only want the background of .container to be gray while the thumbnail is loading, once it has loaded I want it to be black. I also want to replace the thumbnail url with a default thumbnail url if for some reason the thumbnail fails to load. I cannot think of a way to do this without being able to use the onload and onerror events of an actual image element.
Fortunately, since in my actual code I am fetching the thumbnail urls dynamically I can also return the width and height of a thumbnail so I know it before I try to load it. However, I cannot figure out how to convert the width and height of the thumbnail into the correct percent it needs to be to cover the center of the box the same way the first example does using background-image. See the example below:
let c1ThumbnailWidth = 640;
let c1ThumbnailHeight = 480;
let c2ThumbnailWidth = 720;
let c2ThumbnailHeight = 240;
$( document ).ready(function() {
$('.container1 img').css('left', 100 * (1 - (9 / 16) * (c1ThumbnailWidth / c1ThumbnailHeight)) / 2 + '%');
$('.container2 img').css('left', 100 * (1 - (9 / 16) * (c2ThumbnailWidth / c2ThumbnailHeight)) / 2 + '%');
$('.container img').one('load', function() {
$(this).parent().css('background-color', '#000');
});
$('.container img').on('error', function () {
$(this).attr('src', 'default.jpg');
});
});
.container {
background-color: gray;
position: relative;
width: 100%;
padding-top: 56.25%;
}
.container img {
position: absolute;
top: 0;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container container1">
<img src="https://bulma.io/images/placeholders/640x480.png">
</div>
<br/>
<div class="container container2">
<img src="https://bulma.io/images/placeholders/720x240.png">
</div>
How can I make the image element mimic the behavior of a background-image set to cover or alternatively how can I tell when a background-image has loaded or failed to load and adjust it accordingly?
Have you tried using CSS object-fit on the image element?
https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit

div percentage height does not work as intended - inside fixed div

issue:
http://jsfiddle.net/um2b98we/5/
I have a small problem. I try to create a navigation where the child (blue box) div is 75% screen height. I have no problems at all, as long as the parent (green box) is in relative position.
However, when I scroll down, I want the parent to be fixed on top of the screen. However then the child changes the height to 75% of the parent but I need it to keep being 75% height of the screen
for sample code, go to the link above:
#scroll, #header, #one, #two {width: 100%}
#scroll {height: 2000px;}
#one {
background: red;
height:50px;
}
#two {
background: green;
height:50px;
}
#two.fixed{
position:fixed;
top:0;
}
#sub {
position: absolute;
height: 75%;
width: 80%;
background: blue;
margin-top:50px;
}
<div id="scroll">
<div id="header">
<div id="one"></div>
<div id="two">
<div id="sub"></div>
</div>
</div>
</div>
I have been trying to fix it for a long time without any success. I would appreciate the help.
You could give the div height with javascript:
$(window).bind('scroll', function(){
var windowHeight = $(window).height();
$('#two').toggleClass('fixed',$(window).scrollTop() > 50);
$('#sub').css('height',windowHeight *.75);
});
or add it after you applied the fixed class to it:
$(window).scroll(function() {
var scroll = $(window).scrollTop(),
windowHeight = $(window).height();
if (scroll >= 50) {
$("#two").addClass("fixed");
$('#sub').css('height', windowHeight *.75);
} else {
$("#two").removeClass("fixed");
}
});

Center an image inside of a responsive viewport without it losing its aspect ratio

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.
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.
jsfiddle
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.
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".
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.

displaying image of unknown size inside div of fixed size

I have a <div> of fixed size say height:100px and width:100px.
I have to display images of unknown size inside this <div> such that following cases arise:
image width > div width
image width < div width
image width = div width
image height > div height
image height < div height
image height = div height
no matter what, what is the best cross browser strategy, with support for legacy browsers, to display them with following criteria:
no white space around image
nicely centered (horizontally and vertically) if overflow
To eliminate white space, set min-height and min-width to 100% for the images. To clip the overflow, set overflow: hidden on the div. To center overflowing images, use absolute positioning and some JavaScript to set top and left values based on the size of the image.
Edit: If the image is larger than the container in both dimensions, use some JavaScript to remove the minHeight and minWidth and then set the height to 100%. If that leaves whitespace on the width, set height to "" and set width to 100%:
.centeredImageContainer {
height: 100px;
width: 100px;
overflow: hidden;
position: relative;
}
.centeredImage {
min-width: 100%;
min-height: 100%;
position: absolute;
}
function centerImage(img) {
var container = img.parentNode;
if (img.offsetHeight > container.clientHeight &&
img.offsetWidth > container.clientWidth) {
img.style.minHeight = "0";
img.style.minWidth = "0";
img.style.height = "100%";
if (img.offsetWidth < container.clientWidth) {
img.style.height = "";
img.style.width = "100%";
}
}
img.style.top = ((container.offsetHeight - img.offsetHeight) / 2) + "px";
img.style.left = ((container.offsetWidth - img.offsetWidth) / 2) + "px";
}
jsfiddle.net/QRU4w/2
edit:
fiddle
html:
<div id="myPic"></div>
css, if you want a big pic to shrink to fit while still filling the whole div, and want a small pic to expand to fill the whole div:
#myPic{
width: 100px;
height: 100px;
background-image: url(/abs/path/img.jpg);
background-size: cover;
}
css, if you want a big pic to only display a window of the middle without resizing:
#myPic{
width: 100px;
height: 100px;
background-image: url(/abs/path/img.jpg);
background-position: center center;
}
I don't know of a way to both expand small images to fit, while not shrinking big images.
If you mean that you need to have no whitespace including above a landscape-oriented image, for example (i.e. the photo needs to fill the square, regardless of whether it is originally a square), then you may want to look into setting the image as the div's background and using background-size: cover. See this link for browser support.
The best way to do this is by using object-fit property.
.image-container {
width: 400px;
height: 300px;
}
.centered-image {
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="image-container">
<img src="https://24seven.co.ke/uploads/sliders/1550944223ecommmerce.jpg" alt="24seven Developers slider" class="centered-image">
</div>
For more illustrations and geeks see this.

Div Square, width size based on 100% height

I'm trying to make a responsive square with the width size based on the (100%) height of the element. I believe it's impossible using only CSS.
The square width should be equal to the height (100% of the large container. The large container is more than 100% of the screen). The ratio has to be width=height to keep the square.
You could do this with a tiny inline image.
No JS, no extra files.
.container {
height: 150px;
width: 100%;
text-align: center;
background: #acd;
}
.square {
display: inline-block;
height: 100%;
background: #691;
}
<div class="container">
<div class="square">
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" height="100%">
</div>
</div>
For a CSS-only solution (where you're sizing relative to the screen size), use viewport units. For example:
#media screen and (orientation:landscape) {
.box{
height: 100vh;
width: 100vh;
}
}
#media screen and (orientation:portrait) {
.box{
height: 100vw;
width: 100vw;
}
}
(You may want to reduce it to 98 units to eliminate scrolling)
Works great for divs that need to take up a precise proportion of screen space.
JSFiddle here.
Take a look... at the aspect-ratio property.
This property makes creating a square div based on height, in the easiest method possible. Here's some example code:
h2 {
font-family: calibri;
}
#parent {
height: 96px;
width: 256px;
background: grey;
margin-bottom: 16px;
}
#child {
height: 80px;
aspect-ratio: 1 / 1;
background: lightgrey;
}
#anotherParent {
height: 96px;
width: 256px;
background: grey;
}
#anotherChild {
height: 50%;
aspect-ratio: 1 / 1;
background: lightgrey;
}
<h2>Absolute height (80px/96px)</h2>
<div id="parent">
<div id="child">
</div>
</div>
<h2>Relative height (50%)</h2>
<div id="anotherParent">
<div id="anotherChild">
</div>
</div>
Here are a couple of links to help you understand the aspect-ratio property:
https://css-tricks.com/almanac/properties/a/aspect-ratio/
https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
https://support.squarespace.com/hc/en-us/articles/115008538927
Since a square has same width and the height, and you know the width of the square, you can apply the same value to height.
If you can use JS, then please try this: (jQuery)
var wiDth = $('div').css('width'); // get width
$('div').css('height', wiDth); // apply that value to the height
Try it here: http://jsfiddle.net/afzaal_ahmad_zeeshan/vpGUK/
You can accomplish this using javascript. I'm assuming that you have a larger div container, in which you want a square, whose height is the same height as the container. The html is as follows:
<div id="container">
<div id="square" style="height:100%;">
</div>
</div>
In javascript, you would simply do:
<script>
var container = document.getElementById("container");
var square = document.getElementById("square");
square.style.width = container.style.height;
window.onresize=function(){
square.style.width = container.style.height;
};
<script>
Hope that helps
I think this can be a good 'css only' solution for you.
Cross browser working.
http://absolide.tumblr.com/post/7317210512/full-css-fluid-squares
Good to highlight this nice css rule:
If the vertical paddings (and margins) are specified in percent (%) values the size is a percent of the width of the containing element.
Put it on your <script src="http://code.jquery.com/jquery-1.10.2.js"></script> and try with jquery:
var totalHeight = 0;
$("#yourContainer").children().each(function(){
totalHeight += $(this).height;
});
$("#yourContainer").css('width', totalHeight + 'px');
Ok here the solution.
<div id="square" style="background-color:black;height:100%">test</div>
$(window).ready(updateWidth);
$(window).resize(updateWidth);
function updateWidth()
{
var square = $('#square');
var size = square.height();
square.css('width',size);
}
http://jsfiddle.net/j372H/7/
You can assign width and height to the container like this
.container {
width: 100vh;
height: 100vh;
}
It will create a square div with 100% height and width=height.

Categories

Resources