What is the best way to ensure a canvas fits perfectly inside a div without distorting its aspect ratio?

I am facing a challenge with a canvas element placed inside a flexbox that can be resized. My goal is to have the canvas fill the available space while maintaining its aspect ratio (2/3) and without getting cut off.

(I prefer adjusting the CSS dimensions rather than the canvas resolution).

I've experimented with object-fit: contain and clamp(...), but haven't achieved the desired outcome. The canvas either loses its aspect ratio or extends beyond its container.

body{
  margin:0;
}

#mainContent {
    background:grey; 
    height:100vh; 
    display:flex; 
    flex-wrap:nowrap; 
    align-items:center;
}

#someOtherElem {
    background:red; 
    width:200px; 
    height:200px;
    margin-left:1rem;
}

#canvasContainer {
    display:flex; 
    flex:1; 
    height:100%; 
    justify-content:center; 
    align-items:center;
}

canvas {
    width:calc(100%-2rem); 
    height:calc(100%-2rem); 
    background:green; 
    object-fit:contain;
}
<div id="mainContent">
  <div id="someOtherElem"></div>
  <div id="canvasContainer">
    <canvas height="300" width="200"></canvas>
  </div>
</div>

Here's a simplified version of my attempts: https://jsfiddle.net/mwq4502v/.

I'm unsure about the best approach to achieve this, so any guidance would be highly appreciated!

Answer №1

You have the option to set an aspect-ratio of 2 / 3 for a canvas element, with a width of either 100% or <parent-height> * 2 / 3, whichever is smaller.

canvas {
  aspect-ratio: 2 / 3;
  width: min(100%, 100vh * 2 / 3);
  /* ...or height: min(100%, calc(100vw - 210px) * 3 / 2). Same concept. */
}

Here's some mathematical reasoning:

If we define the width and height of the container as w and h, respectively, the canvas should touch at least two borders (if not all four) in order to maximize its size. This means the canvas size would be either w / (w / (2 / 3)) or (h * 2 / 3) / h, depending on the container size.

w / h > 2 / 3:

◄────── w ──────►
┌────────┬─────┬────────┐ ▲
│        │     │        │ │
│        │     │        │ │
│        │     │        │ │
│        │     │        │ h
│        │     │        │ │
│        │     │        │ │
│        │     │        │ │
└────────┴─────┴────────┘ ▼
   ◄ (h*2/3) ►

w / h < 2 / 3:

       ◄─── w ───►
       ┌───────┐ ▲
       │       │ │
     ▲ ├───────┤ │
     │ │       │ │
     │ │       │ │
(w*3/2)│       │ h
     │ │       │ │
     │ │       │ │
     ▼ ├───────┤ │
       │       │ │
       └───────┘ ▼

This implies that the width should be min(w, h * 2 / 3) or, in CSS terms, min(100%, 100vh * 2 / 3).

Feel free to experiment with this setup:

canvas {
  aspect-ratio: 2 / 3;
  width: min(100%, 100vh * 2 / 3);
}

/* Demo purpose only */

#canvasContainer {
  outline: 1px solid #000; /* Marking the area */
}

body {
  margin: 0;
}

#mainContent {
  display: flex;
  align-items: center;
  height: 100vh;
}

#someOtherElem {
  margin-left: 1rem;
  width: 200px;
  height: 200px;
  background: red;
}

#canvasContainer {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

canvas {
  background: green;
}
<div id="mainContent">
  <div id="someOtherElem"></div>
  <div id="canvasContainer">
    <canvas></canvas>
  </div>
</div>

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

PHP-powered image gallery system with a robust search engine

My current project involves creating an image gallery system that is keyword-driven. For each image, there is a corresponding .php file containing the following variables: $keywords = 'Keywords that describe the image'; $src = 'dir ...

Having issues with custom CSS functioning properly on WordPress sites

I have a customized section on my WordPress page with specific CSS and HTML. You can view the code here: Upon hovering over the image, the code is designed to display a semi-transparent background. However, when I implement this code onto my WordPress si ...

Restricting Options in jQuery/ajax选择列表

Although there are similar questions posted, my specific issue is that I am unsure of where to place certain information. My goal is to restrict the number of items fetched from a list within the script provided below. The actual script functions correct ...

Unlocking the full potential of Bootstrap with the colspan feature

I'm currently in the process of developing an Angular 2 and Bootstrap application. Here's a snippet of my code: <div class="panel-body"> <table class="table table-striped table-bordered" style="width:100%;"> < ...

When hovering over a select element within a grid-area that has overflow set to scroll, Safari unexpectedly jumps to the

Encountering a strange issue that I can't seem to figure out. When testing the code in Safari, hovering over the select field causes the .page div to scroll to the top. This behavior only occurs when .page is within a grid layout and there's a s ...

Responsive design causing images to be invisible in Internet Explorer

Hey there! I have a live website (check it out here, although it's currently behind a "coming soon" cover). The site has two stylesheets: one for regular styles (style.css) and one specifically for responsive design (width.css). The responsive stylesh ...

Tips for updating the class of a button upon clicking it

I have a dilemma with my two buttons - one is green and the other has no background. I want them to change appearance when clicked, from green to one with a dashed border-bottom style. Below is the HTML code for these buttons: <div class="btns"> ...

Enhance your Material UI Button with Advanced Text Alignment Options for Compact Screens

As a beginner in React and Material-UI, I'm attempting to customize a set of buttons within my app bar with background images for a cleaner look. Drawing inspiration from various online examples, I've managed to style them to my liking on larger ...

Struggling to incorporate a basic drop-down into my design despite implementing transitions

Looking to optimize space on a webpage, I am interested in creating a hover effect for topics that reveals sub-topics with a smooth ease-out animation. Here is an example of the effect I am aiming for: https://jsfiddle.net/170z6pj1/ I have been strugglin ...

Swap the displayed text in a textbox within an HTML5 document

Is there a way to replace specific text in an HTML5 document? Let's say the user inputs: My name is Toni. I want to change the output text "Toni" to Ani, so the final output is: "My name is Ani". This is the current code I have: <title>tex ...

Adjust the class based on the number of li elements

When there are more than two (li) tags, the ul tag should have the class "col_3"; otherwise it should have the class "col_2" For instance: If there are two columns <div class="container"> <ul class="col_2"> <li>One</li> ...

Set the button to align on the left side within a Bootstrap card

Creating grid elements in Bootstrap 3, I am faced with a challenge. When the viewport is below <768px, I want to align a button in the same position as shown in the image with the lion. Check out the demo site here. For viewports >768px, the button ...

Incorporate JSON and JavaScript into your website template

Currently, I am in the process of developing my online resume using a free template that I found and downloaded. The template incorporates bootstrap and showcases a progress bar indicating my skills. However, I want to take it a step further by dynamically ...

Displaying incorrect results within the div container

I have been developing a website where a div element on a specific page displays values from a PHP file. Below is the PHP code responsible for rendering the information on the HTML: $output .= ' <div class="row text-left col-md-3 ...

The CSS3 transition is not functioning correctly when transitioning element dimensions from a percentage or auto value to a specific pixel

As part of my project, I am developing a single-page website that features a vector graphic occupying 80% of the screen width on the initial 'start screen'. Once the user scrolls down, the graphic smoothly transitions into a navigation bar positi ...

Position a button and input element in alignment

I recently decided to challenge myself by recreating the Netflix registration page as a practice project. Using the flexbox model on the webpage, I encountered an issue with aligning the email input and the "Get Started" button. Despite trying different me ...

Running a shell script on a website should always be done in a single instance

When I use html/php to call a bash script on a website, I have multiple html-buttons that initiate the same script with different arguments. The issue arises when each button click opens a new instance of the script. Is there a way to somehow resume the r ...

The request to "http:192.200.2.2/example.com/api/value" resulted in a 405 (Method Not Allowed) error, and the response for prelight included an invalid HTTP status code of 405

Is there a way to call an API from an HTML page using AngularJS? I have written the following script in my HTML page: $http({ method:'POST', url:'http:192.200.2.2/example.com/api/value', headers:{ X-EXAMPLE.COM-WEB- ...

Angular Appreciation Meter

Looking to create a rating system using Angular. The square should turn green if there are more likes than dislikes, and red vice versa (check out the stackblitz link for reference). Check it out here: View demo I've tried debugging my code with con ...

What steps can I take to ensure that a JavaScript function does not execute when a DOM element from an array has already been chosen?

I am facing an issue with a script that dynamically changes the header based on the selected bubble in an array. The problem arises when the user clicks on the same bubble that is already selected, causing the JavaScript function to run and temporarily cha ...