Reputation: 225
I'm trying to center and scale an image inside a container. In the following diagrams, the pink box is a 16:9 container and the blue box is the image.
If the image is wider than the container, it will scale to fit.
If the image is taller than the container, it will also scale to fit.
If the image fits in the container, it will simply be centered.
As you can see in the diagrams, there is also a caption div aligned to the bottom left of the image, and a close icon aligned to the top right.
Here is the code I have now:
/* The page */
.container {
width: 100%;
height: 100%;
}
/* 16:9 container */
.imageWrapper {
padding-bottom: 56.25%;
position: relative;
width: 100%;
border: 1px solid red;
}
.imageInnerWrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
}
/* The image, footer and close button all need to fit inside the container */
.imageAndFooterWrapper {
display: inline-flex;
flex-direction: column;
position: relative;
border: 1px solid lightblue;
}
.image {
max-height: 100%;
object-fit: contain;
}
.footer {
text-align: left;
}
.closeButton {
position: absolute;
top: -30px;
right: -30px;
}
<div class="container">
<div class="imageWrapper">
<div class="imageInnerWrapper">
<div class="imageAndFooterWrapper">
<img class="image" src="https://images.theconversation.com/files/204986/original/file-20180206-14104-1hyhea9.jpg?ixlib=rb-1.1.0&rect=0%2C1212%2C5550%2C2775&q=45&auto=format&w=1356&h=668&fit=crop">
<div class="footer">
Caption
</div>
<div class="closeButton">X</div>
</div>
</div>
</div>
</div>
The following CodePen contains the above code, with some examples of different sized images.
https://codepen.io/anon/pen/NMKxxm
Upvotes: 3
Views: 1363
Reputation: 4830
This may not be a direct answer to your question but usually when I have to do something like this, I use a div
with a background image instead of an img
tag. Using a div with a bg image allows you to use styles like background-image
, background-position
and background-size
which allow you to create the effect as described by you.
Sample:
var imgDiv = $('.image')[0];
var closeButton = $('.fixed-el')[0];
var img = document.createElement('img');
img.src = getComputedStyle(imgDiv).backgroundImage.split('"')[1];
var calculate_positions = {
img_width: img.naturalWidth,
img_height: img.naturalHeight,
img_ratio: function() {
return calculate_positions.img_width / calculate_positions.img_height;
},
elm_ratio: function(elm) {
return $(elm).width() / $(elm).height();
},
img_offset: function(elm) {
var offset = []; //[x,y]
if (calculate_positions.elm_ratio(elm) > calculate_positions.img_ratio()) {
//centered x height 100%
var scale_percent = $(elm).height() / calculate_positions.img_height;
var scaled_width = calculate_positions.img_width * scale_percent;
var x_offset = ($(elm).width() - scaled_width) / 2;
offset = [x_offset, 0];
} else {
//centered y width 100%
var scale_percent = $(elm).width() / calculate_positions.img_width;
var scaled_height = calculate_positions.img_height * scale_percent;
var y_offset = ($(elm).height() - scaled_height) / 2;
offset = [0, y_offset];
}
return offset;
}
}
function updatePosition() {
var offset = calculate_positions.img_offset($('div.image'));
closeButton.style.top = offset[1] + 'px';
closeButton.style.left = offset[0] + 'px';
}
$(window).resize(updatePosition)
$(img).load(function() {
updatePosition();
});
div.image {
width: 100%;
background-image: url('http://via.placeholder.com/100x100');
background-position: center;
background-size: contain;
background-repeat: no-repeat;
flex: 1;
}
html,
body,
div.container {
width: 100%;
height: 100%
}
div.container {
display: flex;
position: relative;
flex-direction: column;
}
div.fixed-el {
position: absolute;
width: 20px;
height: 20px;
background: red;
}
div.caption {
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="image"></div>
<div class="caption">Some caption here</div>
<div class="fixed-el"></div>
</div>
EDIT: You can change the image size in the styles and resize the window to see the scaling in action.
I also noticed the comment which mentioned that you do not want to use background image as it will clip the image. This will not happen if you use background-size:contain
EDIT 2: It turns out you can actually figure out what the coordinates of the image are and position other elements around it. Have created a dirty hack to demonstrate this (mixed jQuery and vanilla JS, no proper scoping etc).. But you should be able to get the main idea and implement a neater solution. The main idea is derived from this question on SO
Upvotes: 1