为什么 box-sizing 不适用于画布元素上的宽度/高度属性?

2022-01-17 00:00:00 html css html5-canvas

让我们考虑一下这段代码:

Let's consider this code:

.canvas {
  width:150px;
  height:150px;
}
canvas {
  box-sizing:border-box;
  border:5px solid;
}

<canvas height="150" width="150"></canvas>
<canvas class="canvas"></canvas>

我们定义了两个 canvas,它们具有相同的宽度/高度、相同的边框和 box-sizing:border-box.我们可以清楚地看到,我们使用 CSS 属性的画布尊重 box-sizing (边框从宽度/高度减小)但第一个使用属性定义的画布忽略了 box-sizing(边框添加到宽度/高度).

We have two canvas defined with the same width/height, same border and box-sizing:border-box. We can clearly see that the canvas where we used CSS properties is respecting the box-sizing (borders are reduced from the width/height) but the first one defined with attribute is ignoring box-sizing (borders are added to width/height).

我最初认为这与属性的使用有关,但在使用 imgiframe 时,它似乎不像预期的那样工作.

I first thought it has to do with the use of attribute but it seems not as it works as intended when using img or iframe.

.canvas {
  width:150px;
  height:150px;
}
iframe,img {
  box-sizing:border-box;
  border:5px solid;
}

<iframe height="150" width="150"></iframe>
<iframe class="canvas"></iframe>

<img height="150" width="150" src="https://picsum.photos/200/300?image=1069">
<img class="canvas" src="https://picsum.photos/200/300?image=1069">

为什么 canvas 元素会出现这种行为?

Why such behavior with canvas element?

经过一番搜索,我发现应该避免在画布上使用宽度/高度属性,因为它会缩放画布并且不会像我们想象的那样调整它的大小.

After some search, I found that using width/height properties with canvas should be avoided as it will scale the canvas and will not resize it like we may think.

var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, 150, 150);

canvas {
  width: 150px;
  height: 150px;
  border:1px solid red;
}

<canvas ></canvas>

直观地说,上面的代码应该生成一个 150x150 正方形,但我们以一个矩形结束!这是因为画布最初是 300x150(默认尺寸),而我们的正方形是在里面绘制的.然后我们像处理图像一样缩放整个思维,得到了不想要的结果.

Intuitively, the above code should produce a 150x150 square but we ended with a rectangle! This is because the canvas was initially 300x150 (default dimension) and our square was drawn inside. Then we scaled the whole think like we do with an image and we obtain the unwanted result.

但是,使用属性将创建所需的结果:

However, using attribute will create the needed result:

var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, 150, 150);

canvas {
  border:1px solid red;
}

<canvas height="150" width="150"></canvas>

这以某种方式解释了为什么浏览器忽略 box-sizing 以避免缩小效果,但它仍然违反直觉,因为它可能导致 canvas<之外的其他不需要的问题/代码>.如果是这个原因,那么浏览器也应该对 img 做同样的事情,因为它们面临同样的收缩效果.

This somehow explain why the browser is ignoring box-sizing in order to avoid the shrink effect but it still remain counter-intuitive as it may lead to other unwanted issues outside the canvas. If this was the reason, then the broswer should also do the same with img because they face the same shrink effect.

那么,为什么会有这样的行为?为什么浏览器决定忽略 box-sizing 而不是缩小画布?

So again, why such behavior? Why the browser decide to ignore the box-sizing instead of shrinking the canvas?

最重要的问题:此类行为在哪里定义?

我无法找到规范的哪一部分正在处理这个问题.

I am not able to find which part of the specification is dealing with this.

推荐答案

我猜是 规范中的这一段.

当其画布上下文模式为无时,画布元素没有渲染上下文,并且其位图必须是完全透明的黑色,其固有宽度等于元素宽度属性的数值,固有高度等于该数值元素的 height 属性,这些值以 CSS 像素解释,并随着属性的设置、更改或删除而更新.

When its canvas context mode is none, a canvas element has no rendering context, and its bitmap must be fully transparent black with an intrinsic width equal to the numeric value of the element’s width attribute and an intrinsic height equal to the numeric value of the element’s height attribute, those values being interpreted in CSS pixels, and being updated as the attributes are set, changed, or removed.

即位图必须取自height和width属性.盒子大小无关紧要.

That is the bitmap must be taken from the height and width attributes. Box-sizing plays no part.

另请注意,HTML5 渲染部分是这样说的:

Note also that the HTML5 rendering section says that:

embed、iframe、img、object 或 video 元素上的 width 和 height 属性,以及在 Image Button 状态下具有 type 属性且代表图像或用户期望最终代表图像的 input 元素,map分别到元素上的维度属性宽度和高度.

The width and height attributes on embed, iframe, img, object or video elements, and input elements with a type attribute in the Image Button state and that either represents an image or that the user expects will eventually represent an image, map to the dimension properties width and height on the element respectively.

那里没有提到画布.

相关文章