0

I have a parent <div> of unknown size and I would like to create a child <div> of the size of the biggest square which can be contained in the parent and center this square in the middle of the parent. Is it possible with HTML and CSS?

I am aware of max-width and max-height but do not know how to ensure the aspect-ratio.

I want to be able to do something like this:

.frame {
  height: 80%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.square {
  width: 750px;
  height: 750px;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.back {
  width: 100%;
}

.front {
  width: 70.5%;
  top: 23.965%;
  position: absolute;
}
<div class="frame">
  <div class="square">
    <img class="back" src="back.png">
    <img class="front" src="front.png">
  </div>
</div>

But in the square I want the width and height set based on its parent frame as described. The parent frame can be both landscape or portrait.

Arman Ebrahimi
  • 2,035
  • 2
  • 7
  • 20
fales
  • 89
  • 7
  • 2
    Please provide your HTML and attempt – trincot Mar 28 '22 at 20:25
  • 1
    This probably does what you want? https://stackoverflow.com/a/28985475/1495198 "This works because that the padding of an element is calculated relative to the width of its parent element" – V Maharajh Mar 28 '22 at 20:40
  • See [Maintain the aspect ratio of a div with CSS](https://stackoverflow.com/questions/1495407/maintain-the-aspect-ratio-of-a-div-with-css) – isherwood Mar 28 '22 at 20:52
  • As far as I understand it, the padding works if only width vary, but not both width and height. – fales Mar 28 '22 at 21:00
  • 1
    Unfortunately, I don't believe that's possible - you're right that it can be solved when the screen is portrait using padding, but there's no analogue for landscape that fixes aspect ratio (afaik) – tbjgolden Mar 28 '22 at 21:12
  • 1
    It might be possible to do it if it spans the whole screen, using 100vmin as the width and height, but for the general case of any old dimensions, probably not (unless you can solve it with `calc(100vmin - 16px)`) – tbjgolden Mar 28 '22 at 21:17
  • @tbjgolden Thank you, while vmin does not solve the problem completely, it is at least much better than the width and heght set by px. Is there any way to refer by vmin (or something similar) to the previous element, may be iframe? (my quick test is not working...) – fales Mar 28 '22 at 21:42
  • 1
    @fales Could you reopen the question? I found something that could be an answer https://codepen.io/tbjgolden/pen/ZEvyEBv – tbjgolden Mar 28 '22 at 21:47
  • 1
    @tbjgolden I would like to reopen the question, but it seems to me that it is not up to me. – fales Mar 28 '22 at 21:50
  • @tbjgolden It seems great! Thank you. Hopefully, the question will get opened, otherwise, I would try to create a new one. – fales Mar 28 '22 at 21:54
  • Thanks for putting some code up, it helps. In particular are your images square? – A Haworth Mar 29 '22 at 05:29
  • @AHaworth The back.png is indeed a square, the other one is not a square. – fales Mar 29 '22 at 06:46
  • @tbjgolden I have experimented with your code a bit and found out that there still is some width of 800px hardcoded and it can happen hence, that the square is not as big as it could be. It seems to me that a workaround of making the second image also square of the same size as the first is in the end the best possibility. However, I am still wondering if it is not possible to do something as simple as the biggest square in a rectangle in HTML/CSS. – fales Mar 29 '22 at 08:22
  • So for my example, you'd have to create a media query that precisely describes when the containing box is portrait (the media queries are specific to the containing box): this tool might help https://tom.bio/experiments/media-query-playground There's no way of solving this problem without some hardcoding, but media queries can handle the switch between bounded by width and bounded by height – tbjgolden Mar 29 '22 at 09:16
  • @tbjgolden the question has been reopened, please consider providing an answer based on your comments. – fales Mar 31 '22 at 15:36
  • @fales added a full answer :) – tbjgolden Apr 02 '22 at 19:07

1 Answers1

2

This was not possible for a long time; as padding-top:100% and aspect-ratio:1/1 are limited to the width (and not the height) of the container.

BUT It is now possible; keep reading...

The Problem

███ <- square fills the width correctly
███ 
░░░ <- outer box (portrait)
░░░
███████████ \
███████████  } <- outer box (landscape) stops here
███████████ /     but square overfloweth
███████████
███████████
███████████

The "Solution"

Technically, the aspect-ratio doesn't fill the width, so much as the "block direction", which in western languages is always the width...

However, we can change the writing-mode property to get the block direction to be height, like so:

writing-mode: vertical-lr

███░░░ <- outer box (landscape)
███░░░
 ^- square fills the height correctly
███████ 
███████ 
███████
███████
^---^
   `---- outer box (portrait) stops here, but square overfloweth

So now we have the opposite problem, it works in landscape but not portrait.

The Magic

Using the right combination of media queries it should be possible to switch the writing mode at the exact dimensions it switches from portrait to landscape.

html, body {
  margin: 0;
}

*, *:before, *:after {
  box-sizing: border-box;
}

.bounds-outer {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
}
.bounds-inner {
  writing-mode: vertical-rl;
  width: 100%;
  max-width: 90%;
  height: 100vh;
  border: 1px dashed black;
  display: flex;
  align-items: center;
}

.a {
  position: relative;
  flex: 1 0 1px;
  background: red;
  padding-block-start: 100%;
}

.b {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  color: white;
  writing-mode: horizontal-tb;
}

/* this media query depends on layout */
@media (max-aspect-ratio: 10/9)  {
  .bounds-inner {
    writing-mode: horizontal-tb;
  }
}
<div class="bounds-outer">
    <div class="bounds-inner">
      <div class="a">
        <div class="b">
          Hi
        </div>
      </div>
    </div>
</div>

NOTE: Your media queries will depend on the size of the box. Verified in Chrome, Firefox and Safari.

tbjgolden
  • 1,115
  • 8
  • 9