3

I can find multiple half solutions, but I am looking for a complete solution to my issue. I have a div that I would like to be centered in the screen with a fixed aspect ratio, that div should in essence always be completely visible, so that div is always the largest it can be whilst keeping the aspect ratio. regardless of resizing the window vertically and horizontally.

There is a codepen here: https://codepen.io/william-bang/pen/ZjyWRd

That I created, this only solves the issue horizontally but not vertically. I have managed to get it working with and but sizing behaves differently for that. I am looking for a CSS solution, although I am open to a JS solution, if anyone is absolutely sure that no solution exists.

body {
  width: 100%;
  height: 100%;
}

.wrapper {
  width: 40%;
  height: 100%;
  margin: auto
}

.img {
  padding-top: 50%;
  width: 100%;
  background: #ccc;
  text-align: center;
}
<div class="wrapper">

  <div class="img">
    **IMG HERE**
  </div>
  
</div>

I would be grateful for any suggestions, this has had me stumped for many hours. thanks in advance :)

Update, the div needs to maintain its aspect ratio on a varying page and at all times be its own maximum size.

@Grenther Thanks for your response, I tried modifying the answer you gave to do it purely in CSS and not having to use a CSS preprocessor. That went really well, until I realized that CSS media queries does not support standard CSS variables, otherwise the method you proposed would have been possible without SCSS but perhaps you already knew that.

:root {
  --ogW: 1600;
  --ogH: 900;
  --ratio: calc( var(--ogW) / var(--ogH));
}

 body {
  width: 100%;
  height: 100%;
}

.ratio {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  
  @media screen and (max-width: 177vh) {
    width: 90vw; 
    height: calc( 90vw / var(--ratio)); 
  } 

  @media screen and (min-width: 177vh) {
    width: calc( 90vh * var(--ratio));  
    height: 90vh;
  }

}

.div {
  width: 100%;
  height: 100%;
  background: red;
  text-align: center;
}
<div class="ratio">

  <div class="div">
    
    Hello!
    
  </div>
  
</div>
William Larsen Bang
  • 187
  • 1
  • 4
  • 14
  • 1
    possible duplicate of https://stackoverflow.com/a/51041869/8620333 – Temani Afif Jul 24 '18 at 22:08
  • @TemaniAfif The problems are different, this problem aims to keep the aspect ratio of a div when the width & height of the window is changing. The other one is trying to keep a ratio between the container and the box. That is not the aim here. – William Larsen Bang Jul 26 '18 at 08:14
  • simply replace the container by the window and read again your sentence ;) .. by the way I simply tagged as *possible duplicate*, I didn't close as duplicate – Temani Afif Jul 26 '18 at 09:00

3 Answers3

3

Final Update:

It turned into a SCSS question, with any input for variable width or height it can be done like this:

http://jsfiddle.net/832v5f0L/41

 $div-width : 1600;
 $div-height : 900;

 $ratio: $div-width / $div-height;

  @media screen and (max-width: (100 * $ratio) + vh) {
    width: 100vw; // always 100vw to fill
    height: (100 / $ratio) + vw; // 100 / ratio
  }

  @media screen and (min-width: (100 * $ratio) + vh) {
    width: (100 * $ratio) + vh;  //100 * ratio
    height: 100vh; // always 100vh to fill
  }

Updated answer:

Media query portrait automatically activates when width is smaller than height. Which makes sure we can use the vh and vw to obtain the maximum possible size without reaching an overflow.

The ratio between the width and height will make sure you can get a fixed aspect ratio.

    body {
  width: 100%;
  height: 100%;
}
.wrapper {
  position: absolute;
  left: 50%;
  top: 50%;
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

/* 
100vh * (100 / height) 
with hright 50:
100vh * 100 / 50 = 200vh
*/

@media screen and (max-width: 200vh) {
  .wrapper {
      width: 100vw;
      height: 50vw;
  }
}
@media screen and (min-width: 200vh) {
  .wrapper {
      width: 200vh;
      height: 100vh;
  }
}

.img {
/*   padding-top: 50%; */
  width: 100%;
  height: 100%;
  background: #ccc;
  text-align: center;
  background-img: url()
}
<div class="wrapper">

  <div class="img">
    **IMG HERE**
  </div>
  
</div>

Update: min - max width queries

Grenther
  • 476
  • 3
  • 10
  • This is the effect I already have. In the example you gave the div.img will only resize when scaled horizontally but not vertically. – William Larsen Bang Jul 25 '18 at 05:18
  • @WilliamLarsenBang I've updated the answer. Hopefully this will achieve what you're after ;) – Grenther Jul 25 '18 at 08:09
  • Hey, this is a really cool trick, and thanks for writing back :) This, however, limits the maximum size the div can achieve. So if the div was very wide it wouldn't stretch to it's full size. – William Larsen Bang Jul 25 '18 at 09:14
  • What do you mean? if you set width: 100vw/vh it's the width of the full page. Let's say you have a 2:1 aspect ratio and you want it to span the full width no matter what, whilst being fully visible in your viewport. You'd do `width:100vh; height:50vh;` and in portrait `width:100vw; height:50vw;`. I mean unless you want it to allow to be bigger than the viewport. – Grenther Jul 25 '18 at 09:35
  • I've tried doing that here: https://codepen.io/william-bang/pen/ZjyWRd, but the box does not stretch fully. Because the width in landscape orientation is limited by the vertical height of the window (vh). – William Larsen Bang Jul 25 '18 at 10:02
  • @WilliamLarsenBang I've made another edit, you have to calculate it depending on the width and height but it should be usable. – Grenther Jul 25 '18 at 11:55
  • I have to hand it to you @Grenther, this is aweomse. I've used your code and i've set a max width of 400 and height 200 and it works perfectly. But I don't understand the math with the vh. So when I change my div ratio, it goes bad. I've created a fiddle, can you please use my sass vars and weave it into you vh code using math, so i can see how you've worked the vh sizes? https://jsfiddle.net/joshmoto/832v5f0L/ – joshmoto Jul 25 '18 at 13:17
  • @Grenther Thanks for your response, I tried modifying the answer you gave to do it purely in CSS and not having to use a CSS preprocessor. That went really well until I realized that CSS media queries do not support standard CSS variables, otherwise the method you proposed would have been possible without SCSS but perhaps you already knew that. You can se my updated post. – William Larsen Bang Jul 26 '18 at 08:07
  • Yeah, css variables have some limits. "The var() function can be used in place of any part of a value in any property on an element. The var() function can not be used as property names, selectors, or anything else besides property values. (Doing so usually produces invalid syntax, or else a value whose meaning has no connection to the variable.)" I'd suggest marking it as answered and call it a day @WilliamLarsenBang – Grenther Jul 26 '18 at 12:30
1

See the below code snippet. As you adjust the wrapper width, the img will scale to fit while maintaining it's aspect ratio

The img will also be vertically centered and horizontally within the .wrapper element

* {
  box-sizing:border-box;
}

html,
body {
  width: 100%;
  height: 100%;
}

.wrapper {
  width: 50%;
  height: 100%;
  margin: auto;
  position: relative;
}

.img {
  max-width: 100%;
  max-height: 100%;
  padding:20px 40px;
  background:grey;
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: fit-content;
  width: fit-content;
  margin: auto;
  transform: translateY(-50%);
}

.img img {
  max-width: 100%;
  height: auto;
  max-height: 100%;
}
<div class="wrapper">
  <div class="img">
    <img src="https://cdn.pixabay.com/photo/2013/01/29/00/47/search-engine-76519_960_720.png">
  </div>
</div>
Rylee
  • 1,481
  • 1
  • 6
  • 9
  • Yes, I have achieved the effect with an img tag, but I am looking for a div solution only. If there was some way of parenting a div underneath a img that would be great, but this does not solve my issue. Thanks for the help though :) – William Larsen Bang Jul 25 '18 at 05:20
  • @WilliamLarsenBang I've edited the example using a `transform` property. Not personally a fan of using it, but the updated example should solve your issues with css – Rylee Jul 26 '18 at 04:44
  • Note: this only applies when the div has children. Otherwise it has nothing to scale it's width to – Rylee Jul 26 '18 at 04:51
  • Sorry, I did not try out the code properly I did not know there was a method of Height called "fit-content" That is pretty ingenious. – William Larsen Bang Jul 26 '18 at 06:26
0

This is a great question, I've been trying for ages to solve but getting it to resize on a vertical height with out using flex was proving a hard task.

But @Grenther answer seems to actually work without using an image. His 1x2 ratio div stays true when adjusting the window width and height.

I then modified his code so that there is a max-height and max-width on the div. I could only get this to work with his 200px x 400px ratio.

It would be awesome if @Grenther could update my jsfiddle code so what ever div size/ratio variable is set, his clever vh method sizes would adjust using sass math so that any set div size would work. Even I'm struggling to see how his version works. But if the math is in the sass code for each vh dimension, we might be able to understand his wizardry.

@Grenther version here: https://jsfiddle.net/joshmoto/jndmoz6v/

 /* div size vars and div ratio3 */
 $div-width : 400;
 $div-height : 200;

 body {
  width: 100%;
  height: 100%;
}

.ratio {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  /* set your div max-size here  */
  max-width: $div-width + px;
  max-height: $div-height + px;

  @media screen and (max-width: 200vh) {
    width: 100vw;
    height: 50vw;

  }

  @media screen and (min-width: 200vh) {
    width: 200vh;
    height: 100vh;

  }

}

.div {
  width: 100%;
  height: 100%;
  background: red;
  text-align: center;

}

I know this is not sass question, but i'm just using this so we can see @Grenther's answer logic.


I tried the math myself but when I change the div sizes/ratio it does not work like his version.

See my fail: https://jsfiddle.net/joshmoto/Lkebpyws/

$div-width : 400;
$div-height : 200;

.ratio {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  /* set your div max-size here  */
  max-width: $div-width + px;
  max-height: $div-height + px;

  @media screen and (max-width: $div-height + 'vh') {
    width: ($div-width / 4) + vw;
    height: ($div-height / 4) + vw;

  }

  @media screen and (min-width: $div-height + 'vh') {
    width: ($div-width / 2) + vh;
    height: ($div-height / 2) + vh;

  }

}

...
joshmoto
  • 4,472
  • 1
  • 26
  • 45
  • My final update should provide a sufficient solution, please see my updated answer. (I did leave the max-height and max-width commented, but it works well even if you don't) – Grenther Jul 25 '18 at 22:22