How does object-fit work with canvas element?

Solution 1:

object-fit1 will only have an effect when there is a ratio change (a distortion) and applies to only replaced element (canvas is a replaced element)

Here is a basic example:

var canvas = document.querySelectorAll("canvas");
for (var i = 0; i < canvas.length; i++) {
  ctx = canvas[i].getContext("2d");
  ctx.fillRect(50, 50, 100, 100);
}
canvas {
  width: 100px;
  height: 250px;
  border: 1px solid red;
  display: block;
}

.box {
  display: inline-block;
  border: 2px solid green
}
<div class="box">
  <canvas width="200" height="200"></canvas>
</div>
<div class="box">
  <canvas width="200" height="200" style="object-fit:contain;"></canvas>
</div>
<div class="box">
  <canvas width="200" height="200" style="object-fit:cover;"></canvas>
</div>

As you can see I defined a height/width for the canvas to be 200x200 (1:1 ratio) then I change this using CSS thus I break the ratio (we no more have a square) then object-fit will correct this.

A related question to understand the difference between setting width/height using attribute and using CSS: Why box-sizing is not working with width/height attribute on canvas element?


1From the specification we can clearly read that all the values (expect the default one fill) will try to maintain the ratio:

contain

The replaced content is sized to maintain its aspect ratio while fitting within the element’s content box: its concrete object size is resolved as a contain constraint against the element’s used width and height.

cover

The replaced content is sized to maintain its aspect ratio while filling the element’s entire content box: its concrete object size is resolved as a cover constraint against the element’s used width and height.

none

The replaced content is not resized to fit inside the element’s content box: determine the object’s concrete object size using the default sizing algorithm with no specified size, and a default object size equal to the replaced element’s used width and height.

The none value is a bit tricky but it basically mean keep the intrinsic default image size without scaling like contain or cover

var canvas = document.querySelectorAll("canvas");
for (var i = 0; i < canvas.length; i++) {
  ctx = canvas[i].getContext("2d");
  ctx.fillRect(50, 50, 100, 100);
}
.box canvas {
  border: 1px solid red;
  display: block;
  object-fit:none;
}

.box {
  display: inline-block;
  border: 2px solid green
}
<canvas width="200" height="200"></canvas>
<div class="box">
  <canvas width="200" height="200" style="width:100px;height:200px;"></canvas>
</div>
<div class="box">
  <canvas width="200" height="200" style="height:50px;width:200px;"></canvas>
</div>

Related: CSS object-fit: contain; is keeping original image width in layout