I'm using transform to rotate an image according to its EXIF data. Then, I'd like to display it "full screen" by fitting it to its parent div.
The problem is, max-width / max-height and all other sizing directives "ignore" the rotation (which is normal, according to transform specs, the element's transformation is "ignored" in the flow.
Jsfiddle: http://jsfiddle.net/puddjm4y/2/
div.top {
position: fixed;
width: 100%;
height: 100%;
border: 1px solid blue;
}
img {
transform: rotate(90deg);
max-width: 100%;
max-height: 100%;
}
<div class="top">
<img src="http://www.androidpolice.com/wp-content/uploads/2014/02/nexusae0_wm_DSC02232.jpg">
</div>
Is there a way to achieve this?
For full screen display, the simplest solution is to use viewport units to specify width and height of images:
Normal image should be 100vw wide and 100vh tall
Rotated image should be 100vh wide and 100vw tall
The image could be moved to the middle using CSS transformations. Here is an example, it uses two images that are larger and smaller than the viewport:
body {
margin: 0;
}
img {
display: block;
}
img.normal {
max-width: 100vw;
max-height: 100vh;
transform: translatex(calc(50vw - 50%)) translatey(calc(50vh - 50%));
}
img.rotated {
max-width: 100vh;
max-height: 100vw;
transform: translatex(calc(50vw - 50%)) translatey(calc(50vh - 50%)) rotate(90deg);
}
/* demo */
.demo {
height: 100vh;
position: relative;
}
.demo:nth-child(odd) {
background-color: #CCC;
}
.demo:nth-child(even) {
background-color: #EEE;
}
.demo::after {
content: attr(title);
position: absolute;
left: 0;
top: 0;
padding: .25em .5em;
background-color: rgba(255, 255, 255, .8);
}
<div class="demo" title="Large image, normal"><img class="normal" src="https://i.stack.imgur.com/2DdPE.jpg"></div>
<div class="demo" title="Large image, rotated"><img class="rotated" src="https://i.stack.imgur.com/2DdPE.jpg"></div>
<div class="demo" title="Small image, normal"><img class="normal" src="https://i.stack.imgur.com/ustNQ.jpg"></div>
<div class="demo" title="Small image, rotated"><img class="rotated" src="https://i.stack.imgur.com/ustNQ.jpg"></div>
Make the height of an element equal it's width and vice versa, is a Javascript thing, since it can retrieve those values and set them back.
In CSS there's no way of accomplishing that, and also not possible with dynamic dimensions, we don't know what 100% would equal to exactly, and even if we did we wouldn't be able to use them, because there's no reference to them.
However if you would go with fixed values, that can be manipulated with media queries, then why not use variables, this way we have the value, and a reference to it.
:root {
--width: 100px;
--height: 140px;
}
div.top {
position: fixed;
width: var(--width);
height: var(--height);
border: 1px solid blue;
}
img {
width: var(--width);
height: var(--height);
animation: rotate 3s alternate infinite;
}
/* translate values are the difference between the height */
/* and width divided between the X and Y */
/* 100 - 140 = 40 / 2 = 20px each */
#keyframes rotate {
to {
transform: rotate(90deg) translate(20px, 20px);
width: var(--height);
height: var(--width);
}
}
<div class="top">
<img src="http://www.androidpolice.com/wp-content/uploads/2014/02/nexusae0_wm_DSC02232.jpg">
</div>
Then again, this is just an idea.
I would probably go for something like this (swapped max-width/height using viewport sizing)
* {
box-sizing:border-box;
}
html, body {
margin:0;
}
div.top {
position: fixed;
width: 100%;
height: 100%;
top:0;
left:0;
border: 1px solid blue;
display:flex;
}
img {
transform: rotate(90deg);
max-width: 100vh;
max-height: 100vw;
margin:auto;
}
<div class="top">
<img src="http://www.androidpolice.com/wp-content/uploads/2014/02/nexusae0_wm_DSC02232.jpg">
</div>
You could do this in JavaScript by checking the container height and setting the maxWidth of the image to the height of the container.
/**
* Set max width of a rotated image to container height
* #param {*} container
* #param {*} image
*/
function setRotatedImageWidth(container = null, image = null) {
if (!container || !image) {
return false; // exit if empty
}
var h = container.offsetHeight; // Container height
var w = image.offsetWidth; // Image width
// If image width is greater container height
if (w > h) {
image.style.maxWidth = h + 'px';
}
}
var container = document.querySelector('.container');
var image = container.querySelector('img');
setRotatedImageWidth(container, image);
I finally found the answer to what I needed for this problem, maybe it will help someone else.
I have a flex parent and the child I needed to be rotated based on EXIF.
I needed image-orientation: from-image;
imgBox {
flex: 1;
padding: 1rem;
overflow: hidden;
}
.img1 {
object-fit: cover;
max-width: 100%;
image-orientation: from-image;
}
Here's a scant attempt that requires manually syncing the width / height. For those who are willing to use JS, that should be fairly easy to sync.
Here it is:
div.top {
border: 1px solid blue;
box-sizing: border-box;
width: 100%;
height: 300px;/* SYNC */
position: relative;
overflow: hidden;
}
div.top:before {
content: "";
position: absolute;
width: 300px;/* SYNC */
height: 100%;
transform: rotate(90deg);
background-image: url(http://www.androidpolice.com/wp-content/uploads/2014/02/nexusae0_wm_DSC02232.jpg);
background-size: contain;
background-repeat: no-repeat;
}
<div class="top"></div>
Positioning becomes awkward. However, my hope is that someone will branch from here and conjure a better solution.
If you could ignore the transform part as it is a question of aspect ratio and there is no answer for it, but displaying an image to 100% of the parent element is possible and will not be needing any media queries to it. 100 percent is relative to the parent and with images it is the aspect ratio that rules the dimensions. we can stretch it but that will not serve the purpose. Hope below css might help you in some way.
div.top {
position: fixed;
width: 100%;
height: 100%;
border: 1px solid blue;
background-image:url("http://www.androidpolice.com/wp-content/uploads/2014/02/nexusae0_wm_DSC02232.jpg");
background-size:cover;
background-repeat:no-repeat;
background-position:50%;
}
div.top img {
/* transform: rotate(90deg); */
min-width: 100%;
min-height: 100%;
visibility:hidden;
}
I am using image natural width and height to calculate transform scale as I have documented at:
https://stackoverflow.com/a/61620946/7037600
For the exif part you can't do it with css as css ins't able to ready exif datas.
For the CSS part though, you need to use transform-origin, not just transform and also use width 100% and heigh auto to keep ratio.
Here is an exemple :
http://jsfiddle.net/yxqgt2d1/1/
Related
I've looked into this a fair bit but can't seem to find a good, solid answer to find how to make a responsive circle around a div element of variable height.
It's easy to make a simple responsive circle using vw units.
<div style="height:20vw; width:20vw"></div>
However, I'm looking to use a min-height of an element and have a circle around this div.
Another way to create a responsive circle is using something like the snippet below, but again I can't adapt this to work for a variable height (again, I can't use vh units as the div will change in height.
.square {
position: relative;
width: 10%;
background: gray;
border-radius: 50%;
}
.square:after {
content: "";
display: block;
padding-bottom: 100%;
}
.content {
position: absolute;
width: 100%;
height: 100%;
}
<div class="square">
<div class="content">
</div>
</div>
I am trying to create something like the below, where the circle will never cut into the corners of the div (with around a 10px padding). I personally was trying to avoid javascript and would have preferred a css only approach, but it seems it's unavoidable. Maybe the only solution is to use a jquery to calculate the height of the element in order to apply this to a wrapper element?
I was playing around with this:
.square {
position: absolute;
top: 50%;
display: inline-block;
left: 50%;
transform: translate(-50%, -50%);
min-height: 100px;
border-radius: 50%;
background: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium');
background-size: 100% 100%;
padding: 20px;
}
.content {
width: 300px;
min-height: 100px;
background: tomato;
}
<div class="square">
<div class="content">
Hello!<br>
<br><br><br>This has a variable height but fixed width<br><br><br>Hello
</div>
</div>
Clip-path can easily do this if you consider solid coloration.
Resize the element and the circle will follow:
.box {
width: 200px;
height: 200px;
overflow: hidden;
resize: both;
background: blue;
box-shadow: 0 0 0 200vmax red;
clip-path: circle(71%);
margin: 100px auto;
}
<div class="box"></div>
Related question to understand the magic number 71%: clip-path:circle() radius doesn't seem to be calculated correctly
To use an image we can consider pseudo elements. You can also rely on calc() to add the offset:
.box {
width: 200px;=
resize: both;
clip-path: circle(calc(71% + 10px));
margin: 100px auto;
position: relative;
font-size:35px;
color:#fff;
}
/* the background layer */
.box::before {
content:"";
position: absolute;
z-index:-1;
top:0;
left:0;
right:0;
bottom:0;
background:blue;
}
/* the image layer */
.box::after {
content:"";
position: fixed; /* to make sure the image cover all the screen */
z-index:-2;
top:0;
bottom:0;
left:0;
right:0;
background:url(https://picsum.photos/id/1015/1000/1000) center/cover no-repeat;
}
<div class="box" contenteditable="true"> Edit this<br>text </div>
I tried my hardest to figure this out with pure css. Though the problem with css I could not figure out how to calculate the diameter of the circle based on the content div size; the length from top left corner to bottom right corner of the variable height div.
I'm not sure if can be done using the calc() css function.
But I did manage to do it with a little jquery (which could easily be changed to pure javascript if you are not using jquery).
See working resizable example below (follow my comments in code)
Note: If you are using internet explorer the resizable demo content div will not resize.
// circumscriber for variable size divs
function circumscriber() {
// for each variable size div on page
$(".variable-size").each(function() {
// get the variable size div content width and height
let width = $(this).outerWidth();
let height = $(this).outerHeight();
// get the diameter for our pefect circle based on content size
let diameter = Math.sqrt(width ** 2 + height ** 2);
// extra 15 pixel circle edge around variable size div
let edge = 15;
// add current circle size width css
$('.circle', this).css({
'width': (diameter + (edge * 2)) + 'px'
})
});
}
// run the circumscriber (you might wana do this on ready)
circumscriber();
// if the window is resized responsively
$(window).on('resize', function() {
circumscriber();
});
// for demo purpose to fire circumscriber when resizing content
// not needed for real thing
$('.content').on('input', function() {
this.style.height = "";
this.style.height = ( this.scrollHeight - 30 ) + "px";
circumscriber();
}).on('mouseup', function() {
circumscriber();
});
/* variable size container to be circumscribed by circle */
/* none of these styles are required, this just to center the variable size div in the window for demo purposes */
.variable-size {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* resizable text area for demo */
/* again not needed */
.variable-size .content {
padding: 15px;
background: #fff;
resize: both;
overflow: auto;
color: #000;
border: none;
width: 200px;
font-weight: bold;
}
.variable-size .content:focus {
outline: 0;
}
/* child circle div css */
.variable-size .circle {
position: absolute;
background-image: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium');
background-position: center center;
z-index: -1;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: all 0.5s ease;
width: 0;
}
/* fast way to make circle height the same as current width */
.variable-size .circle:before {
display: block;
content: '';
width: 100%;
padding-top: 100%;
}
/* demo window css */
HTML,
BODY {
height: 100%;
min-height: 100%;
background: black;
position: relative;
font-family: "Lucida Console", Courier, monospace;
}
<div class="variable-size">
<textarea class="content" rows="1" placeholder="TYPE TEXT OR RESIZE ME ↘"></textarea>
<div class="circle"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
See jsfiddle here... https://jsfiddle.net/joshmoto/6d0zs7uq/
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.stroke();
Source: https://www.w3schools.com/
You could use flex display and insert empty flex-items around the inner div and use flex-basis to fix their width.
Try this
.square {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-height: 100px;
border-radius: 50%;
background: black;
background-size: 100% 100%;
padding: 20px;
}
.content {
width: 300px;
min-height: 100px;
background: tomato;
}
.emptyDiv {
flex-basis: 120px
}
<div class="square">
<div class="emptyDiv"></div>
<div class="content">
Hello!<br>
<br><br><br>This has a variable height but fixed width<br><br><br>Hello
</div>
<div class="emptyDiv"></div>
</div>
I've looked into this a fair bit but can't seem to find a good, solid answer to find how to make a responsive circle around a div element of variable height.
It's easy to make a simple responsive circle using vw units.
<div style="height:20vw; width:20vw"></div>
However, I'm looking to use a min-height of an element and have a circle around this div.
Another way to create a responsive circle is using something like the snippet below, but again I can't adapt this to work for a variable height (again, I can't use vh units as the div will change in height.
.square {
position: relative;
width: 10%;
background: gray;
border-radius: 50%;
}
.square:after {
content: "";
display: block;
padding-bottom: 100%;
}
.content {
position: absolute;
width: 100%;
height: 100%;
}
<div class="square">
<div class="content">
</div>
</div>
I am trying to create something like the below, where the circle will never cut into the corners of the div (with around a 10px padding). I personally was trying to avoid javascript and would have preferred a css only approach, but it seems it's unavoidable. Maybe the only solution is to use a jquery to calculate the height of the element in order to apply this to a wrapper element?
I was playing around with this:
.square {
position: absolute;
top: 50%;
display: inline-block;
left: 50%;
transform: translate(-50%, -50%);
min-height: 100px;
border-radius: 50%;
background: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium');
background-size: 100% 100%;
padding: 20px;
}
.content {
width: 300px;
min-height: 100px;
background: tomato;
}
<div class="square">
<div class="content">
Hello!<br>
<br><br><br>This has a variable height but fixed width<br><br><br>Hello
</div>
</div>
Clip-path can easily do this if you consider solid coloration.
Resize the element and the circle will follow:
.box {
width: 200px;
height: 200px;
overflow: hidden;
resize: both;
background: blue;
box-shadow: 0 0 0 200vmax red;
clip-path: circle(71%);
margin: 100px auto;
}
<div class="box"></div>
Related question to understand the magic number 71%: clip-path:circle() radius doesn't seem to be calculated correctly
To use an image we can consider pseudo elements. You can also rely on calc() to add the offset:
.box {
width: 200px;=
resize: both;
clip-path: circle(calc(71% + 10px));
margin: 100px auto;
position: relative;
font-size:35px;
color:#fff;
}
/* the background layer */
.box::before {
content:"";
position: absolute;
z-index:-1;
top:0;
left:0;
right:0;
bottom:0;
background:blue;
}
/* the image layer */
.box::after {
content:"";
position: fixed; /* to make sure the image cover all the screen */
z-index:-2;
top:0;
bottom:0;
left:0;
right:0;
background:url(https://picsum.photos/id/1015/1000/1000) center/cover no-repeat;
}
<div class="box" contenteditable="true"> Edit this<br>text </div>
I tried my hardest to figure this out with pure css. Though the problem with css I could not figure out how to calculate the diameter of the circle based on the content div size; the length from top left corner to bottom right corner of the variable height div.
I'm not sure if can be done using the calc() css function.
But I did manage to do it with a little jquery (which could easily be changed to pure javascript if you are not using jquery).
See working resizable example below (follow my comments in code)
Note: If you are using internet explorer the resizable demo content div will not resize.
// circumscriber for variable size divs
function circumscriber() {
// for each variable size div on page
$(".variable-size").each(function() {
// get the variable size div content width and height
let width = $(this).outerWidth();
let height = $(this).outerHeight();
// get the diameter for our pefect circle based on content size
let diameter = Math.sqrt(width ** 2 + height ** 2);
// extra 15 pixel circle edge around variable size div
let edge = 15;
// add current circle size width css
$('.circle', this).css({
'width': (diameter + (edge * 2)) + 'px'
})
});
}
// run the circumscriber (you might wana do this on ready)
circumscriber();
// if the window is resized responsively
$(window).on('resize', function() {
circumscriber();
});
// for demo purpose to fire circumscriber when resizing content
// not needed for real thing
$('.content').on('input', function() {
this.style.height = "";
this.style.height = ( this.scrollHeight - 30 ) + "px";
circumscriber();
}).on('mouseup', function() {
circumscriber();
});
/* variable size container to be circumscribed by circle */
/* none of these styles are required, this just to center the variable size div in the window for demo purposes */
.variable-size {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* resizable text area for demo */
/* again not needed */
.variable-size .content {
padding: 15px;
background: #fff;
resize: both;
overflow: auto;
color: #000;
border: none;
width: 200px;
font-weight: bold;
}
.variable-size .content:focus {
outline: 0;
}
/* child circle div css */
.variable-size .circle {
position: absolute;
background-image: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium');
background-position: center center;
z-index: -1;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: all 0.5s ease;
width: 0;
}
/* fast way to make circle height the same as current width */
.variable-size .circle:before {
display: block;
content: '';
width: 100%;
padding-top: 100%;
}
/* demo window css */
HTML,
BODY {
height: 100%;
min-height: 100%;
background: black;
position: relative;
font-family: "Lucida Console", Courier, monospace;
}
<div class="variable-size">
<textarea class="content" rows="1" placeholder="TYPE TEXT OR RESIZE ME ↘"></textarea>
<div class="circle"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
See jsfiddle here... https://jsfiddle.net/joshmoto/6d0zs7uq/
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.stroke();
Source: https://www.w3schools.com/
You could use flex display and insert empty flex-items around the inner div and use flex-basis to fix their width.
Try this
.square {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-height: 100px;
border-radius: 50%;
background: black;
background-size: 100% 100%;
padding: 20px;
}
.content {
width: 300px;
min-height: 100px;
background: tomato;
}
.emptyDiv {
flex-basis: 120px
}
<div class="square">
<div class="emptyDiv"></div>
<div class="content">
Hello!<br>
<br><br><br>This has a variable height but fixed width<br><br><br>Hello
</div>
<div class="emptyDiv"></div>
</div>
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>
SO,
I've created a four-column fluid-width layout for a site, and I'm working on placing a fluid square DIV within one of my columns. There are a few techniques I've found to achieve this - namely, setting padding-bottom to the same percentage as the width - but none of these seem to work when the DIV contains content.
Is there a way to maintain a 1:1 (square) ratio on a fluid DIV when that DIV contains content?
Here's my HTML:
<div id="leftmostcolumn">
<div id="logo"></div>
</div>
<div id="leftcolumn"></div>
<div id="rightcolumn"></div>
<div id="rightmostcolumn"></div>
And my CSS:
body {
width: 100%;
height: 100%;
background-color: red;
}
#leftmostcolumn {
position: absolute;
top: 0;
left: 0;
width: 25%;
height: 100%;
background-color: blue;
}
#leftcolumn {
position: absolute;
top: 0;
left: 25%;
width: 25%;
height: 100%;
background-color: green;
}
#rightcolumn {
position: absolute;
top: 0;
left: 50%;
width: 25%;
height: 100%;
background-color: yellow;
}
#rightmostcolumn {
position: absolute;
top: 0;
left: 75%;
width: 25%;
height: 100%;
background-color: gray;
}
#logo {
width:100%;
padding-bottom:100%;
background-color: #aa2d2d;
color: white;
}
And here's a JsFiddle.
The DIV "logo" is the one I'm trying to maintain as a square. Right now, I've used the padding-bottom approach but that doesn't do the trick when there's content in the DIV. Any input is greatly appreciated!
Marca
EDIT:
Getting there...I'm adapting a script I found to find the width of the DIV and then apply that value to the height to keep it a square. However, as it stands now the script doesn't constantly resize the DIV, and it won't allow it to shrink below a certain size. Any thoughts on how to correct either of these issues?
HTML:
<div id="box"></div>
CSS:
#box { width: 75%; height: 50px; background-color: black; }
JQUERY:
$("#box").css("height", function() {
return $(this).width();
});
JsFiddle is here.
This is something I've actually been messing around with for a while, and have come up with a quasi (but not entirely) hacky, CSS-only solution that seems to work on most browsers in the past decade. The trick is to use images, and positioning in a tricky fashion. Consider the following (simplification) of your code.
Markup:
<div class="sqr_box">
your content goes here!
</div>
CSS:
.sqr_box
{
width: 50%; /* or 100px, or 20em, or whatever you want */
border: solid 2px pink;
background-color: grey;
color: white;
}
Now, we can't set the height in terms of percent, so we won't; instead, first we'll go into Photoshop, and make an image that is 2x2 px, transparent, or background-colored. Next we'll add the following to your markup:
<div class="sqr_box">
<img src="images/sizers/2x2.png" class="sizer">
<div class="content">your content goes here!</div>
</div>
and THIS to your CSS:
.sqr_box
{
width: 50%; /* or 100px, or 20em, or whatever you want */
position: relative; /* static positioning is less than ideal for this scenario */
}
.sqr_box > img.sizer
{
display: block; /* images default to an inline-block like thing */
width: 100%;
height: auto; /* CLUTCH!!! this ensures that the image's height changes to maintain proportions with it's width */
visibility: hidden;
}
.sqr_box > .content
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%; /* Our parent element now has a dynamically assigned height, this will work */
border: solid 2px pink;
background-color: grey;
color: white;
}
Best of all, this will work for any sized ratio of box you'd want! Just change the proportions of the image!
Hope this is all still relevant to you, 3 months later.
-Sandy
Put all four columns in one div. set that div to 100% width and set the font size to 100em
Have each of your four columns have a width of 25em instead of 25%
Have your logo width and height set to 25em each
Is there a css-only solution to scale an image into a bounding box (keeping aspect-ratio)? This works if the image is bigger than the container:
img {
max-width: 100%;
max-height: 100%;
}
Example:
Use case 1 (works): http://jsfiddle.net/Jp5AQ/2/
Use case 2 (works): http://jsfiddle.net/Jp5AQ/3/
But I want to scale up the image until a dimension is 100% of the container.
Use case 3 (doesn't work): http://jsfiddle.net/Jp5AQ/4/
Thanks to CSS3 there is a solution !
The solution is to put the image as background-image and then set the background-size to contain.
HTML
<div class='bounding-box'>
</div>
CSS
.bounding-box {
background-image: url(...);
background-repeat: no-repeat;
background-size: contain;
}
Test it here: http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=contain
Full compatibility with latest browsers: http://caniuse.com/background-img-opts
To align the div in the center, you can use this variation:
.bounding-box {
background-image: url(...);
background-size: contain;
position: absolute;
background-position: center;
background-repeat: no-repeat;
height: 100%;
width: 100%;
}
Note: Even though this is the accepted answer, the answer below is more accurate and is currently supported in all browsers if you have the option of using a background image.
Edit 2: In the modern age, using object-fit might be an even better solution: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
No, there is no CSS only way to do this in both directions. You could add
.fillwidth {
min-width: 100%;
height: auto;
}
To the an element to always have it 100% width and automatically scale the height to the aspect ratio, or the inverse:
.fillheight {
min-height: 100%;
width: auto;
}
to always scale to max height and relative width. To do both, you will need to determine if the aspect ratio is higher or lower than it's container, and CSS can't do this.
The reason is that CSS does not know what the page looks like. It sets rules beforehand, but only after that it is that the elements get rendered and you know exactly what sizes and ratios you're dealing with. The only way to detect that is with JavaScript.
Although you're not looking for a JS solution I'll add one anyway if someone might need it. The easiest way to handle this with JavaScript is to add a class based on the difference in ratio. If the width-to-height ratio of the box is greater than that of the image, add the class "fillwidth", else add the class "fillheight".
$('div').each(function() {
var fillClass = ($(this).height() > $(this).width())
? 'fillheight'
: 'fillwidth';
$(this).find('img').addClass(fillClass);
});
.fillwidth {
width: 100%;
height: auto;
}
.fillheight {
height: 100%;
width: auto;
}
div {
border: 1px solid black;
overflow: hidden;
}
.tower {
width: 100px;
height: 200px;
}
.trailer {
width: 200px;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tower">
<img src="http://placekitten.com/150/150" />
</div>
<div class="trailer">
<img src="http://placekitten.com/150/150" />
</div>
Here's a hackish solution I discovered:
#image {
max-width: 10%;
max-height: 10%;
transform: scale(10);
}
This will enlarge the image tenfold, but restrict it to 10% of its final size - thus bounding it to the container.
Unlike the background-image solution, this will also work with <video> elements.
Interactive example:
function step(timestamp) {
var container = document.getElementById('container');
timestamp /= 1000;
container.style.left = (200 + 100 * Math.sin(timestamp * 1.0)) + 'px';
container.style.top = (200 + 100 * Math.sin(timestamp * 1.1)) + 'px';
container.style.width = (500 + 500 * Math.sin(timestamp * 1.2)) + 'px';
container.style.height = (500 + 500 * Math.sin(timestamp * 1.3)) + 'px';
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
#container {
outline: 1px solid black;
position: relative;
background-color: red;
}
#image {
display: block;
max-width: 10%;
max-height: 10%;
transform-origin: 0 0;
transform: scale(10);
}
<div id="container">
<img id="image" src="https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png">
</div>
Today, just say object-fit: contain. Support is everything but IE: http://caniuse.com/#feat=object-fit
html:
<div class="container">
<img class="flowerImg" src="flower.jpg">
</div>
css:
.container{
width: 100px;
height: 100px;
}
.flowerImg{
width: 100px;
height: 100px;
object-fit: cover;
/*object-fit: contain;
object-fit: scale-down;
object-position: -10% 0;
object-fit: none;
object-fit: fill;*/
}
You can accomplish this with pure CSS and complete browser support, both for vertically-long and horizontally-long images at the same time.
Here's a snippet which works in Chrome, Firefox, and Safari (both using object-fit: scale-down, and without using it):
figure {
margin: 0;
}
.container {
display: table-cell;
vertical-align: middle;
width: 80px;
height: 80px;
border: 1px solid #aaa;
}
.container_image {
display: block;
max-width: 100%;
max-height: 100%;
margin-left: auto;
margin-right: auto;
}
.container2_image2 {
width: 80px;
height: 80px;
object-fit: scale-down;
border: 1px solid #aaa;
}
Without `object-fit: scale-down`:
<br>
<br>
<figure class="container">
<img class="container_image" src="https://i.imgur.com/EQgexUd.jpg">
</figure>
<br>
<figure class="container">
<img class="container_image" src="https://i.imgur.com/ptO8pGi.jpg">
</figure>
<br> Using `object-fit: scale-down`:
<br>
<br>
<figure>
<img class="container2_image2" src="https://i.imgur.com/EQgexUd.jpg">
</figure>
<br>
<figure>
<img class="container2_image2" src="https://i.imgur.com/ptO8pGi.jpg">
</figure>
Another solution without background image and without the need for a container (though the max sizes of the bounding box must be known):
img{
max-height: 100px;
max-width: 100px;
width: auto; /* These two are added only for clarity, */
height: auto; /* as the default is auto anyway */
}
If a container's use is required, then the max-width and max-height can be set to 100%:
img {
max-height: 100%;
max-width: 100%;
width: auto; /* These two are added only for clarity, */
height: auto; /* as the default is auto anyway */
}
div.container {
width: 100px;
height: 100px;
}
For this you would have something like:
<table>
<tr>
<td>Lorem</td>
<td>Ipsum<br />dolor</td>
<td>
<div class="container"><img src="image5.png" /></div>
</td>
</tr>
</table>
This example to stretch the image proportionally to fit the entire window.
An improvisation to the above correct code is to add $( window ).resize(function(){});
function stretchImg(){
$('div').each(function() {
($(this).height() > $(this).find('img').height())
? $(this).find('img').removeClass('fillwidth').addClass('fillheight')
: '';
($(this).width() > $(this).find('img').width())
? $(this).find('img').removeClass('fillheight').addClass('fillwidth')
: '';
});
}
stretchImg();
$( window ).resize(function() {
strechImg();
});
There are two if conditions. The first one keeps checking if the image height is less than the div and applies .fillheight class while the next checks for width and applies .fillwidth class.
In both cases the other class is removed using .removeClass()
Here is the CSS
.fillwidth {
width: 100%;
max-width: none;
height: auto;
}
.fillheight {
height: 100vh;
max-width: none;
width: auto;
}
You can replace 100vh by 100% if you want to stretch the image with in a div. This example to stretch the image proportionally to fit the entire window.
Are you looking to scale upwards but not downwards?
div {
border: solid 1px green;
width: 60px;
height: 70px;
}
div img {
width: 100%;
height: 100%;
min-height: 500px;
min-width: 500px;
outline: solid 1px red;
}
This however, does not lock aspect-ratio.
I have used table to center image inside the box. It keeps aspect ratio and scales image in a way that is totally inside the box. If the image is smaller than the box then it is shown as it is in the center. Below code uses 40px width and 40px height box. (Not quite sure how well it works because I removed it from another more complex code and simplified it little bit)
.SmallThumbnailContainer {
display: inline-block;
position: relative;
float: left;
width: 40px;
height: 40px;
border: 1px solid #ccc;
margin: 0px;
padding: 0px;
}
.SmallThumbnailContainer {
width: 40px;
margin: 0px 10px 0px 0px;
}
.SmallThumbnailContainer tr {
height: 40px;
text-align: center;
}
.SmallThumbnailContainer tr td {
vertical-align: middle;
position: relative;
width: 40px;
}
.SmallThumbnailContainer tr td img {
overflow: hidden;
max-height: 40px;
max-width: 40px;
vertical-align: middle;
margin: -1px -1px 1px -1px;
}
<table class="SmallThumbnailContainer" cellpadding="0" cellspacing="0">
<tr>
<td>
<img src="https://www.gravatar.com/avatar/bf7d39f4ed9c289feca7de38a0093250?s=32&d=identicon&r=PG" width="32" height="32" alt="OP's SO avatar image used as a sample jpg because it is hosted on SO, thus always available" />
</td>
</tr>
</table>
Note: the native thumbnail size in this snippet is 32px x 32px, which is smaller than its 40px x 40px container. If the container is instead sized smaller than the thumbnail in any dimension, say 40px x 20px, the image flows outside the container in the dimensions that are smaller than the corresponding image dimension. The container is marked by a gray 1px border.
Use Object Fit on both div and img to scale image
<div class="box"><img src="image.jpg"></div>
.box {height: auto;
object-fit: cover;}
img { height: 100%; object-fit: cover; }
This worked for my needs, doesn't flatten out the image while setting height limitation, it overflows instead.
.top-container{
width:50%;
}
.img-container {
display: flex;
justify-content: center;
align-items: center;
height: 40vh;
width: 100%;
overflow: hidden;
}
.img-container img {
max-width: 10%;
max-height: auto;
transform: scale(10);
}
<div class='top-container'>
<div class='img-container'>
<img src='image.jpg'>
</div>
</div>
First some CSS:
div.image-wrapper {
height: 230px; /* Suggestive number; pick your own height as desired */
position: relative;
overflow: hidden; /* This will do the magic */
width: 300px; /* Pick an appropriate width as desired, unless you already use a grid, in that case use 100% */
}
img {
width: 100%;
position: absolute;
left: 0;
top: 0;
height: auto;
}
The HTML:
<div class="image-wrapper">
<img src="yourSource.jpg">
</div>
.img-class {
width: <img width>;
height: <img height>;
content: url('/path/to/img.png');
}
Then on the element (you can use javascript or media queries to add responsiveness):
<div class='img-class' style='transform: scale(X);'></div>
.boundingbox {
width: 400px;
height: 500px;
border: 2px solid #F63;
}
img{
width:400px;
max-height: 500px;
height:auto;
}
With the styles set as shown above in css, now the following html div will show the image always fit width wise and will adjust hight aspect ratio to width. Thus image will scale to fit a bounding box as asked in the question.
<div class="boundingbox"><img src="image.jpg"/></div>