displaying image of unknown size inside div of fixed size - javascript

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.

Related

object-fit:cover resizes img width

I'm trying to make a carousel slide, but when I'm using object-fit:cover and adding the second image the first and the second image width are changing from 100% to 50%
on 1 input it works fine
See photo here
on second input it's changing its width
See photo2 here
I think the object-fit:cover property can be set with the width property.
image {
width: 100%;
object-fit: cover;
}
Then the image places appropriately so that it's width is 100%.
If you really want img to be 100% in flex layout you can use one of these options:
img {
width: 100%;
flex-shrink: 0;
}
img {
min-width: 100%;
}
If smth else - update/improve your question

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

Proportional width div with 100% height (without JS?) [duplicate]

I need to maintain the width of an element as a percentage of its height. So as the height changes, the width is updated.
The opposite is achievable by using a % value for padding-top, but padding-left as a percentage will be a percentage of the width of an object, not its height.
So with markup like this:
<div class="box">
<div class="inner"></div>
</div>
I'd like to use something like this:
.box {
position: absolute;
margin-top: 50%;
bottom: 0;
}
.inner {
padding-left: 200%;
}
To ensure the box's aspect ratio is maintained according to it's height. The height is fluid because of it's % margin - as the window's height changes, the box's height will too.
I know how to achieve this with JavaScript, just wondering if there's a clean CSS-only solution?
You can use an image that has the desired proportions as to help with proportional sizing (images can be scaled proportionally by setting one dimension to some value and other to auto). The image does not have to be visible, but it must occupy space.
.box {
position: absolute;
bottom: 0;
left: 0;
height: 50%;
}
.size-helper {
display: block;
width: auto;
height: 100%;
}
.inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(255, 255, 153, .8);
}
<div class="box">
<img class="size-helper" src="//dummyimage.com/200x100/999/000" width="200" height="100">
<div class="inner">
1. box has fluid height<br>
2. img has 2:1 aspect ratio, 100% height, auto width, static position<br>
2.1 it thus maintains width = 200% of height<br>
2.2 it defines the dimensions of the box<br>
3. inner expands as much as box
</div>
</div>
In the above example, box, inner and helper are all same size.
You can use vh units for both height and width of your element so they both change according to the viewport height.
vh
1/100th of the height of the viewport. (MDN)
DEMO
.box {
position: absolute;
height:50vh;
width:100vh;
bottom: 0;
background:teal;
}
<div class="box"></div>
There is another, more efficient way to achieve constant aspect ratio according to height.
You can place an empty svg so you dont have to load an external image.
HTML code:
<svg xmlns="http://www.w3.org/2000/svg"
height="100"
width="200"
class='placeholder-svg'
/>
CSS code:
.placeholder-svg {
width: auto;
height: 100%;
}
Change width/height to achieve desired aspect ratio.
Keep in mind, the svg might overflow.
http://www.w3.org/2000/svg is just a namespace. It doesn't load anything.
If you change placeholder-svg class to:
.placeholder-svg {
width: 100%;
height: auto;
}
then height is adjusted according to width.
Demo 1 Width is adjusted according to height and 2:1 aspect ratio.
Demo 2 same as above, but you can resize easily (uses React)
The CSS trick you wrote, works pretty well to keep ratio width / height on an element.
It is based on the padding property that, when its value is in percent, is proportional to parent width, even for padding-top and padding-bottom.
There is no CSS property that could set an horizontal sizing proportionally to the parent height.
So I think there is no clean CSS solution.
As of 2021 there is a property called aspect-ratio.
Most browsers support it
div {
border: 1px solid;
margin: 8px;
}
.box {
width: 100px;
min-height: 100px;
resize: horizontal;
overflow: auto;
}
.inner1 {
aspect-ratio: 1/1;
}
.inner2 {
aspect-ratio: 3/1;
}
<div class="box">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
Run this snippet and resize the outer div manually to see the inner divs behavior
I can't find a pure CSS solution. Here's a solution using CSS Element Queries JavaScript library.
var aspectRatio = 16/9;
var element = document.querySelector('.center');
function update() {
element.style.width = (element.clientHeight * aspectRatio) + 'px';
}
new ResizeSensor(element, update);
update();
CodePen demo!

Maintain aspect ratio of background-image

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

Scale a div to fit in window but preserve aspect ratio

How can I scale a div to fit inside the browser view port but preserve the aspect ratio of the div. How can I do this using CSS and/or JQuery?
Thanks!
You don't need javascript for this. You can use pure CSS.
A padding-top percentage is interpreted relative to the containing block width. Combine it with position: absolute on a child element, and you can put pretty much anything in a box that retains its aspect ratio.
HTML:
<div class="aspectwrapper">
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
display: inline-block; /* shrink to fit */
width: 100%; /* whatever width you like */
position: relative; /* so .content can use position: absolute */
}
.aspectwrapper::after {
padding-top: 56.25%; /* percentage of containing block _width_ */
display: block;
content: '';
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0; /* follow the parent's edges */
outline: thin dashed green; /* just so you can see the box */
}
The display: inline-block leaves a little extra space below the bottom edge of the .aspectwrapper box, so another element below it won't run flush against it. Using display: block will get rid of it.
Thanks to this post for the tip!
Another approach relies on the fact that browsers respect an image's aspect ratio when you resize only its width or height. (I'll let google generate a 16x9 transparent image for demonstration purposes, but in practice you would use your own static image.)
HTML:
<div class="aspectwrapper">
<img class="aspectspacer" src="http://chart.googleapis.com/chart?cht=p3&chs=160x90" />
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
width: 100%;
position: relative;
}
.aspectspacer {
width: 100%; /* let the enlarged image height push .aspectwrapper's bottom edge */
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0;
outline: thin dashed green;
}
Thanks to Geoff for the tip on how to structure the math and logic. Here's my jQuery implementation, which I'm using to size a lightbox so it fills the window:
var height = originalHeight;
var width = originalWidth;
aspect = width / height;
if($(window).height() < $(window).width()) {
var resizedHeight = $(window).height();
var resizedWidth = resizedHeight * aspect;
}
else { // screen width is smaller than height (mobile, etc)
var resizedWidth = $(window).width();
var resizedHeight = resizedWidth / aspect;
}
This is working well for me right now across laptop and mobile screen sizes.
I have a different pure HTML/CSS approach which does not rely on padding or absolute positioning. Instead it uses em units and relies on the CSS min() function plus a little bit of math.
Imagine that we want a viewport div with 16:9 aspect ratio which always fits the browser window and is centered in the axis with excess space. Here's how we can accomplish that:
HTML
<body>
<div class="viewport">
<p>
This should be a 16:9 viewport that fits the window.
</p>
</div>
</body>
CSS
body {
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: white;
font-size: min(1vw, 1.778vh);
}
div.viewport {
width: 100em;
height: 56.25em;
background-color: lightblue;
}
div.viewport > p {
font-size: 3em;
text-align: center;
}
You can experiment with this in a sample JSFiddle here.
The secret sauce is in the body font-size. It should be set to min(1vw, Avh), where A is the aspect ratio you want the div to have, i.e. width / height. In the example above we're using 1.778, which is approximately 16 / 9.
In CSS, em units are based on the font-size of the element, which is inherited from parent element if not explicitly set. For your viewport div, set the width to 100em (NOT rem) and the height to Iem, where I is the inverse of the aspect ratio expressed as a percentage, i.e. 100 / A or 100 * height / width. In the example above we're using 56.25, which is 100 * 9 / 16.
One bonus of this approach is that all of your nested elements may also use em units so that they always scale precisely with the size of the viewport. You can see this used on the p element in the example.
Note that as an alternative to the above, you may set the font-size on your html element and use rem units everywhere. CSS rem units are similar to em units but always relative to the root element's font-size.
Javascipt:
//Responsive Scaling
let outer = document.getElementById('outer'),
wrapper = document.getElementById('wrap'),
maxWidth = outer.clientWidth,
maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){
let scale,
width = window.innerWidth,
height = window.innerHeight,
isMax = width >= maxWidth && height >= maxHeight;
scale = Math.min(width/maxWidth, height/maxHeight);
outer.style.transform = isMax?'':'scale(' + scale + ')';
wrapper.style.width = isMax?'':maxWidth * scale;
wrapper.style.height = isMax?'':maxHeight * scale;
}
HTML:
<div id="wrap">
<div id="outer">
{{ fixed content here }}
</div>
</div>
Styling:
/* Responsive Scaling */
#wrap {
position: relative;
width: 1024px;
height: 590px;
margin: 0 auto;
}
#outer {
position: relative;
width: 1024px;
height: 590px;
transform-origin: 0% 0%;
overflow: hidden;
}
This is possible with JQuery and a bit of maths.
Use JQuery to get the view ports width and height as well as the divs current dimensions.
$(document).width();
Calculate the divs current aspect ratio. eg width/height
You need a bit of logic to determine whether to set the width or height first, then use the initial ratio to calculate the other side.
jQuery has a plugin that grows an object until one of it's sides reaches a certain px-value. Coupling this will the viewport's height, you could expand any element to that size: jQuery MaxSide.

Categories

Resources