为什么box-sizing无法在canvas元素上使用width / height属性?

时间:2018-12-01 23:21:55

标签: html css html5 html5-canvas

让我们考虑以下代码:

.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(边界被添加到width /高度)。

我首先认为它与属性的使用有关,但似乎与使用imgiframe时的效果不一样。

.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元素的这种行为?


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

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(默认尺寸),而正方形是在内部绘制的。然后我们像对图像一样缩放整个思维,并获得不需要的结果。

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

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执行相同的操作,因为它们面临相同的收缩效果。

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

最重要的问题:在哪里定义了这种行为?

我找不到规范的哪一部分正在处理此问题。

2 个答案:

答案 0 :(得分:3)

我猜是this paragraph from the spec

  

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

这是位图,必须从height和width属性中获取。大小调整不起作用。

还请注意,HTML5呈现部分指出:

  

嵌入,iframe,img,对象或视频元素上的width和height属性以及在Image Button状态下具有type属性的输入元素,它们要么表示图像,要么用户期望最终表示图像,地图分别设置为元素的尺寸属性的宽度和高度。

那里没有提到帆布。

答案 1 :(得分:1)

intrinsic width and height由其widthheight属性设置。
这些default to 300 and 150 respectively

对于,这些将取决于所加载的资源,但是对于光栅图像,它非常简单地将使用介质中定义的图像。

因此,要使案例与您的案例相似,实际上您必须在第一个中加载150x150px的图像,在第二个中加载300x150px的图像。

.canvas {
  width:150px;
  height:150px;
}
iframe,img {
  box-sizing:border-box;
  border:5px solid;
}
<!-- equivalent to 
<canvas width="150" height="150"></canvas>
load a 150x150px image -->
<img src="https://picsum.photos/150/150?image=1069">

<!-- equivalent to 
<canvas class="canvas"></canvas>
load a 300x150px image -->
<img class="canvas" src="https://picsum.photos/300/150?image=1069">

现在,我们看到的行为实际上是完全相同的:它们遵循inline-replaced elements rules (CSS2) ,后者在CSS-images-3中进行了改写,结果大致相同< / sub>。

当计算出的widthheightauto时,box-sizing不起作用,其固有的 width height 正在被使用。
通过CSS进行设置时,CSS会胜出,并且box-sizing个母版。