Make a <div> square when there is a dynamically changing width based on percentage [duplicate]
Asked Answered
S

4

43

I am working on a web app that will generate an NxN grid based on the user's selection of N. I want the total width of the grid to be relative (ie 100% of the available space) so that users can print on various paper sizes.

I can easily calculate the width of the squares in the grid by % (ie: 100%/N), but I am having issues calculating the height. The height of a web page is always going to be infinite unless I artificially limit it which, like I said, I don't want to do.

How can I make the squares in my grid be square versus rectangular when the height and width constraints of my grid are dynamic and not square?

Slander answered 15/4, 2010 at 20:25 Comment(1)
The real problem is not the size of the squares: that is simply (height/n). The problem is setting the total height of the grid to the same as it's width. It's tricky, without either making some fixed-size assumptions, or using some form of scripting.Neck
E
25

This is un-tested, I do not know of how to do this in CSS only, I would use jQuery.

$('div').height($('div').width());
Expedite answered 15/4, 2010 at 20:39 Comment(2)
I didn't know JQuery at the time but once I learned it, this was easy enough. Thanks!Slander
this will fail if the page get resized.Equalizer
C
60

There are 3 main techniques to keep the aspect ratio of a responsive element.
The first one is by far the best and will work for a variety of use cases : the aspect-ratio CSS property. The 2 others may suit other use cases : using padding or vw units :
(for a complete solution for a responsive grid of squares, you can see this answer)

The aspect-ratio property

This specifies directly the aspect ratio of and element. It can be based on the width or height of the element. (see MDN)
Here is an example :

body {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
}

div {
  width: 23%;
  margin-bottom: 2%;
  background: gold;
  aspect-ratio: 1/1;
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

Using vw units

You can use vw units to make your elements square and responsive (viewport units on MDN).
1vw = 1% of viewport width so you can set the height of the elements according to the width of the viewport (or height with vh units).
Example with a 4x4 grid :

body{
  margin:0;
  display:flex;
  flex-wrap:wrap;
  justify-content:space-around;
}

div{
    width:23vw; height:23vw;
    margin:1vw 0;
    background:gold;  
}
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

The same behaviour can be achieved sizing the element according to the viewport height using vh units.


Using padding

Padding is calculated according to the container's width so you can use it to set the height of block according to its width.
Example with a 4x4 grid :

.wrap {
    width:80%;
    margin:0 auto;
}
.wrap div {
    width:23%;
    padding-bottom:23%;
    margin:1%;
    float:left;
    background:gold;
}
<div class="wrap">
    <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
Checkerboard answered 13/5, 2014 at 14:4 Comment(3)
this is fine as long as you realise that vw and vh are relative to the size of the viewport, not any given container (unfortunately)Telegenic
@Telegenic I edited my answer with a solution based on the width of the container ("Padding technique")Checkerboard
that's an awesome hack! programmers for the win!!Homograft
M
28

To make a div a square is pretty easy with CSS. You set a width, let's say 50%. Then you add a padding-bottom of the same value:

div {
width: 50%;
padding-bottom: 50%;
}

and it will stay square whenever you resize the window.

.

.

You can do this with any side ratio you want, if you want the box to be 16:9 you calculate:

9/16= 0.56

which you then multiply by the width of your element (in this case 50%(=0.5)), so:

9/16*0.5= 0.28 = 28%

Morgen answered 19/10, 2014 at 20:38 Comment(6)
I was looking for a pure css way to do this, thank you!Alysiaalyson
Don't work in Edge. :/ jsfiddle.net/836popre/3Ranchman
Beautiful solution, needs to be the answer.Tabshey
FYI, I used this solution to maintain a dynamic perfect circle, but I needed to explicitly set height: 0 for it to work at all.Tabshey
Unfortunately this seems to break when max-width is set, ie max-width: 200px;;Oller
Great answer, can you explain how the padding-bottom makes the height equals to the width?Anxious
E
25

This is un-tested, I do not know of how to do this in CSS only, I would use jQuery.

$('div').height($('div').width());
Expedite answered 15/4, 2010 at 20:39 Comment(2)
I didn't know JQuery at the time but once I learned it, this was easy enough. Thanks!Slander
this will fail if the page get resized.Equalizer
H
-3

The above solution doesn't preserve area - this one is better

        //@param {jQuery} div 
        function makeSquare(div){
            //make it square !
            var oldDimens = {
                h : div.height(),
                w : div.width()
            };
            var area = oldDimens.h * oldDimens.w;
            var l = Math.sqrt(area);
            div.height(l).width(l);
        }
Howlet answered 11/12, 2012 at 5:25 Comment(1)
I don't believe preserving area is relevant. The OP is wanting to no how to make an element square based on its width. Changing this width is kind of defeating the purpose. -1Scarlatti

© 2022 - 2024 — McMap. All rights reserved.