如何用Flexbox+Three.js让Canvas填充视口垂直剩余空间
问题描述
我正在使用Three.js渲染Canvas,希望在Canvas上方和下方各放置一个<div>,让Canvas填充两者之间的剩余空间(视口尺寸变化时Canvas比例改变也可)。三个元素需始终占满100%视口,且不超出视口产生滚动条。
我本以为这是简单的Flexbox布局,但尝试后要么出现滚动条,要么底部元素被推出视口。奇怪的是,将flex-direction改为row时,横向布局能正常实现需求,我想实现垂直方向的同样效果,是否可行?
解决方案
垂直方向的Flex布局完全可以实现需求,问题出在两个容易忽略的细节:
- 用
100vh替代100%定义视口高度,避免DOM继承链的高度计算偏差导致溢出 - 给Canvas所在的
.middle容器添加overflow: hidden,防止Canvas默认固定尺寸撑开布局
修正后的完整代码
HTML
<div class="container"> <div class="top">Top</div> <div class="middle"> <canvas></canvas> </div> <div class="bottom">Bottom</div> </div> <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@v0.155.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@v0.155.0/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; window.THREE = THREE; </script>
CSS
html, body { min-height: 100vh; margin: 0; overflow: hidden; } .container { display: flex; flex-direction: column; width: 100%; min-height: 100vh; } .top, .bottom { padding: 10px; } .middle { flex: 1; overflow: hidden; } .middle canvas { width: 100%; height: 100%; display: block; }
JavaScript
const canvas = document.querySelector('canvas'); const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(); camera.position.z = 5; const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: '#ff0000' }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); requestAnimationFrame(render); function render() { cube.rotation.x += 0.01; cube.rotation.y += 0.01; if (resizeRendererToDisplaySize(renderer)) { camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(); } renderer.render(scene, camera); requestAnimationFrame(render); } function resizeRendererToDisplaySize(renderer) { const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width || canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize; }
内容的提问来源于stack exchange,提问作者XåpplI'-I0llwlg'I -
相关产品推荐
相关产品推荐

