Search code examples
csshtmlhtml5-canvasobject-fit

How does object-fit work with canvas element?


I have been unable to find any documentation to tell me one way or another.

Am I able to use object-fit cover on a canvas elements? I have done some experimenting and it is not behaving as expected.

Can somebody give me a definitive answer?


Solution

  • 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