Use CSS (And Maybe JavaScript) to Make an Element Be Square (Or Maintain a Specific Aspect Ratio)

Use CSS (and maybe JavaScript) to make an element be square (or maintain a specific aspect ratio)

I figured out how to do this without js, though you need to use a transparent image.

Set up a html structure like:

<div class="rect_container"><img class="rect_image" src="rect_image.png"/>
<div class="rect">Your favorite content here</div>
</div>

Use a AxB transparent png for rect_image where AxB is the aspect ratio.

Meanwhile set up a stylesheet like:

.rect_container {width: 50%; position: relative;}
.rect_image {width: 100%; display: block;}
.rect {width: 100%; height: 100%; position: absolute; left: 0px; top: 0px;}

The important thing here is taking advantage of the fact that images maintain their aspect ratio when resized in one direction. Meanwhile, we need a useable div, so we make the image display as block, wrap it in a div, and put an absolutely positioned div inside that. I distilled this code from something more complicated I actually tested. Works like a charm.

Maintain the aspect ratio of a div with CSS

Just create a wrapper <div> with a percentage value for padding-bottom, like this:

.demoWrapper {
padding: 10px;
background: white;
box-sizing: border-box;
resize: horizontal;
border: 1px dashed;
overflow: auto;
max-width: 100%;
height: calc(100vh - 16px);
}

div {
width: 100%;
padding-bottom: 75%;
background: gold; /** <-- For the demo **/
}
<div class="demoWrapper">
<div></div>
</div>

Pure CSS Solution - Square Elements?

It is actually possible to achieve it with this neat trick i found at
this blog

#square {
width: 100%;
height: 0;
padding-bottom: 100%;
}

Maintain the aspect ratio of a div with CSS

Just create a wrapper <div> with a percentage value for padding-bottom, like this:

.demoWrapper {
padding: 10px;
background: white;
box-sizing: border-box;
resize: horizontal;
border: 1px dashed;
overflow: auto;
max-width: 100%;
height: calc(100vh - 16px);
}

div {
width: 100%;
padding-bottom: 75%;
background: gold; /** <-- For the demo **/
}
<div class="demoWrapper">
<div></div>
</div>

How to make div element auto-resize maintaining aspect ratio?

The aspect-ratio ref property has a good support now so you can use the below:

body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}

.stage {
--r: 960 / 540;

aspect-ratio: var(--r);
width:min(90%, min(960px, 90vh*(var(--r))));

display: flex;
justify-content: center;
align-items: center;


background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>

How to group the css selectors

I don't think you can reasonably do this with a single line.

You could do simplify it with Sass/Scss:

$ratios: "square", "landscape", "portrait", "widescreen", "ultrawide", "golden";

@each $ratio in $ratios {
:host([aspect-ratio='#{$ratio}']) img {
aspect-ratio: var(--ratio-#{$ratio});
}
}

Which generates the CSS:

:host([aspect-ratio='square']) img {
aspect-ratio: var(--ratio-square);
}

:host([aspect-ratio='landscape']) img {
aspect-ratio: var(--ratio-landscape);
}

:host([aspect-ratio='portrait']) img {
aspect-ratio: var(--ratio-portrait);
}

:host([aspect-ratio='widescreen']) img {
aspect-ratio: var(--ratio-widescreen);
}

:host([aspect-ratio='ultrawide']) img {
aspect-ratio: var(--ratio-ultrawide);
}

:host([aspect-ratio='golden']) img {
aspect-ratio: var(--ratio-golden);
}

Div Square, width size based on 100% height

Ok here the solution.

<div id="square" style="background-color:black;height:100%">test</div>

$(window).ready(updateWidth);
$(window).resize(updateWidth);

function updateWidth()
{
var square = $('#square');
var size = square.height();

square.css('width',size);
}

http://jsfiddle.net/j372H/7/

What's the algorithm to calculate aspect ratio?

I gather you're looking for an usable aspect ratio integer:integer solution like 16:9 rather than a float:1 solution like 1.77778:1.

If so, what you need to do is find the greatest common divisor (GCD) and divide both values by that. The GCD is the highest number that evenly divides both numbers. So the GCD for 6 and 10 is 2, the GCD for 44 and 99 is 11.

For example, a 1024x768 monitor has a GCD of 256. When you divide both values by that you get 4x3 or 4:3.

A (recursive) GCD algorithm:

function gcd (a,b):
if b == 0:
return a
return gcd (b, a mod b)

In C:

static int gcd (int a, int b) {
return (b == 0) ? a : gcd (b, a%b);
}

int main(void) {
printf ("gcd(1024,768) = %d\n",gcd(1024,768));
}

And here's some complete HTML/Javascript which shows one way to detect the screen size and calculate the aspect ratio from that. This works in FF3, I'm unsure what support other browsers have for screen.width and screen.height.

<html><body>
<script type="text/javascript">
function gcd (a, b) {
return (b == 0) ? a : gcd (b, a%b);
}
var w = screen.width;
var h = screen.height;
var r = gcd (w, h);
document.write ("<pre>");
document.write ("Dimensions = ", w, " x ", h, "<br>");
document.write ("Gcd = ", r, "<br>");
document.write ("Aspect = ", w/r, ":", h/r);
document.write ("</pre>");
</script>
</body></html>

It outputs (on my weird wide-screen monitor):

Dimensions = 1680 x 1050
Gcd = 210
Aspect = 8:5

Others that I tested this on:

Dimensions = 1280 x 1024
Gcd = 256
Aspect = 5:4

Dimensions = 1152 x 960
Gcd = 192
Aspect = 6:5

Dimensions = 1280 x 960
Gcd = 320
Aspect = 4:3

Dimensions = 1920 x 1080
Gcd = 120
Aspect = 16:9

I wish I had that last one at home but, no, it's a work machine unfortunately.

What you do if you find out the aspect ratio is not supported by your graphic resize tool is another matter. I suspect the best bet there would be to add letter-boxing lines (like the ones you get at the top and bottom of your old TV when you're watching a wide-screen movie on it). I'd add them at the top/bottom or the sides (whichever one results in the least number of letter-boxing lines) until the image meets the requirements.

One thing you may want to consider is the quality of a picture that's been changed from 16:9 to 5:4 - I still remember the incredibly tall, thin cowboys I used to watch in my youth on television before letter-boxing was introduced. You may be better off having one different image per aspect ratio and just resize the correct one for the actual screen dimensions before sending it down the wire.



Related Topics



Leave a reply



Submit