Is it possible to fill a div with an image such that at least one image dimension is 100% and the other dimension is either wider or equal size as the div, whilst respecting the image's aspect ratio.
An example could use the classes wide and tall like this:
<div class="tall">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Klaproos.jpg/266px-Klaproos.jpg"/>
</div>
<div class="wide">
<img src="https://groenevrijdag.files.wordpress.com/2013/11/klaproos2.jpg"/>
</div>
div {
width: 400px; height: 400px;
display: block;
overflow: hidden;
border-radius: 50%;
display: inline-block;
}
div.tall img { width: 100%; margin-top: -50%; }
div.wide img { height: 100%; margin-left: -50%; }
https://jsfiddle.net/7tuod6vu/
I'm looking for a pure HTML+CSS solution which works for responsive rectangular (not necessarily square) divs. For this particular reason, Javascript would be a pain as one would need to determine whether the width or height should be 100% on every resize. Server side wouldn't even be an option.
Does a pure HTML+CSS solution exist for this?
EDIT Should have been clear about this from the beginning, sorry about that :( I'm not looking for the background-image solution, since it does not allow base64-inhtml representation of images. Moreover, I think background-image's are semantically different from <img>s.
Consider using the CSS object-fit property.
5.5. Sizing Objects: the object-fit
property
The object-fit property specifies how the contents of a replaced
element should be fitted to the box established by its used height and
width.
Here are two of the values:
cover
The replaced content is sized to maintain its aspect ratio while
filling the element's entire content box.
contain
The replaced content is sized to maintain its aspect ratio while
fitting within the element's content box.
So, with cover the image retains its aspect ratio and covers all available space. Of course, this means that much of an image may be cropped off-screen.
With contain the aspect ratio is also maintained, but the image scales to fit within the box. This means that an image may have whitespace on the left and right, or top and bottom.
Browser Compatibility
As of this writing, object-fit is not supported by Internet Explorer. For a workaround see:
Neat trick for CSS object-fit fallback on Edge (and other browsers)
fitie - An object-fit polyfill for Internet Explorer
object-fit-images - Adds support for object-fit on IE9, IE10, IE11, Edge and other old browsers
Polyfill (mostly IE) for CSS object-fit property to fill-in/fit-in images into containers.
More information
MDN object-fit property
CSS-Tricks object-fit property
object-fit browser support # caniuse.com
Here is the solution without using background images and with HTML and CSS only: http://codepen.io/anon/pen/JGGObQ
(change overflow to visible in the .container1 rule to see the full pictures. The numbers in them are their original size in pixels.)
It uses position: absolute on the images, and depending on the format (two classes, as suggested by yourself) a top or left of 50% that moves the position reference into the (horizontal or vertical) center, and a transform : translate setting that moves the position reference point of the image back from that center by 50% of their own size, which results in centering:
.container1 {
position: relative;
float: left;
margin-right: 50px;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
border: 1px solid red;
}
img.landscape {
position: absolute;
width: auto;
height: 100%;
transform: translate(-50%, 0);
left: 50%;
}
img.portrait {
position: absolute;
width: 100%;
height: auto;
transform: translate(0, -50%);
top: 50%;
}
<div class="container1">
<img src="http://placehold.it/750x500/09d/fff" class="landscape">
</div>
<div class="container1">
<img src="http://placehold.it/600x900/0d9/fff" class="portrait">
</div>
This is not the exact solution, but it could be an implementation that you could try to make your code work. Here is an example:
As you can't predict the aspect ratio of the image here is what I would do:
HTML:
Set the div tag to 'fill':
<div class="fill"></div>
CSS:
This will place your image as the background, and stretch it to fit the div size without distortion.
.fill {
overflow: hidden;
background-size: cover;
background-position: center;
background-image:"path/to/image.jpg";
}
You could set the images as the div's backgrounds instead and use backkground-size:cover
https://jsfiddle.net/3x5x0v24/
Related
Question
What should I edit to make the image be centered horizontally while fitting within the height of the containing <figure>?
The thumbnail will be 75px x 75px. Images uploaded may vary but will usually be approximately a 4:3 ratio, like 800px x 600px.
HTML
<figure>
<img src="">
</figure>
Sass
figure {
background-color: #777;
display: inline-block;
text-align: center;
overflow: hidden;
height: 75px;
width: 75px;
vertical-align: top;
position: relative;
z-index: 1;
img {
position: absolute;
z-index: 5;
height: 75px;
width: auto !important;
top: 50%;
left: 50%;
transform:translate(-50%, -50%);
}
}
Ideal Approach
The best way to do this and have good cross browser support is using a background-image instead of an actual image tag. Check out this codepen:
https://codepen.io/treyhakanson/pen/eGVVpr
Basically, using background-size: contain will cause the image to be bound by its largest dimension, while maintaining its aspect ratio, and background-position: center will center the image within its container.
Alternate Approach
If you cannot use background-image and must use img tags, check out the object-fit and object-position properties, which act similar to background-size and background-position, but for img and even video tags. It has good cross browser support, but not as good as the aforementioned method. examples of this have been added to the codepen link.
I have a viewport that takes up about 75% of the screen and I fit single images of varying aspect ratios into it using the object-fit: contain css. Above the image I have text labels for the file name & type. I want to keep these aligned to start at the left most edge of the image and end at the right most edge. I could do this easily before by aligning them to the <img> tag.
One side effect of using object-fit: contain is that the <img> element is bigger than the viewable picture, so when I try to align text to the <img> it can appear that the text is floating off of the image.
How can I align the text to the viewable image, when the img tag is expanded to fit the whole viewport but the actual picture is autoscaled inside the img tag using object-fit: contain?
The solution is very much dependent on markup, fixed widths and/or heights etc.
Assuming you don't know their width/height in advance, you'll need a script, as in below sample.
Updated: I added the opacity so the image and text display's at the same time.
If you do know them, you still need to work out a bunch of CSS animation rules, covering their ratio and animation setting to make it look good, which can be done, though it will take some work. In the end of this answer is a sample how to set an element size based on the same way fit-content calculate size.
document.querySelector('img').addEventListener('load', function(e) {
document.querySelector('.image-text').style.cssText = 'width: ' + e.target.width +'px; opacity: 1;';
})
.image-wrap {
position: relative;
height: 200px;
overflow: hidden;
border: 1px dashed gray;
margin-bottom: 10px;
}
.image-wrap img { /* fit-content replacement */
position: relative;
max-height: 100%;
max-width: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
div.image-text {
opacity: 0;
margin: 0 auto;
}
<div class="image-text">Some text we want to size and break at the same width as the image</div>
<div class="image-wrap">
<img src="http://placehold.it/500x400" alt="some image here" />
</div>
Here is another post about getting an images both natural and scaled size:
object-fit: get resulting dimensions
Started playing around with SVG and am having trouble getting it to position the way i want to. What I want to achieve is for my SVG to come in front and locked to the bottom of the border-div and be centered on the page as well as resize when the window is resized (responsive). So far I've played with the viewbox and height/width properties of the SVG to get the responsive behavior but I can't figure out to not have the SVG slip under the rest of my page(see picture to have a better idea of what's hapenning). I tried to play with the z-index and position:absolute but to no avail. Here's what I have so far for my code: (I use the bootstrap framework with SASS)
HTML
<section>
a first section
</section>
<section class="parallax1">
<div class="container-fluid">
<div class="row">
<div style="height:500px;">
<div class="col-sm-12 border-div">
<div class="col-sm-12">
<svg xmlns="http://www.w3.org/2000/svg" class="svg-test" viewBox="0 0 500 375">my SVG</svg>
</div>
</div>
</div>
</div>
</div>
</section>
<section>
Another section
</section>
CSS
.border-div{
height:100px;
background-color: $orange-background;
}
.svg-test{
left: 50vw;
width: 100%;
height: 600px;
}
.parallax1{
background-attachment: fixed;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-image: url("../images/bkgnd.jpg");
}
What i get right now is something like this:current result
And what I am looking for is this:desired result
Preliminary remarks
A few remarks about your problem, which may also explain why you haven't received any answers in such a long time:
Your problem is about the positioning of an SVG image in an HTML document. Playing around with ViewBox won't solve your problem, as this merely dictates what the SVG image should show, and not how the SVG image should be positioned within a parent document, in this case a HTML document. In fact, you could replace the SVG image with a DIV countainer and nothing would change about the solution.
It isn't really clear what you want:
Does come in front and locked to the bottom imply that you want the SVG image to appear when the user scrolls, or with some animation? Or does it mean you want the SVG to be placed there statically, independent of any event?
Does centered on the page mean horizontally only? If you meant also vertically, I don't understand how it should be in relation to the height requirements of the DIVs, or the requiement that it should lock to the bottom of the border-div.
And does resize when the window is resized only mean change its width or also its height? Because you've defined the height as 600px, which clearly won't respond to any resizing of the window.
slip under the rest of my page - I thought the SVG should be on top of everything else?
It's not clear whether the first and the last sections should have a stable width, or be responsive. And how they should relate to the 500px. A bit of CSS for them would be good.
So the 100px of border-div should be part of the 500px? In the "screenshots" it doesn't seem like it, but the code you posted suggests so.
Also, there are some inconsistencies in your formulation of the problem:
The width of the SVG is defined as 100%, but your pictures show that it's clearly not 100%. After all, if it were 100%, you wouldn't have to worry about centering it, either.
The height of the SVG is defined as 600px. If that was the case, it would be taller than the parent DIV, which is only 500px. The pictures show something different.
Last but not least, left: 50vh will make your SVG start at the horizontal center of the page, and not center it. If you want to center it, it should be (100% - width)/2 and not 100%/2.
Possible solution
In any case, here's the HTML code and the accompanying CSS styles to get what I (possibly incorrectly) interpret you are asking for:
<section id="first">
A first section
</section>
<section id="height-500">
<div id="border-div">
<div id="relative">
<div id="bottom">
<svg>
</svg>
</div>
</div>
</div>
</section>
<section id="another">
Another section
</section>
And here the CSS:
#first,
#another {
background: #808000;
height: 150px;
width: 100%;
height: 150px;
}
#height-500 {
background: green;
height: 500px;
position: relative;
}
#border-div {
background: #008080;
height: 100px;
position: absolute;
bottom: 0;
width: 100%;
}
#relative {
position: relative;
width: 100%;
height: 100%;
}
#bottom {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
svg {
display: block;
background: #f00;
width: 20vw;
height: 20vw;
margin: auto;
}
Explanation of key points
Setting the position: relative of #height-500 allows you to position #border-div at its bottom. This trick will be used again for #relative and #bottom to place the SVG at the bottom of #border-div (setting width and height to 100% allows the dimensions of #relative to be identical to #border-div).
Setting the width and height of the SVG to 20vw indicate that we want the SVG to be a square, each side being 20% of the viewport width. If you change the width of your browser, the SVG will resize too.
margin: auto are used to place block elements in the horizontal center. Note that we need to turn the SVG into a block element for this to work, by setting display: block. (Note that margin: auto doesn't work for really old browsers, but there are workarounds with some additional DIVs.)
If you want the height of the SVG remain the same, you may want to play around with the preserveAspectRatio attribute to indicate you you want to deal with the changing aspect ratio.
Note that the viewport width vw also includes the scrollbar and isn't supported by some older browsers. However, there are other methods of keeping the aspect ratio, in case that's a requirement for you.
I am trying to figure out how to re-size an image so that it keeps it ratio of width to height, but gets re-sized until the height of the image matches the height of the containing div. I have these images that are pretty large and long (screenshots), and I want to put them into a 200px width, 180px height div for display and without re-sizing the images manually. To make this look good, the sides of the image need to overflow and be hidden with the containing div. This is what I have so far:
http://jsfiddle.net/f9krj/2/
HTML
<a class="image_container" href="http://www.skintype.ca/assets/background-x_large.jpg">
<img src="http://www.skintype.ca/assets/background-x_large.jpg" alt="" />
</a>
CSS
a.image_container {
background-color: #999;
width: 200px;
height: 180px;
display: inline-block;
overflow: hidden;
}
a.image_container img {
width: 100%;
}
As you can see, there is grey color showing on the images parent container which should not be shown at all. In order for that container to be filled completely, the width needs to be overflowed equally on both sides. Is this possible? Is it also possible to account for an image that is also too tall?
Original Answer:
If you are ready to opt for CSS3, you can use css3 translate property. Resize based on whatever is bigger. If your height is bigger and width is smaller than container, width will be stretch to 100% and height will be trimmed from both side. Same goes for larger width as well.
Your need, HTML:
<div class="img-wrap">
<img src="http://lorempixel.com/300/160/nature/" />
</div>
<div class="img-wrap">
<img src="http://lorempixel.com/300/200/nature/" />
</div>
<div class="img-wrap">
<img src="http://lorempixel.com/200/300/nature/" />
</div>
And CSS:
.img-wrap {
width: 200px;
height: 150px;
position: relative;
display: inline-block;
overflow: hidden;
margin: 0;
}
div > img {
display: block;
position: absolute;
top: 50%;
left: 50%;
min-height: 100%;
min-width: 100%;
transform: translate(-50%, -50%);
}
Voila! Working: http://jsfiddle.net/shekhardesigner/aYrhG/
Explanation
DIV is set to the relative position. This means all the child elements will get the starting coordinates (origins) from where this DIV starts.
The image is set as a BLOCK element, min-width/height both set to 100% means to resize the image no matter of its size to be the minimum of 100% of it's parent. min is the key. If by min-height, the image height exceeded the parent's height, no problem. It will look for if min-width and try to set the minimum height to be 100% of parents. Both goes vice-versa. This ensures there are no gaps around the div but image is always bit bigger and gets trimmed by overflow:hidden;
Now image, this is set to an absolute position with left:50% and top:50%. Means push the image 50% from the top and left making sure the origin is taken from DIV. Left/Top units are measured from the parent.
Magic moment:
transform: translate(-50%, -50%);
Now, this translate function of CSS3 transform property moves/repositions an element in question. This property deals with the applied element hence the values (x, y) OR (-50%, -50%) means to move the image negative left by 50% of image size and move to the negative top by 50% of image size.
Eg. if Image size was 200px × 150px, transform:translate(-50%, -50%) will calculated to translate(-100px, -75px). % unit helps when we have various size of image.
This is just a tricky way to figure out centroid of the image and the parent DIV and match them.
Apologies for taking too long to explain!
Resources to read more:
https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate
https://css-tricks.com/centering-css-complete-guide/
Change your code:
a.image_container img {
width: 100%;
}
To this:
a.image_container img {
width: auto; // to maintain aspect ratio. You can use 100% if you don't care about that
height: 100%;
}
http://jsfiddle.net/f9krj/5/
Use max-width property of CSS, like this :
img{
max-width:100%;
}
you can use flex box for it.. this will solve your problem
.image-parent
{
height:33px;
display:flex;
}
If you take answer's Shekhar K. Sharma, and it almost work, you need also add to your this height: 1px; or this width: 1px; for must work.
For me the easiest way to do it without using position absolute, translate.
<div class="img-container">
<img src="yoururl" />
</div>
the CSS should look like this :
.img-container {
height:100px;
width:100px;
overflow:hidden;
}
.img-container > img {
width:100%;
height:100%;
object-fit:cover;
}
If all your trying to do is fill the div this might help someone else, if aspect ratio is not important, is responsive.
.img-fill > img {
min-height: 100%;
min-width: 100%;
}
I need to make the img tag width and height 100% inside overflow hidden div while maintaining the aspect ratio.
What I reached for is putting the image within overflow hidden div And the image is max-width 100% and auto height.
<div id="foo">
<img src="http://www.engineering.com/Portals/0/BlogFiles/swertel/heart-cloud.jpg" />
</div>
but the problem i'm facing is not go height 100%
Look the code in action http://fiddle.jshell.net/TARwL/
And get close look at the div#cover is 100% width and height is perfect look and i would like to see my code do the same
I can't use the background-size:cover method because beside is not working in older browsers, I can't click right and save the image and this is important to me
I rethought and I found eligible solution for me, I don't know if will suit anyone else !!
The Image will be background size cover and at the same time I will add the image inside the same div with 100% width and height and 0 opacity
So the image will show like cover and anyone can click on the same area and use the image like normal (copy link, download, etc.)
HTML
<div style="background-image:url(http://www.engineering.com/Portals/0/BlogFiles/swertel/heart-cloud.jpg)">
<img src="http://www.engineering.com/Portals/0/BlogFiles/swertel/heart-cloud.jpg" />
</div>
CSS
div{
width: 300px;
height: 300px;
display:inline-block;
vertical-align: top;
background-size:cover;
background-position:50% 50%;
}
div img{
width: 100%;
height: 100%;
opacity: 0;
/* OLD IE */
zoom: 1;
filter: alpha(opacity=0);
}
Code In Action http://jsfiddle.net/Jim_Toth/mVtJc/1/
I think you'll have to use a Script for this one. (unless you want to use a centered background image)
Working Fidlle
[try it with any image you want, with different aspects ratios]
JQuery
var img = $("#foo > img");
var ratio = img.width() / img.height();
var limit = (100*ratio)+"%";
var margin = ((1-ratio)*50)+"%";
if( ratio > 1)
{
img.css({"width": limit, "margin-left": margin});
}
else
{
ratio = 1 / ratio;
img.css({"height": limit, "margin-top": margin});
}
Edit:
this Fiddle support multiple images at once (use the foo class)
Try this: (Note this will only work if you use images with the same aspect ratios)
#foo img {
width:133.33%;
margin-left: -16.66%; /* crop img to the left: 33.33 /2 = 16.66 */
}
FIDDLE
Explanation:
Your image is 1024px wide X 768px high. So width to height ratio= 1.333.
However your overflow:hidden div has a raio 1X1 - so the image will be distorted at 100%.
So in order to display the image to ratio - you need to increase the width by 133%.
Then, in order to center or 'crop' the image to fit the div - use margin.
Another proposal: jsFiddle
I really did not understand why it shouldn't be possible to use a background-iamge!?
So you can use the example code as long as the width and height of the containing div remains the same and also the aspect ration of the image stays at 4:3.
If any of the values changes you have to adapt at least the value for left (the calculation can easily be done with Javascript).
Not using a background-image make the whole thing very "fragile" ..., and from a semantically point of view it is also "not ideal".
Would be better to use a server side technique to crop the image to the desired/ needed size.
I think it should be like:
.image-container {
width: 169px; // May be auto
height: 169px;
position: relative;
overflow: hidden;
.image-wrap {
position: absolute;
left: 50%;
transform: translateX(-50%) translateY(0);
transition: all .2s ease-in-out; //Run on IE
height: 100%; // Height full frame
img.scale {
height: 100%;
max-height: 100%;
max-width: none !important; // To make sure that width of the image can be larger than its container.
}
}
}
HTML:
<div class="image-container">
<div class="image-wrap"><img class="scale" src="your image path" /></div>
</div>
In modern browsers it is possible to use the property object-fit: cover
<style>
#foo {
width: 200px;
height: 200px;
overflow: hidden;
}
#foo img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
<div id="foo">
<img src="https://picsum.photos/300/200" />
</div>
Example: https://jsfiddle.net/davox/z5a728jm/7/
Source:
https://developer.mozilla.org/en-US/docs/Learn/CSS/Howto/Fill_a_box_with_an_image