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>
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'm trying to create 2 divs, one of them is the left sidebar and the other one is the body of the page where content shows up. What I'm trying to do is:
make the sidebar div height 100%
the body height 100% too
make the body's width change when sidebar width changes.
This is the code that I've tried so far:
#Sidebar{
background-color:#F0F0F0;
height: calc(100% - 80px);
width: 257px;
position: fixed;
left: 0;
bottom: 0;
overflow: hidden;
white-space: nowrap;
}
#content {
margin: 0;
position: fixed;
height: 100%;
}
when I do this, the content div shows IN the Sidebar!
#Sidebar {
height: calc(100% - 80px);
width: 257px;
position: fixed;
top:0;
left: 0;
bottom: 0;
overflow: hidden;
white-space: nowrap;
border:1px solid #000;
}
#content {
margin: 0;
position: fixed;
height: 100%;
border:1px solid tomato;
}
<div id="Sidebar">
Hello World!!
</div>
<div id="content">
Content Div
</div>
Note that i use Jquery .Resizable to change the width.
and this is a jsfiddle https://jsfiddle.net/j64r3bm1/
Can't You just put the sidebar
.sidebar {
position: fixed;
height: 100vh;
left: 0px;
top: 0px;
width: 275px;
}
and the body container
body {
padding-left: 275px;
}
it will never overlap and you can just build your body as you wish.
The fun thing about this is when you use media-queries to handle mobile version - you can just remove padding and move sidebar outside of body and on some button (or anything) make it slide into view.
Set the margin-left of your main content to the same width (+gap if you prefer) and change it when you resize your sidebar.
#content {
margin-left: 257px;
Updated fiddle: https://jsfiddle.net/j64r3bm1/2/
To explain what's happening: when you use position:fixed, it no longer takes up space and effectively 'hovers' on the page, so when your content div comes along, it gets put at left:0 because they're nothing to its left that's taking up space on the page.
You could also use position:fixed on your content and set the left - but then neither will take up 100% height (as they will both be 0width/0height).
Alternatively, you could take out the position:fixed and use float:left.
Looks like i figured out how to do it.
and I used JQuery to do that, all what i did is :
#Sidebarlist
{
background-color: var(--SidebarBackgroundColor);
height: calc(100% - 80px);
color:var(--SidebarTextColor);
width: 257px;
position: fixed;
left: 0;
bottom: 0;
overflow:hidden;
white-space: nowrap;
}
#MainContentdiv {
height: 100%;
}
And using jquery :
$('#Sidebarlist').resizable({
start: function( event, ui ) {},
stop: function( event, ui ) {},
handles: 'n,w,s,e',minWidth: 200,
maxWidth: 400
});
$( "#Sidebarlist" ).on( "resizestart", function( event, ui ) {
var marginleft = $("#Sidebarlist").width();
$('#MainContentdiv').css('margin-left',marginleft);
});
$( "#Sidebarlist" ).on( "resizestop", function( event, ui ) {
var marginleft = $("#Sidebarlist").width();
$('#MainContentdiv').css('margin-left',marginleft);
});
Thanks for anybody that answered my question.
You can simply add
left: 257px;
top: 0;
To the #content div and it will appear how you want it. To get this to resize, you'd adjust this. The alternative is to use a container, like this:
#Container {
height: 100%;
position: fixed;
width: 100%;
top: 0;
left: 0;
display: flex;
flex-direction: row;
}
#Sidebar {
height: calc(100% - 80px);
width: 257px;
display: block;
overflow: hidden;
white-space: nowrap;
border:1px solid #000;
}
#content {
margin: 0;
height: 100%;
border:1px solid tomato;
}
<div id="Container">
<div id="Sidebar">
Hello World!!
</div>
<div id="content">
Content Div
</div>
</div>
I'm gonna give you an out there answer, I've tested this in firefox and chrome and it works. But it's a bit cutting edge so I'm not sure if IE will support it.
It's using css variables, if you have a different variable in at the start (in the :root section) then the page will be calculated differently.
I also took your borders out as they mess with total width and used background colours to tell the divs apart.
EDIT:
I've added a tiny amount of JS to show the variable being updated on the fly and everything readjusting.
changeSidebar = function() {
var customSize = document.querySelector('.sidebar-width').value;
document.documentElement.style.setProperty('--menu-width', customSize + 'px');
}
:root {
--menu-width: 257px
}
#sidebar,
#sidebar-footer {
width: var(--menu-width);
left: 0;
overflow: hidden;
position: fixed
}
body {
margin: 0
}
#sidebar {
height: calc(100% - 80px);
top: 0;
white-space: nowrap;
background: orange
}
#sidebar-footer {
height: 80px;
top: calc(100% - 80px);
background: pink
}
#content {
position: fixed;
right: 0;
width: calc(100% - var(--menu-width));
height: 100%;
background: tomato
}
<div id="sidebar">
Hello World!!
</div>
<div id="sidebar-footer">
I'm just here to fill that space...
</div>
<div id="content">
Content Div
<br />
<input class="sidebar-width" value='257'>
<button onclick="changeSidebar();">Enter</button>
</div>
That is the Solution :
var offsetHeight = document.getElementById('Sidebar').offsetHeight;
document.getElementById('content').style.height = offsetHeight+'px';
#Sidebar{
background-color:#F0F0F0;
height: 700px;
width: 10%;
float:left;
left: 0;
bottom: 0;
overflow: hidden;
}
#content {
margin: 0;
width:90%;
float:right;
background-color:green;
}
<div id="Sidebar">
Side bar
</div>
<div id="content">
Hello World !
</div>
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/
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