None of the answers I've looked up quite works for my use case.
I want to fix the aspect ratio of a HTML element on my page (specifically, a canvas which I want to always be square) in such a way that
- it's as large as fits in the alloted space;
- it fits inside the browser window without scrolling.
I don't think this can be done by CSS alone (please prove me wrong). I did find various CSS tricks purported to do it, but they take into account only either the available width or the available height, not both.
I tried javascript that looks up the size (.parentElement.clientWidth
and .parentElement.clientHeight
) of the parent element, finds the smaller one and sizes the canvas according to that by setting canvas.style.width
and canvas.style.height
, but for some reason I don't understand this doesn't work - the canvas ends up too small and only resizes to the correct setting on a window resize. In this case, the parent element's size was determined by flexbox.
EDIT: the following code does almost what I am looking for. There is only one problem, which you can observe by:
- loading the page in a non-maximed window
- maximizing and un-maximizing that window.
The resulting layout is not the same as the original (directly after the load).
<!DOCTYPE html>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
margin: 0;
background: #404040;
height: 100vh;
min-width: 800px;
display: flex;
justify-content: center;
align-items: stretch;
}
main {
background: yellow;
flex: 0 1 100vh;
display: flex;
flex-direction: column;
}
.sidepanel {
background: blue;
flex: 0.2 0.4 250px;
text-align: center;
}
.spacer {
flex: 0.5 1 0;
}
#square {
background: black;
margin: auto;
}
</style>
<script type="module">
const canvas = document.querySelector('#square')
const parent = canvas.parentElement
const setSquare = () => {
const { clientWidth, clientHeight } = parent
const L = Math.min(clientWidth, clientHeight)
canvas.style.width = canvas.style.height = `${L}px`
}
window.addEventListener('resize', setSquare)
setSquare()
</script>
<div class="spacer"></div>
<section class="sidepanel">
</section>
<main>
<canvas id="square"></canvas>
</main>
<section class="sidepanel">
</section>
<div class="spacer"></div>