skip to Main Content

I try to fit a square into a rectangle. I used max-width, max-height and aspect-ratio, but it works only in portrait mode and fails in landscape mode. This shows how Firefox renders it:

works fails

This is the example.

function portrait() {
  document.body.style.width = "10em";
  document.body.style.height = "14em";
}

function landscape() {
  document.body.style.width = "14em";
  document.body.style.height = "10em";
}

document.getElementById("button0").addEventListener('click', portrait);
document.getElementById("button1").addEventListener('click', landscape);

portrait();
html, body {
  margin: 0;
}
#page {
  height: 100%;
  box-sizing: border-box;
  border: 1ex solid blue;
  display: grid;
  grid-template-rows: auto min-content;
}
.square {
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 1 / 1;
}
canvas {
  box-sizing: border-box;
  border: 1ex solid red;
  display: block;
  width: 100%;
  height: 100%;
}
.buttons {
  box-sizing: border-box;
  border: 1ex solid green;
  width: 100%;
}
<div id="page">
  <div class="square">
    <canvas width="100" height="100">
    </canvas>
  </div>
  <div class="buttons">
    <input id="button0" type="button" value="Works"/>
    <input id="button1" type="button" value="Fails"/>
  </div>
</div>

How to fit the red and green boxes into the blue box?

2

Answers


  1. I’ve managed to get it to work using container-type. There are nifty container unit called cqmin and cqmax. cqmin is the minimum of the inline and block container size which is handy when the aspect ratio changes. By declaring the square as a container and using the size value rather than inline-size and setting the width of the canvas to be 100cqmin it fills the height or the width of the grid item, depending on what is the smaller container size (because the size value looks at both the block and inline lengths) Thankfully container queries seem to be nearly universally supported.

    function portrait() {
      //I changed these from em to px so I could make sure the body and #page div sizes were as specified.
      document.body.style.width = "250px";
      document.body.style.height = "300px";
    }
    
    function landscape() {
      document.body.style.width = "300px";
      document.body.style.height = "250px";
    }
    
    document.getElementById("button0").addEventListener('click', portrait);
    document.getElementById("button1").addEventListener('click', landscape);
    
    portrait();
    * {
      box-sizing: border-box;
    }
    
    html, body {
      margin: 0;
    }
    
    #page {
      height: 100%;
      border: 1ex solid blue;
      display:grid;
      grid-template-rows: 1fr auto;
    }
    
    .square {
      container-type: size; /* make it size and not inline-size so the units work for both inline and block dimensions */
    }
    
    canvas {
      border: 1ex solid red;
      display: block;
      width: 100cqmin; /* this is the secret sauce */
      aspect-ratio: 1/1;
    }
    
    .buttons {
      border: 1ex solid green;
      width: 100%;
    }
    <div id="page">
      <div class="square">
       <canvas width="100" height="100"></canvas>
      </div>
      <div class="buttons">
        <input id="button0" type="button" value="Works"/>
        <input id="button1" type="button" value="Works!!!!"/>
      </div>
    </div>
    Login or Signup to reply.
  2. Try using orientation and @container rule!
    MDN Documentation

    Note: If you want to do it by real page size change the @container to @media

    function portrait() {
      document.body.style.width = "10em";
      document.body.style.height = "14em";
    }
    
    function landscape() {
      document.body.style.width = "14em";
      document.body.style.height = "10em";
    }
    
    document.getElementById("button0").addEventListener('click', portrait);
    document.getElementById("button1").addEventListener('click', landscape);
    
    portrait();
    html, body {
      margin: 0;
    }
    #page {
      height: 100%;
      box-sizing: border-box;
      border: 1ex solid blue;
      display: block;
      container-type: size;
    }
    #wrapper {
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      height: 100%;
    }
    .square {
      aspect-ratio: 1 / 1;
    }
    @container (orientation: landscape) {
    .square {
      flex: 1;
      margin: auto;
      }
    }
    
    @container (orientation: portrait) {
    .square {
       width: 100%;
      }
    }
    canvas {
      box-sizing: border-box;
      border: 1ex solid red;
      display: block;
      width: 100%;
      height: 100%;
    }
    .buttons {
      box-sizing: border-box;
      border: 1ex solid green;
      width: 100%;
    }
    <div id="page">
      <div id="wrapper">
        <div class="square">
          <canvas>
          </canvas>
        </div>
        <div class="buttons">
          <input id="button0" type="button" value="Works"/>
          <input id="button1" type="button" value="Fails"/>
        </div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search