How to style a div to be a responsive square? [duplicate]
Asked Answered
U

6

247

I want my div to adapt its height to always equal its width. The width is percental. When the parent's width decreases, the box should decrease by keeping its aspect ratio.

How to do this is CSS?

Untruth answered 28/9, 2013 at 14:37 Comment(4)
Square elements in pure css is challenging and with limitations, but has been answered before. Another useful reference may be this answer.Gastrulation
For a responsive grid of square elements you can check this answer : responsive square columnsColeoptile
Perfect square on any screen: jsfiddle.net/far4jqt2/2Pede
Here's a good article with a good explanation... spin.atomicobject.com/2015/07/14/css-responsive-squareMercie
B
265

Works on almost all browsers.

You can try giving padding-bottom as a percentage.

<div style="height:0;width:20%;padding-bottom:20%;background-color:red">
<div>
Content goes here
</div>
</div>

The outer div is making a square and inner div contains the content. This solution worked for me many times.

Here's a jsfiddle

Burgh answered 28/9, 2013 at 15:28 Comment(11)
It works, but I don't understand the technique. Could you please explain why this actually works?Untruth
This is very good tutorial if you want to use padding-bottom method. [link]dwuser.com/education/content/…Burgh
Preferable to the chosen answer because it works within the constraints of a container, NOT the viewport which is rarely usefulHic
I didn't like this one at first because it looks like a hack, anyhow there's a good discussion at #11004411Annabel
Don't forget box-sizing: content-box; in case you add border on the entity. Else it can distort the 1:1 ratio. (happened when adding fat border-radius)Eichman
This is really, really cool. How did I not know that? You can get anything to have an aspect ratio, for example I just set my padding-bottom to be 120%, and now the width:height ratio is 1:1.2 - amazing.Jesuit
does not seem to work on new ie - Edge when element has display:flex;, it actually works on older versionsGradus
It doesn't seem to work for me in Chrome somehow. If there is no content in the inner div, the box ratio is 1:1, but when I add content in the inner div, it takes some space and make the height greater than width.Boeke
@Boeke You have to add position: absolute; on the inner div to make it work. Elements with absolute positioning are ignored when the parent dimensions are calculated. That means you can add content, but also padding, borders, etc to the inner element. :) See this fiddle.Penchant
This technique is actually used to display images in Google AMP. Cool!Bilharziasis
If someone is using flex containers beware because it does not work correctly in nested structuresOsteoma
C
217

To achieve what you are looking for you can use the viewport-percentage length vw.

Here is a quick example I made on jsfiddle.

HTML:

<div class="square">
    <h1>This is a Square</h1>
</div>

CSS:

.square {
    background: #000;
    width: 50vw;
    height: 50vw;
}
.square h1 {
    color: #fff;
}

I am sure there are many other ways to do this but this way seemed the best to me.

Carthage answered 28/9, 2013 at 15:44 Comment(9)
This is definitely the cleanest solution. For people interested in browser support, I found this overview.Untruth
Very nice but browser support is a little bit sketchy at the moment though isn't it - google.ie/…Tenno
This solution doesn't play nice with a grid system. If you're looking at squares expanding with columns width, the answer of @Burgh works better.Endres
Browser support for vw : caniuse.com/#search=vwAbhorrent
Browser support is pretty solid for vw, but it probably won't work for you if your pages scroll. vw is effectively the width of the window, not the viewport, as it includes scrollbars (same with vh for vertical stuff). Bad decision by the spec authors in my view, because this has the potential to be a super useful unit of measurement, but if your pages scroll, you're better off using @rahulbehl's solution. I can't think of a use case where it's handy to have the width including the scrollbars... but it is what it is.Knorring
this deform the image, and is better if you can recort it, so :/Callison
Tip: if you want to fit a square inside a viewport on either portrait or landscape view: ``` @media (orientation:portrait){width:100vw; height:100vw;} @media (orientation:landscape){width:100vh; height:100vh;} ```Ilarrold
Note: this would be bigger than the viewport on superultrawide monitors where 50vw > 100vhKelley
Weird stuff happens if parent is flex.Rusell
O
72

HTML

<div class='square-box'>
    <div class='square-content'>
        <h3>test</h3>
    </div>
</div>

CSS

.square-box{
    position: relative;
    width: 50%;
    overflow: hidden;
    background: #4679BD;
}
.square-box:before{
    content: "";
    display: block;
    padding-top: 100%;
}
.square-content{
    position:  absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    color: white;
    text-align: center;
}

http://jsfiddle.net/38Tnx/1425/

Om answered 11/3, 2015 at 11:29 Comment(11)
This is pure magic, but it works! Thanks!Bandore
What kind of black magic is this ?!Kasandrakasevich
This solution works really well when the width might be restricted by a 'max-width' rule. In those cases the actual computed width might be less than the width set in percentage and all the other solutions which set the padding directly on the outermost element will fail.Drabble
Oh man, this is saucy. 100 points to gidziorJesuit
As @Drabble mention, it's important to set the padding on the pseudo element for it to correctly be constrained by max-widthFresnel
Using ".square-box:after" instead of ".square-box:before" seems to behave in the exact same way.Obola
This works because that the padding of an element is calculated relative to the width of its parent element.Amatruda
I have been looking for answers to keep aspect ratio of divs while resizing them with flex box and this is the only one that worked perfectly. Pure magic, thanks!Fer
The accepted answer does not work. This one works perfectly. Thanks !Switchman
Piling on to say this is absolute CSS magic. The only one that worked here.Mina
This should be the accepted answerAriana
T
35

It is as easy as specifying a padding bottom the same size as the width in percent. So if you have a width of 50%, just use this example below

id or class{
    width: 50%;
    padding-bottom: 50%;
}

Here is a jsfiddle http://jsfiddle.net/kJL3u/2/

Edited version with responsive text: http://jsfiddle.net/kJL3u/394

Tectonic answered 29/5, 2014 at 1:57 Comment(2)
This grows out of the square aspect ratio once you add content to it, though.Confrere
You can fix that problem with overflow:hidden or other absolute positioning of children inside the container. Conveniently exactly like @gidzior's answerAretta
A
8

Another way is to use a transparent 1x1.png with width: 100%, height: auto in a div and absolutely positioned content within it:

html:

<div>
    <img src="1x1px.png">
    <h1>FOO</h1>
</div>

css:

div {
    position: relative;
    width: 50%;
}

img {
    width: 100%;
    height: auto;
}

h1 {
    position: absolute;
    top: 10px;
    left: 10px;
}

Fidle: http://jsfiddle.net/t529bjwc/

Archimedes answered 2/2, 2015 at 11:31 Comment(4)
This is a more useful method, because you have actual size and height to work with - useful for elements inside the square div.Roberson
Nice tip, but this works even better with <svg viewBox='0 0 1 1'></svg>Wilkey
Uhh this doesnt look right at allSwadeshi
This should go into the meseum of "what it used to take to make css work" lolSurety
U
3

This is what I came up with. Here is a fiddle.

First, I need three wrapper elements for both a square shape and centered text.

<div><div><div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat
volutpat.</div></div></div>

This is the stylecheet. It makes use of two techniques, one for square shapes and one for centered text.

body > div {
    position:relative;
    height:0;
    width:50%; padding-bottom:50%;
}

body > div > div {
    position:absolute; top:0;
    height:100%; width:100%;
    display:table;
    border:1px solid #000;
    margin:1em;
}

body > div > div > div{
    display:table-cell;
    vertical-align:middle; text-align:center;
    padding:1em;
}
Untruth answered 28/9, 2013 at 15:58 Comment(1)
Extra elements for a simple square, yuk, but works I suppose. Side note; display:table-cell is not supported in IE7 or older.Jazminejazz

© 2022 - 2024 — McMap. All rights reserved.