我有一个基于CSS网格UI的Web应用程序。在其中一个网格部分中,有一个可折叠的侧面板和一个我想始终调整其大小以填充剩余空间的画布元素。画布会更新每帧,因此我将canvas.width
设置为每帧包装div的clientWidth
。
当面板折叠时,画布会适当地扩展以填充空间,但是当再次打开面板时,画布不会收缩,而是从页面上溢出。我有一些关于为什么会发生这种情况的理论,例如,包装画布div扩展后,包装div拒绝收缩,但是我不知道该如何解决这个问题。
这里是问题的简单模型:
<meta charset="utf-8" />
<script>
let open = true;
window.onload = () => {
let canvas = document.getElementById("canvas");
canvasUpdate(canvas);
}
function canvasUpdate(canvas){
let ctx = canvas.getContext("2d");
canvas.width = document.getElementById("canvasWrapper").clientWidth;
canvas.height = document.getElementById("canvasWrapper").clientHeight;
ctx.fillStyle = "gray";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 50, 50);
ctx.fillStyle = "black";
ctx.fillRect(canvas.width - 50, canvas.height - 50, 50, 50);
window.requestAnimationFrame(()=>{canvasUpdate(canvas)});
}
function togglePanel(){
if (open){
document.getElementById("sidePanel").style.display = "none";
document.getElementById("expandBtn").style.display = "block";
open = false;
}
else{
document.getElementById("sidePanel").style.display = "flex";
document.getElementById("expandBtn").style.display = "none";
open = true;
}
}
</script>
<style>
html, body{
margin: 0;
padding: 0;
}
#gridWrapper{
display: grid;
grid-template-areas:
"header header"
"col1 col2";
grid-template-columns: 100pt 1fr;
grid-template-rows: 50pt minmax(0, 1fr);
width: 100%;
height: 100%;
}
#header{
grid-area: header;
background: #AAFFAA;
}
#col1{
grid-area: col1;
background: #FFAAAA;
}
#col2{
grid-area: col2;
display: flex;
flex-direction: row;
}
#sidePanel{
display: flex;
flex-direction: row;
height: 100%;
}
#expandBtn{
display: none;
height: 100%;
}
#canvasWrapper{
width: 100%;
height: 100%;
}
</style>
<body>
<div id="gridWrapper">
<div id="header">
Header contents
</div>
<div id="col1">
Col1 contents
</div>
<div id="col2">
<div id="sidePanel">
<div id="panelContents">
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
</div>
<button id="collapseBtn" onclick="togglePanel()">
<
</button>
</div>
<button id="expandBtn" onclick="togglePanel()">
>
</button>
<div id="canvasWrapper">
<canvas id="canvas">
//Error loading canvas
</canvas>
</div>
</div>
</div>
</body>
如果我设置了网格的overflow = hidden
,它解决了页面运行的问题,但是画布仍保持扩展宽度。
我知道了。无论您设置了什么CSS设置,似乎块级元素都不会缩小到画布元素以下,但是值得庆幸的是,我找到了一种解决方法,将画布w / h临时设置为1,然后获取并存储尺寸包装材料,最后将画布设置为存储的尺寸。
let wrapperBounds = {width:0,height:0};
canvas.width = 1;
canvas.height = 1;
wrapperBounds.width = document.getElementById("canvasWrapper").clientWidth;
wrapperBounds.height = document.getElementById("canvasWrapper").clientHeight;
canvas.width = wrapperBounds.width;
canvas.height = wrapperBounds.height;
我本来不认为这行得通,因为我认为自动宽度是在生命周期中与requestAnimationFrame()
的不同点计算出来的,但是显然CSS是在更改后立即计算出来的。
完整代码实施:
<meta charset="utf-8" />
<script>
let open = true;
window.onload = () => {
let canvas = document.getElementById("canvas");
canvasUpdate(canvas);
}
function canvasUpdate(canvas){
let ctx = canvas.getContext("2d");
let wrapperBounds = {width:0,height:0};
canvas.width = 1;
canvas.height = 1;
wrapperBounds.width = document.getElementById("canvasWrapper").clientWidth;
wrapperBounds.height = document.getElementById("canvasWrapper").clientHeight;
canvas.width = wrapperBounds.width;
canvas.height = wrapperBounds.height;
ctx.fillStyle = "gray";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 50, 50);
ctx.fillStyle = "black";
ctx.fillRect(canvas.width - 50, canvas.height - 50, 50, 50);
window.requestAnimationFrame(()=>{canvasUpdate(canvas)});
}
function togglePanel(){
if (open){
document.getElementById("sidePanel").style.display = "none";
document.getElementById("expandBtn").style.display = "block";
open = false;
}
else{
document.getElementById("sidePanel").style.display = "flex";
document.getElementById("expandBtn").style.display = "none";
open = true;
}
}
</script>
<style>
html, body{
margin: 0;
padding: 0;
}
#gridWrapper{
display: grid;
grid-template-areas:
"header header"
"col1 col2";
grid-template-columns: 100pt 1fr;
grid-template-rows: 50pt minmax(0, 1fr);
width: 100%;
height: 100%;
}
#header{
grid-area: header;
background: #AAFFAA;
}
#col1{
grid-area: col1;
background: #FFAAAA;
}
#col2{
grid-area: col2;
display: flex;
flex-direction: row;
}
#sidePanel{
display: flex;
flex-direction: row;
height: 100%;
}
#expandBtn{
display: none;
height: 100%;
}
#canvasWrapper{
width: 100%;
height: 100%;
}
</style>
<body>
<div id="gridWrapper">
<div id="header">
Header contents
</div>
<div id="col1">
Col1 contents
</div>
<div id="col2">
<div id="sidePanel">
<div id="panelContents">
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
<div class="contents">Contents</div>
</div>
<button id="collapseBtn" onclick="togglePanel()">
<
</button>
</div>
<button id="expandBtn" onclick="togglePanel()">
>
</button>
<div id="canvasWrapper">
<canvas id="canvas">
//Error loading canvas
</canvas>
</div>
</div>
</div>
</body>