使用 CSS 时画布会被拉伸,但使用“宽度”/“高度”属性是正常的

Posted

技术标签:

【中文标题】使用 CSS 时画布会被拉伸,但使用“宽度”/“高度”属性是正常的【英文标题】:Canvas is stretched when using CSS but normal with "width" / "height" properties 【发布时间】:2021-08-21 09:55:22 【问题描述】:

我有 2 个画布,一个使用 html 属性 widthheight 来调整大小,另一个使用 CSS:

<canvas id="compteur1"   onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>

Compteur1 显示应该是这样,但不是 compteur2。内容是使用 javascript 在 300x300 画布上绘制的。

为什么会有显示差异?

【问题讨论】:

【参考方案1】:

widthheight 属性似乎决定了画布坐标系的宽度或高度,而 CSS 属性只决定了它的显示框的大小。

这在HTML specification中有解释:

canvas 元素有两个属性来控制元素位图的大小:widthheight。这些属性在指定时必须具有有效的非负整数解析非负整数的规则必须用于获取它们的数值。如果缺少某个属性,或者如果解析其值返回错误,则必须使用默认值。 width 属性默认为 300,height 属性默认为 150。

【讨论】:

确实.. 我一直认为像“width”和“height”这样的直接属性在最近的 html 版本中被弃用了.. 哦,显然它实际上在whatwg.org/specs/web-apps/current-work/multipage/…(#attr-canvas-width 部分)描述得相当好。问题是我之前点击了错误的width,而是转到了#dom-canvas-width部分。提交w3.org/Bugs/Public/show_bug.cgi?id=9469关于它。 拥有一个看起来很像但与另一个(css 宽度、高度)根本不同的 API。哇。 当您希望内部坐标系不同时,区分这些很重要。 (即用于视网膜显示器或 8 位风格的游戏) 这真是令人困惑。我们试图在css中设置宽度和高度。我们花了 2 天的时间拉扯头发来了解这两种关于宽度和高度的不同解释。哇...【参考方案2】:

要设置你需要的widthheight,你可以使用

canvasObject.setAttribute('width', '475');

【讨论】:

+1 el.setAttribute('width', parseInt($el.css('width'))) 成功了,谢谢 如果我想让我的画布有一个相对大小怎么办?也就是说,如何模仿width: 100%;的css属性? 很好的答案,但不要忘记添加 canvasObject.setAttribute('height', '123') ! 我认为你不需要使用 .setAttribute() 我一直使用 .width 和 .height 属性 使用getComputedStyle的纯JavaScript(不带jQuery)版本:canvas.setAttribute('width', window.getComputedStyle(canvas, null).getPropertyValue("width"));。重复高度。【参考方案3】:

对于 &lt;canvas&gt; 元素,widthheight 的 CSS 规则设置将被绘制到页面的画布元素的实际大小。另一方面,widthheight 的 HTML 属性设置了画布 API 将使用的坐标系或“网格”的大小。

例如,考虑这个 (jsfiddle):

var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);

var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas 
  border: 1px solid black;
<canvas id="canvas1" style="width: 50px; height: 100px;"  ></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;"  ></canvas>

相对于画布元素的内部坐标,两者都绘制了相同的东西。但在第二个画布中,红色矩形的宽度将增加一倍,因为整个画布被 CSS 规则拉伸到更大的区域。

注意:如果未指定 width 和/或 height 的 CSS 规则,则浏览器将使用 HTML 属性来调整元素的大小,使这些值的 1 个单位等于页面上的 1px。如果未指定这些属性,则它们将默认为 300width150height

【讨论】:

【参考方案4】:

如果您在 CSS 中设置宽度和高度,画布将被拉伸。如果你想动态操作画布的尺寸,你必须像这样使用 JavaScript:

canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');

【讨论】:

太棒了!感谢您的回答。我必须在 canvas.getContext('2d') 之前放置 canvas.setAttribute 以避免拉伸图像。【参考方案5】:

浏览器使用css的宽度和高度,但canvas元素根据canvas的宽度和高度进行缩放。在 javascript 中,读取 css 宽度和高度并将画布宽度和高度设置为该值。

var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();

【讨论】:

【参考方案6】:

香尼玛修正

var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))

【讨论】:

【参考方案7】:

CSS 设置画布元素的宽度和高度,因此它会影响坐标空间,使所有内容都倾斜

这是我如何使用 Vanilla JavaScript 设置宽度和高度的方法

canvas.width = numberForWidth

canvas.height = numberForHeight

【讨论】:

【参考方案8】:

canvas 是通过缓冲区来渲染图像的,所以当你指定宽度和高度 html 属性时,缓冲区的大小和长度会发生变化,但是当你使用 css 时,缓冲区的大小是不变的。使图像拉伸。

使用 html 大小调整。

画布大小改变 -> 缓冲区大小改变 -> 渲染

使用 css 调整大小

画布大小改变 -> 渲染

由于缓冲区长度保持不变,当上下文渲染图像时, 图像显示在调整大小的画布中(但在未更改的缓冲区中呈现)

【讨论】:

【参考方案9】:

如果您想要基于例如的动态行为CSS 媒体查询,不要使用画布宽度和高度属性。使用 CSS 规则,然后在获取画布渲染上下文之前,将 CSS 宽度和高度样式分配给宽度和高度属性:

var elem = document.getElementById("mycanvas");

elem.width = elem.style.width;
elem.height = elem.style.height;

var ctx1 = elem.getContext("2d");
...

【讨论】:

很明显,如果仅在 CSS 中指定尺寸,画布将获得默认坐标尺寸 (300 x 150)。但是,这个建议对我不起作用,但下面的解决方案可以。 @PerLindberg - 如果您为画布元素定义了 CSS 宽度和高度(以像素为单位),则此解决方案有效。

以上是关于使用 CSS 时画布会被拉伸,但使用“宽度”/“高度”属性是正常的的主要内容,如果未能解决你的问题,请参考以下文章

ThreeJS canvas画布自适应的原理

canvas绘制线条怎么改变线条长度

CSS Grid将高度和宽度拉伸到容器[重复]

关于使用canvas画图时,图片被拉伸的问题

画布元素溢出其容器 div

创建拉伸画布视图的方法