I often use the ‘background-image” css property to achieve nicely behaving responsive images. I add the following CSS:
background-size: cover;
background-position: center center;
Which yields a centered image which takes the whole space of the containing div/element.
I use it for images which are a part of the content. The problem is it is probably incorrect semantically, as background-images should be set for decoration not content. I consider using either of the following methods to solve this issue:
Find a method to make the a background-image more semantically appropriate. Perhaps holding it in a figure html tag instead of a div. Perhaps using the title property as a replacement for the alt property of the image element.
Provide the advantages a background-image has to the ordinary img tag. Is there a way for an image element to cover the containing div and also to center in the middle of that containing div?
Say hello to the css property object-fit (css-tricks). The behavior is kinda the same as background-size, you got kinda the same options. Although the support for it is not great for IE and only partial in Edge (caniuse).
There are polyfills for it. They are different though
calulates the position with javascript (found here)
puts the image as a background-image (found here) (note there are several polyfills that does this)
I rolled my own for a project (it's more complete then the example below), but it's the same approach as in option two. I'm not sure about the support for media object on that one though as I haven't had the need for it.
if you prefer jsfiddle
if ("objectFit" in document.documentElement.style === false) {
$(".block__image").each(function() {
var $image = $(this);
if ($image === undefined) {
return;
}
$image
.parents(".block")
.css("background-image", "url(" + $image.attr("src") + ")")
.addClass("block--object-fit");
});
}
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
padding: 2rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.block {
height: 25rem;
width: 30%;
background-color: deepskyblue;
overflow: hidden;
position: relative;
-webkit-transition: height 200ms;
transition: height 200ms;
}
#media screen and (min-width: 1000px) {
.block {
height: 35rem;
}
}
.block.block--object-fit {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.block__image {
height: 100%;
width: 100%;
-o-object-fit: cover;
object-fit: cover;
}
.block--object-fit .block__image {
opacity: 0;
}
.block__image-alternative {
max-height: 100%;
max-width: auto;
position: absolute;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block">
<img src="https://source.unsplash.com/cXU6tNxhub0/1600x900" alt="" class="block__image">
</div>
Related
Here is the css for my wrapper container in which the div in question resides:
body {
margin:0;
overflow: hidden;
}
.wrapper{
height: 100vh;
background-size: cover;
background-position: center bottom;
background-color: gray;
display: flex;
justify-content: center;
align-items: center;
}
Now the following div I want to remain fixed to the bottom of the scroll-less SPA, but upon the change of a class (from infoTabHidden to infoTabDeployed), I want it to go from invisible to dynamically rise from the bottom of the window and cover most of the screen.
.infoTabHidden > * {
position: fixed;
overflow: hidden;
height: 0%;
}
.infoTabDeployed{
position: absolute;
width: 100%;
height: 90%;
bottom: 0%;
transition: all 200ms ease-in-out;
background-color: black;
display: flex;
justify-content: center;
}
Rather than rising right now, the div sort of just phases into existence...
Any tips? Thanks everyone for your valuable time!
I figure it out. The > * in infoTabHidden was still affecting the class after it had been changed.... however that works.
I know that it is impossible to actually modify an image with CSS, which is why I put crop in quotes.
What I'd like to do is take rectangular images and use CSS to make them appear square without distorting the image at all.
I'd basically like to turn this:
Into this:
A pure CSS solution with no wrapper div or other useless code:
img {
object-fit: cover;
width: 230px;
height: 230px;
}
Assuming they do not have to be in IMG tags...
HTML:
<div class="thumb1">
</div>
CSS:
.thumb1 {
background: url(blah.jpg) 50% 50% no-repeat; /* 50% 50% centers image in div */
width: 250px;
height: 250px;
}
.thumb1:hover { YOUR HOVER STYLES HERE }
EDIT: If the div needs to link somewhere just adjust HTML and Styles like so:
HTML:
<div class="thumb1">
Link
</div>
CSS:
.thumb1 {
background: url(blah.jpg) 50% 50% no-repeat; /* 50% 50% centers image in div */
width: 250px;
height: 250px;
}
.thumb1 a {
display: block;
width: 250px;
height: 250px;
}
.thumb1 a:hover { YOUR HOVER STYLES HERE }
Note this could also be modified to be responsive, for example % widths and heights etc.
If the image is in a container with a responsive width:
.rect-img-container {
position: relative;
}
.rect-img-container::after {
content: "";
display: block;
padding-bottom: 100%;
}
.rect-img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="rect-img-container">
<img class="rect-img" src="https://picsum.photos/id/0/367/267" alt="">
</div>
(edit: updated from sass to plain css)
(edit: Added dummy image for reference)
Place your image in a div.
Give your div explicit square dimensions.
Set the CSS overflow property on the div to hidden (overflow:hidden).
Put your imagine inside the div.
Profit.
For example:
<div style="width:200px;height:200px;overflow:hidden">
<img src="foo.png" />
</div>
Using background-size:cover - http://codepen.io/anon/pen/RNyKzB
CSS:
.image-container {
background-image: url('http://i.stack.imgur.com/GA6bB.png');
background-size:cover;
background-repeat:no-repeat;
width:250px;
height:250px;
}
Markup:
<div class="image-container"></div>
I actually came across this same problem recently and ended up with a slightly different approach (I wasn't able to use background images). It does require a tiny bit of jQuery though to determine the orientation of the images (I' sure you could use plain JS instead though).
I wrote a blog post about it if you are interested in more explaination but the code is pretty simple:
HTML:
<ul class="cropped-images">
<li><img src="http://fredparke.com/sites/default/files/cat-portrait.jpg" /></li>
<li><img src="http://fredparke.com/sites/default/files/cat-landscape.jpg" /></li>
</ul>
CSS:
li {
width: 150px; // Or whatever you want.
height: 150px; // Or whatever you want.
overflow: hidden;
margin: 10px;
display: inline-block;
vertical-align: top;
}
li img {
max-width: 100%;
height: auto;
width: auto;
}
li img.landscape {
max-width: none;
max-height: 100%;
}
jQuery:
$( document ).ready(function() {
$('.cropped-images img').each(function() {
if ($(this).width() > $(this).height()) {
$(this).addClass('landscape');
}
});
});
Check out CSS aspect-ratio
https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
.square-image{
width: 50%;
background-image: url('https://picsum.photos/id/0/367/267');
background-size: cover;
background-position: center;
aspect-ratio: 1/1;
}
<div class="square-image"></div>
You can also do this with a regular img tag as follows
.square-image{
width: 50%;
object-fit: cover; /* Required to prevent the image from stretching, use the object-position property to adjust the visible area */
aspect-ratio: 1/1;
}
<img src="https://picsum.photos/id/0/367/267" class="square-image"/>
Today you can use aspect-ratio:
img {
aspect-ratio: 1 / 1;
}
It has wide support amongst modern browsers as well:
https://caniuse.com/mdn-css_properties_aspect-ratio
object-fit: cover will do exactly what you need.
But it might not work on IE/Edge. Follow as shown below to fix it with just CSS to work on all browsers.
The approach I took was to position the image inside the container with absolute and then place it right at the centre using the combination:
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
Once it is in the centre, I give to the image,
// For vertical blocks (i.e., where height is greater than width)
height: 100%;
width: auto;
// For Horizontal blocks (i.e., where width is greater than height)
height: auto;
width: 100%;
This makes the image get the effect of Object-fit:cover.
Here is a demonstration of the above logic.
https://jsfiddle.net/furqan_694/s3xLe1gp/
This logic works in all browsers.
Original Image
Vertically Cropped
Horizontally Cropped
Square Container
I had a similar issue and could not "compromise" with background images.
I came up with this.
<div class="container">
<img src="http://lorempixel.com/800x600/nature">
</div>
.container {
position: relative;
width: 25%; /* whatever width you want. I was implementing this in a 4 tile grid pattern. I used javascript to set height equal to width */
border: 2px solid #fff; /* just to separate the images */
overflow: hidden; /* "crop" the image */
background: #000; /* incase the image is wider than tall/taller than wide */
}
.container img {
position: absolute;
display: block;
height: 100%; /* all images at least fill the height */
top: 50%; /* top, left, transform trick to vertically and horizontally center image */
left: 50%;
transform: translate3d(-50%,-50%,0);
}
//assuming you're using jQuery
var h = $('.container').outerWidth();
$('.container').css({height: h + 'px'});
Hope this helps!
Example:
https://jsfiddle.net/cfbuwxmr/1/
Use CSS: overflow:
.thumb {
width:230px;
height:230px;
overflow:hidden
}
Either use a div with square dimensions with the image inside with the .testimg class:
.test {
width: 307px;
height: 307px;
overflow:hidden
}
.testimg {
margin-left: -76px
}
or a square div with a background of the image.
.test2 {
width: 307px;
height: 307px;
background: url(http://i.stack.imgur.com/GA6bB.png) 50% 50%
}
Here's some examples: http://jsfiddle.net/QqCLC/1/
UPDATED SO THE IMAGE CENTRES
.test {
width: 307px;
height: 307px;
overflow: hidden
}
.testimg {
margin-left: -76px
}
.test2 {
width: 307px;
height: 307px;
background: url(http://i.stack.imgur.com/GA6bB.png) 50% 50%
}
<div class="test"><img src="http://i.stack.imgur.com/GA6bB.png" width="460" height="307" class="testimg" /></div>
<div class="test2"></div>
I came with a different approach. You basically have to crop the rectangular image to fit it inside the square is all there is to it. Best approach is if the image width is greater than the height, then you crop the image alittle from left and right side of the image. If the image height is greater than the image width then you crop the bottom of the image. Here is my solution. I needed a little help from PHP though.
<div style="position: relative; width: 154px; height: 154px; overflow: hidden;">
<?php
//get image dimmensions whichever way you like. I used imgaick
$image = new Imagick("myimage.png");
$width = $image->getImageWidth();
$height = $image->getImageHeight();
if($width > $height){
?>
<img src="myimage.png" style="display: block; position: absolute; top: 0px; left: 50%; transform: translateX(-50%); -ms-transform: translateX(-50%); -webkit-transform: translateX(-50%); height: 100%; " />
<?php
}else{
?>
<img src="myimage.png" style="display: block; position: absolute; top: 0px; left: 0px; width: 100%; " />
<?php
}
?>
</div>
I'm using object-fit: cover; in my CSS for images on a specific page, because they need to stick on the same height. It works great in most browsers.
But when scaling my browser in IE or Edge, the image is resizing in width (not height) instead of zooming. The image gets out of shape.
What CSS rule can I use to fix this?
Here is the page
I had similar issue. I resolved it with just CSS.
Basically Object-fit: cover was not working in IE and it was taking 100% width and 100% height and aspect ratio was distorted. In other words image zooming effect wasn't there which I was seeing in chrome.
The approach I took was to position the image inside the container with absolute and then place it right at the centre using the combination:
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
Once it is in the centre, I give to the image,
// For vertical blocks (i.e., where height is greater than width)
height: 100%;
width: auto;
// For Horizontal blocks (i.e., where width is greater than height)
height: auto;
width: 100%;
This makes the image get the effect of Object-fit:cover.
Here is a demonstration of the above logic.
https://jsfiddle.net/furqan_694/s3xLe1gp/
This logic works in all browsers.
There is no rule to achieve that using CSS only, besides the object-fit (that you are currently using), which has partial support in EDGE1 so if you want to use this in IE, you have to use a object-fit polyfill in case you want to use just the element img, otherwise you have to do some workarounds.
You can see the the object-fit support here
UPDATE(2019)
You can use a simple JS snippet to detect if the object-fit is supported and then replace the img for a svg
//ES6 version
if ('objectFit' in document.documentElement.style === false) {
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('img[data-object-fit]').forEach(image => {
(image.runtimeStyle || image.style).background = `url("${image.src}") no-repeat 50%/${image.currentStyle ? image.currentStyle['object-fit'] : image.getAttribute('data-object-fit')}`
image.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${image.width}' height='${image.height}'%3E%3C/svg%3E`
})
})
}
//ES5 version transpiled from code above with BabelJS
if ('objectFit' in document.documentElement.style === false) {
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('img[data-object-fit]').forEach(function(image) {
(image.runtimeStyle || image.style).background = "url(\"".concat(image.src, "\") no-repeat 50%/").concat(image.currentStyle ? image.currentStyle['object-fit'] : image.getAttribute('data-object-fit'));
image.src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='".concat(image.width, "' height='").concat(image.height, "'%3E%3C/svg%3E");
});
});
}
img {
display: inline-flex;
width: 175px;
height: 175px;
margin-right: 10px;
border: 1px solid red
}
[data-object-fit='cover'] {
object-fit: cover
}
[data-object-fit='contain'] {
object-fit: contain
}
<img data-object-fit='cover' src='//picsum.photos/1200/600' />
<img data-object-fit='contain' src='//picsum.photos/1200/600' />
<img src='//picsum.photos/1200/600' />
UPDATE(2018)
1 - EDGE has now partial support for object-fit since version 16, and by partial, it means only works in img element (future version 18 still has only partial support)
I just used the #misir-jafarov and is working now with :
IE 8,9,10,11 and EDGE detection
used in Bootrap 4
take the height of its parent div
cliped vertically at 20% of top and horizontally 50% (better for portraits)
here is my code :
if (document.documentMode || /Edge/.test(navigator.userAgent)) {
jQuery('.art-img img').each(function(){
var t = jQuery(this),
s = 'url(' + t.attr('src') + ')',
p = t.parent(),
d = jQuery('<div></div>');
p.append(d);
d.css({
'height' : t.parent().css('height'),
'background-size' : 'cover',
'background-repeat' : 'no-repeat',
'background-position' : '50% 20%',
'background-image' : s
});
t.hide();
});
}
Hope it helps.
You can use this js code. Just change .post-thumb img with your img.
$('.post-thumb img').each(function(){ // Note: {.post-thumb img} is css selector of the image tag
var t = $(this),
s = 'url(' + t.attr('src') + ')',
p = t.parent(),
d = $('<div></div>');
t.hide();
p.append(d);
d.css({
'height' : 260, // Note: You can change it for your needs
'background-size' : 'cover',
'background-repeat' : 'no-repeat',
'background-position' : 'center',
'background-image' : s
});
});
Here's a CSS solution to fix this.
Use the below css.
.row-fluid {
display: table;
}
.row-fluid .span6 {
display: table-cell;
vertical-align: top;
}
.vc_single_image-wrapper {
position: relative;
}
.vc_single_image-wrapper .image-wrapper {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
}
HTML from the OP:
<div class="vc_single_image-wrapper vc_box_border_grey">
<div class="image-wrapper" style="background-image: url(http://i0.wp.com/www.homedecor.nl/wp-content/uploads/2016/03/Gordijnen-Home-Decor-2.jpg?fit=952%2C480;"></div>
</div>
try this, it should work. also remove float from .row-fluid .span6
I achieved satisfying results with:
min-height: 100%;
min-width: 100%;
this way you always maintain the aspect ratio.
The complete css for an image that will replace "object-fit: cover;":
width: auto;
height: auto;
min-width: 100%;
min-height: 100%;
position: absolute;
right: 50%;
transform: translate(50%, 0);
parent div:
height: 584px;
display: block;
background-position: center center;
background-size: cover;
width: 100%;
position: absolute;
overflow: hidden;
background-color: #fff;
child img
object-position: center center;
min-height: 100%;
display: block;
position: absolute;
top: -9999px;
bottom: -9999px;
left: -9999px;
right: -9999px;
margin: auto;
width: auto;
min-width: 100%;
max-width: none;
-o-object-fit: cover; // you can keep them for modern browsers
object-fit: cover; // you can keep them for modern browsers
height: 100%;
fiddle: http://jsfiddle.net/j6hLaxz8/
img.imgdemo {
background: white;
width: 65%;
margin: auto;
}
<a class=imagelink href=periodictable.htm>
<img class=imgdemo src=ptabledemo.png>
</a>
I'm trying to center an image that also acts as a link, but when it has a style of display: block, it acts as a block element, making everything in it's width a link as well. Is there any way to fix this?
Images are inline just like text so:
.imagelink {
text-align:center;
}
One option you could use is the transform: translate() property and give the a.imagelink display: inline-block. This will let you set the size of the image to whatever you want and make sure the link is the same size and stays centered at all times:
JS Fiddle
a.imagelink {
display: inline-block;
background: blue;
position: relative;
left: 50%;
transform: translateX(-50%);
}
img {
width: 50%;
display: block;
}
If your image is 200px
img {
width: 200px;
margin-left: calc(50% - 200px / 2);
}
If your image is 65%
img {
width: 65%;
margin-left: calc(50% - 65% / 2);
}
Here is my code:
#my_div:before
{
/* displaying the image */
content: url("img path");
/* centering the image */
display: block;
text-align: center;
/* making the image responsive */
max-width: 100%;
}
<div id="my_div"></div>
I'm trying to make the image responsive through the max-width:100% property but it is not working
My Question: Is it possible to do such a thing?
Edit
The question is not a duplicate, I want the dimensions to scale automatically on screen resize while the other question sets a fixed size to the image
Try this:
#my_div:before
{
/* displaying the image */
content: url("img path");
/* centering the image */
display: block;
text-align: center;
/* making the image responsive */
max-width: 100%;
height: auto;
}
If this doesn't work, try removing the :before pseudo-element
#my_div
{
/* displaying the image */
content: url("img path");
/* centering the image */
display: block;
text-align: center;
/* making the image responsive */
max-width: 100%;
height: auto;
}
Without seeing the context of your html, this is the best solution I can offer. We'll need more information in order to understand your situation better.
I confess I'm not entirely sure what effect you are after but I think this might be a better option for you.
Don't put the image in the content property...make that pseudo-element 100% size of the div and use a background image.
A couple of options for you.
.my_div {
position: relative;
height: 150px;
border: 1px solid grey;
width: 75%;
margin: 1em auto;
}
.my_div:before {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
content: '';
background-image: url(http://lorempixel.com/g/400/200/);
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
.cover:before {
background-size: contain;
}
<div class="my_div"></div>
<div class="my_div cover"></div>
JSfiddle Demo