Use a canvas to fill up the rest of the viewport space using a combination of flexbox layout and three

I am utilizing three.js to render content onto a canvas. My goal is to have a div element positioned above the canvas and another below it, with the canvas filling the space in between. The total height of these 3 elements should always be 100% of the viewport without exceeding it and causing scrollbars to appear, even if this means adjusting the aspect ratio of the canvas when the viewport size changes.

To illustrate what I am aiming for, here is a gif demonstrating the desired layout:

https://i.sstatic.net/SDsNw.gif

I initially thought that using flexbox would solve this layout challenge, but my attempts have not been successful. Scrollbars keep appearing or the bottom element ends up outside the viewport. You can see one of my attempts by running the code snippet in full page mode:

// JavaScript code
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
const scene = new THREE.Scene();
// More code...
// CSS code
html, body {
  height: 100%;
  margin: 0;
}
// More code...
<div class="container">
  <div class="top">Top</div>
  <div class="middle">
    <canvas></canvas>
  </div>
  <div class="bottom">Bottom</div>
</div>
// More HTML code...

If you change the flex-direction to row, you'll notice that the layout works horizontally as intended. However, my goal is to achieve the same result vertically. Is there a way to make this happen?

Answer №1

Discovered the solution here. When the flex-direction is set to column, ensure that the min-height of the middle element is specified as zero.

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;
}
html, body {
  height: 100%;
  margin: 0;
}

.container {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

.top, .bottom {
  padding: 10px;
}

.middle {
  flex: 1;
  min-height: 0;
}

.middle canvas {
  width: 100%;
  height: 100%;
  display: block;
}
<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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c5a0b6e8a8aaa1b0a9a0e8b6adaca8b685f4ebf3ebf6">[email protected]</a>/dist/es-module-shims.js"></script>
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f08498829595b086c0dec1c5c5dec0">[email protected]</a>/build/three.module.js",
      "three/addons/": "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="becad6ccdbdbfec88e908f8b8b908e">[email protected]</a>/examples/jsm/"
    }
  }
</script>
<script type="module">
  import * as THREE from 'three';
  window.THREE = THREE;
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Shape with a dark border div

Having some trouble with creating this particular shape using CSS border classes. If anyone can assist in making this black box shape using Jquery, it would be greatly appreciated. Check out the image here. ...

pictures aren't showing up on the website once they've been uploaded to the server

While creating a landing page, I encountered an issue where it displayed three specific images when tested locally on my computer, but not when uploaded to the host server. Even after re-uploading the images and trying different browsers like Chrome and S ...

Is there a way to eliminate gaps between containers?

Is it possible to specify a custom width or height for the container when using Bootstrap without affecting its default responsiveness? My main concern is how to eliminate the space below the content in the Bootstrap container. Here's a screenshot scr ...

Store <td> in a variable

At the moment, I have a script that allows users to input an item name, along with its size, color, and other options. Each of these entries is saved as individual items with their custom specifications, such as a black t-shirt in large size. The script c ...

Is there a way to add a clickable icon to a form-floating label in Bootstrap 5?

I'm having trouble getting a clickable icon to work properly in a form-floating label. It seems that the label is being rendered behind the input field. I've tried adjusting the z-index with no success, and I'm not sure what else to try to ...

Manipulate objects in three.js to always face the mouse pointer

It seems that despite my efforts, I am struggling with this task as I am relatively new to it. Surprisingly, I am not getting any errors in Dreamweaver. I've started fresh by integrating the look at function with the OBJ loader, camera, and lights in ...

I am interested in developing a select box with autocomplete functionality

Here is the HTML code I have: <select class="form-control" id="city" style="width:100%; margin-left:2%;"> <option>Sonal</option> <option>abcd</option> <option>3</option> <option& ...

How can I adjust the scale of the Flex Grid to fit within

I'm currently working on setting up a dynamic gallery. The number of items in the gallery will vary, and I want them to adjust to fit the browser viewport. It seems like it should be a straightforward task? My current DOM structure is as follows: < ...

Unpacking Django's request processing: Understanding the logic behind choosing one URL pattern over another

Currently enrolled in a free online Django course and faced with a perplexing issue related to request processing in Django. The application I am working on consists of a single module with two pages that inherit from a layout template - an index page with ...

How to set a maximum width in IE8 when using width:100%?

After researching online, I am still unable to get it to work. I have a basic HTML layout that I have been testing across different browsers. Knowing the quirks of IE, I wasn't surprised when the max-width CSS code didn't function as expected. Ho ...

The div's style property now includes Tailwind Width set at 0px

Currently, I am developing a web application with Next.JS and Tailwind CSS for styling. In this project, I need to map over some "accords" related to perfumes and assign variable widths to each one based on the size property of the accord, which is a strin ...

Fluid Cursor Movement in the Atom Text Editor

I encountered an issue where adding a smooth caret animation in the atom editor caused the background to start blinking uncontrollably. Below is the code snippet I used to add the animation in my style.less file: atom-text-editor .cursor { transition: ...

Display an element that has been tucked away, and then bring it to life

Is there a way to implement an animation that causes the hidden form to slide from right to left after the .button class is hidden? I have been able to achieve similar effects individually, but struggle with synchronizing their animations. When the butt ...

Users are reporting a problem with the PrimeNG confirmation dialog where it becomes unresponsive and locks up the screen

Previously functioning code seems to have been affected by an update to PrimeNG. The confirmation dialog that was once usable is now hidden behind a gray click-mask, rendering everything on the screen unclickable: https://i.sstatic.net/YN7Iu.png The HTML ...

Steps for showing an alert notification when the form field is empty

Within my script, there is a Bootstrap form where I am facing an issue. If the user fails to select a language and leaves the value blank or as "Select Language," I want to display an alert message prompting them to choose a language before proceeding to t ...

What is the best way to resize an image within a div that is contained within a grid layout?

I'm currently working with a grid layout. I utilized grid-template-columns and grid-template-rows to outline its structure. My aim is for the first cell to feature an image. To horizontally center it, my plan was to enclose it within a div that can ac ...

What is the process for forming an object from points so that it can be easily integrated into a graphical user interface (GUI)?

I have been following Bruno Simons' Three.js tutorial on Mixing Html with WebGl, specifically the part where you try to attach a text box to a 3D model. I have imported the GUI and set it up, but I am struggling to understand what I need to 'gui. ...

Why isn't the image showing up as a list style?

I can't seem to get the image to show up on my page. Can anyone help me figure out what's wrong? ul li { background-image: url(logo.png); background-repeat: no-repeat; padding-left: 0px; } This is what I'm currently seeing: This is what ...

Getting the badge value of a button in Angular JS is a simple process that involves accessing

How can I retrieve the badge value of a Button? This badge represents data-text-as-pseudo-element and I am new to Angular. Can someone guide me on how to achieve this? <style type="text/css">[data-text-as-pseudo-element]::before { content: ...

Item on the menu has been pushed lower in the list

There seems to be an issue with the layout of my menu as one item is displaying lower than the others without any clear reason. <html> <head> <title> My Website Homepage </title> </head> <body> ...