I have several columns that I am giving equal width using flex. Each contains img tags, and I'd like those images to exhibit the object-fit: cover sizing.
.container {
display: flex;
flex-direction: row;
width: 100%;
}
.test {
flex: 1;
margin-right: 1rem;
overflow: hidden;
height: 400px;
}
img {
object-fit: cover;
}
<div class="container">
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
</div>
The images are not resizing, as can be seen in this demo. Why is that?
From the specification:
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.
The key term being: fitted to the box established by its used height and width
The image gets replaced, not its container. And the box established by its used height and width relates to the image itself, not its container.
So, scrap the container and make the images themselves the flex items.
.container {
display: flex;
flex-direction: row;
width: 100%;
}
img {
object-fit: cover;
flex: 1;
margin-right: 1rem;
overflow: hidden;
height: 400px;
}
<div class="container">
<img src="http://placehold.it/1920x1080">
<img src="http://placehold.it/1920x1080">
<img src="http://placehold.it/1920x1080">
<img src="http://placehold.it/1920x1080">
</div>
Revised Codepen
Additional Details
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 three 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.
fill
The replaced content is sized to fill the element's content box.
With cover the image retains its aspect ratio and covers all available space. With this option, 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 may result in whitespace on the left and/or right (portrait fit), or top and/or bottom (landscape fit). The object-position property can be used to shift the image within its box.
With fill the aspect ratio is abandoned and the image is sized to fit the box.
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.
The problem is that object-fit specifies how an image is painted inside the img, but you didn't specify the sizes of these elements, only the sizes of their .test parents.
So an alternative to Michael_B's answer is making the images have the same size as the flex items:
img {
height: 100%;
width: 100%;
object-fit: cover;
}
.container {
display: flex;
flex-direction: row;
width: 100%;
}
.test {
flex: 1;
margin-right: 1rem;
overflow: hidden;
height: 400px;
}
img {
height: 100%;
width: 100%;
object-fit: cover;
}
<div class="container">
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
<div class="test"><img src="http://placehold.it/1920x1080"></div>
</div>
For anyone who can't just "scrap the container and make the images themselves the flex items," just add container levels:
<div class="display-flex">
<div class="flex-grow position-relative">
<div class="pos-absolute top-left-right-bottom-0">
<img class="object-fit-cover height-width-100">
As a way to support the object-fit functionality for your images in non-compatible browsers, you can create a CSS class with background-image and background-size. For it to properly calculate the occupied space, you wrap an img element and make it invisible. Example below.
HTML
<div class="my-image">
<img src="path/to/my/image"/>
</div>
CSS
.my-image {
background-image: url('path/to/my/image');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.my-image > img {
visibility: hidden;
}
If the <img/> is stretched to 100% in IE11 then add flex-shrink: 0 on the <img/> itself, as adviced here: Flexbox on IE11: image stretched for no reason?
Related
I need to fit an image into a fixed width/height div (say 80%/80%), but I also need the image to be wrapped in another div so that I can place an absolutely positioned element on top of the image (using that wrapper div as the anchor). I have accomplished the first point by just setting the max-height and max-width of the image to 100% so that it will always take up 100% of one dimension and won't exceed the other while maintaining aspect ratio, but I am unable to figure out a way to wrap the image in a div such that there is no extra space in the wrapper. I was under the impression that using display: inline or display: inline-block on the .wrapper div should shrink to the size of it's content (the image in my case), but that does not appear to be the case. When I replace the image with a test div with a defined width and height, the wrapper works as expected, i.e. there is no excess yellow background from the wrapper, it is exactly the same size as the div. How can I achieve the same behavior with the image? I've tried using all sorts of combinations of different display modes (flexbox/inline/block) and various min/max heights/widths but none have worked.
I've put an example of what my HTML looks like now, and what I would like it to look like if I could get this to work below. The .window element is a stand in for whatever the parent of the container is. The .container element is where I'd like to fit the image. In the example with the image, the inline wrapper is still larger than the image (which can be seen by the yellow overflowing on the sides). In the example after that with just a fixed size div (colored green), the wrapped properly shrinks to exactly the size of the div. Can this be accomplished with just css without knowing anything about the size of the image itself?
.window {
height: 400px;
width: 600px;
display: flex;
justify-content: center;
align-items: center;
background: red;
}
.container {
height: 80%;
width: 80%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: blue;
}
.wrapper {
display: inline;
max-height: 100%;
max-width: 100%;
background: yellow;
}
img {
max-height: 100%;
max-width: 100%;
}
.test {
width: 64px;
height: 128px;
background: green;
}
<div class='window'>
<div class='container'>
<div class='wrapper'>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/ReceiptSwiss.jpg/1920px-ReceiptSwiss.jpg" />
</div>
</div>
</div>
<div class='window'>
<div class='container'>
<div class='wrapper'>
<div class='test' />
</div>
</div>
NOTE: You can skip the full explanation and scroll down to TLTR section.
I want to implement a slider like in this page positioned inside a vertical flexbox. I have the following code and it represents the inner flexbox div which is positioned horizontally i.e. the slider's layout.
.img {
max-height: 100%;
}
.items {
display: flex;
flex-direction: row;
height: 100%;
}
.item {
height: 100%;
border: 1px solid black;
}
.container {
overflow: hidden;
flex: 1 1 auto;
height: 80%;
width: 100%;
}
<div class='container'>
<div class='items' style='height: 100%'>
<div class='item'>
<img class='img' src="/img1.jpg" alt="this expected to be image 1"/></div>
<div class='item'><img class='img' src="/img2.jpg" alt="this expected to be image 2"/></div>
<div class='item'><img class='img' src="/img3.jpg" alt="this expected to be image 3"/></div>
</div>
</div>
The outer flexbox div looks like this:
.main {
display: flex;
flex-direction: column;
height: 100%;
}
.title {
flex: 0 0 60px;
border: 1px solid black;
}
.slider {
flex: 1 0 auto;
border: 1px solid black;
}
<div class="main">
<div class="title">Title</div>
<div class="slider">Slider</div>
</div>
The code for the inner flexbox div is rendering well on any browser. The same is the case with the code for the outer flexbox div. The problem comes when I put the inner flexbox div inside div.slider. The browser cannot render the HTML as expected. If I set height and min-height of div.title and height of div.slider then everything works on Firefox and Chrome. Cannot test it on Safari but I have the feeling that it won't work and I'm missing something. I tested on Epiphany browser which is developed on WebKit (same as Safari) and it fails to render. I've come across similar issues in the past, working with flexbox and overflowing divs and I know that there might be a browser's issue. If I remove height and min-height of div.title and div.slider and change some CSS params I could make the page render on Chrome but still fails to render on Firefox. Am I missing something or doing something wrong? I need a cross-browser solution.
================== TLTR ==================
Here it is a full example - https://jsfiddle.net/SitkaCharley/xht9vaef/10/
I expect the images in div.slide to resize and fit inside it even though they are different sizes. Instead I see images with different sizes and a verticall scroll bar when images are too big. My understanding is that since the .main div is instructed to take 100% of windows height the .title will take 60px and .slider will take the rest of parent's height (see .slider's flex item css instructions). Then the .container is expected to take 80% out of parent's height and .img's max-height: 100% will force to resize images to the height of their parents which is the height of .container.
I'm developping an ionic application, and i want to display some images in some cards, the problem is that my images have not the some size, and i want them to look the some.
The idea is to use à css class that will solve the problem ( at least in the width )
.full-width-image {
width: 100%
}
this class will solve the problem of size and all the images will have the some width. how ever i dont know how to make a fixed height for them all. if i add to my css class a fixed height like:
.full-width-image {
width: 100%;
height: 60px;
}
some pictures will look ugly:
how it looks like
what i want is to hide the extra part of the image.
If you have a set width and height you can use object-fit: cover; for the image to fill the entire space without losing its aspect ratio.
I would recommend you to use a flex wrapper around an image.
.wrapper {
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 2px gray;
width: 100px;
height: 100px;
overflow: hidden;
margin: 1em;
}
.wrapper img {
border: 1px solid black;
max-width: 100%;
max-height: 100%;
}
.example {
display: flex;
}
<div class="example">
<div class="wrapper">
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a">
</div>
<div class="wrapper">
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a">
</div>
<div class="wrapper">
<img src="https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-_geograph.org.uk_-_590710.jpg">
</div>
<div>
Using this technique you get a kind of smart image - it scales itself to fit your wrapper, its fixed size, but without distortion. Look, there are black borders around the images, so you can see that both an image with width > height and an image with a tree, where height > width, fit well the wrapper, restricting the width and the height correspondingly.
Also you can you inline-flex instead of flex in the wrapper class.
I want an image to fill the 100% of its container's width, and I want it to have a max-heigth property set to it, all this keeping the aspect ratio but allowing to lose any part of the image.
img {
max-height:200px;
width:100%;
}
I know a similar thing can be done with background-size property but i want to make this to an inline <img> tag.
Any idea of how could i achieve this using CSS? or javascript?
You can try CSS3 object-fit, and see browser support tables.
CSS3 object-fit/object-position Method of specifying how an object (image or video) should fit inside
its box. object-fit options include "contain" (fit according to aspect
ratio), "fill" (stretches object to fill) and "cover" (overflows box
but maintains ratio), where object-position allows the object to be
repositioned like background-image does.
JSFIDDLE DEMO
.container {
width: 200px; /*any size*/
height: 200px; /*any size*/
}
.object-fit-cover {
width: 100%;
height: 100%;
object-fit: cover; /*magic*/
}
<div class="container">
<img class="object-fit-cover" src="https://i.stack.imgur.com/UJ3pb.jpg">
</div>
Related Info:
Exploring object-fit ★ Mozilla Hacks
Polyfill for CSS object-fit property
You can achieve this using css flex properties. Please see the code below
.img-container {
width: 150px;
height: 150px;
border: 2px solid red;
justify-content: center;
display: flex;
flex-direction: row;
overflow: hidden;
}
.img-container .img-to-fit {
flex: 1;
height: 100%;
}
<div class="img-container">
<img class="img-to-fit" src="https://images.pexels.com/photos/8633/nature-tree-green-pine.jpg" />
</div>
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/