如何让画布填充一个div同时保持其宽高比?

huangapple go评论59阅读模式
英文:

How do I make a canvas fill a div while keeping its aspect ratio?

问题

我有一个位于弹性盒子内的画布元素,可能会被调整大小。如何使画布填充可用空间,同时保持其纵横比(2/3)且不被裁切?(我想更改CSS尺寸,而不是画布分辨率)。

我尝试过使用object-fit: containclamp(...),但无法获得我想要的结果。要么画布无法保持其纵横比,要么它会超出其容器。

这是我一直在尝试的精简版本:https://jsfiddle.net/mwq4502v/。

我不确定如何最好地实现这一点,所以非常感谢任何帮助!

英文:

I have a canvas element inside a flexbox that may be resized.
How do I get the canvas to fill the available space without losing its aspect ratio (2/3), and without being cut off?

(I want to change the CSS dimensions, not the canvas resolution).

I've tried using object-fit: contain and clamp(...), but I can't get the results I want. Either the canvas doesn't maintain its aspect ratio, or it grows outside its container.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

body {
  margin: 0;
}

#mainContent {
    background: grey;
    height: 100vh;
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
}

#someOtherElem {
    background: red;
    width: 200px;
    height: 200px;
    margin-left: 1rem;
}

#canvasContainer {
    display: flex;
    flex: 1;
    height: 100%;
    justify-content: center;
    align-items: center;
}

canvas {
    width: calc(100% - 2rem);
    height: calc(100% - 2rem);
    background: green;
    object-fit: contain;
}

<!-- language: lang-html -->

&lt;div id=&quot;mainContent&quot;&gt;
  &lt;div id=&quot;someOtherElem&quot;&gt;&lt;/div&gt;
  &lt;div id=&quot;canvasContainer&quot;&gt;
    &lt;canvas height=&quot;300&quot; width=&quot;200&quot;&gt;&lt;/canvas&gt;
  &lt;/div&gt;
&lt;/div&gt;

<!-- end snippet -->

Here's a stripped-down version of what I've been trying: https://jsfiddle.net/mwq4502v/.

I'm not sure what the best way to achieve this is, so any help would be greatly appreciated!

答案1

得分: 2

你可以为canvas指定一个aspect-ratio2 / 3,宽度为100%&lt;parent-height&gt; * 2 / 3,以较小者为准。

canvas {
  aspect-ratio: 2 / 3;
  width: min(100%, 100vh * 2 / 3);
  /* ...或者高度: min(100%, calc(100vw - 210px) * 3 / 2). 相同的精神。 */
}

一些数学计算:

设容器的宽度和高度分别为wh。由于canvas需要尽可能大,它将始终触碰容器的至少两个边界(或四个边界),这意味着其大小可以是w / (w / (2 / 3))(h * 2 / 3) / h,这取决于容器的大小。

w / h > 2 / 3

◄──────────── w ────────────►
┌────────┬─────────┬────────┐ ▲
│        │         │        │ │
│        │         │        │ │
│        │         │        │ │
│        │         │        │ h
│        │         │        │ │
│        │         │        │ │
│        │         │        │ │
└────────┴─────────┴────────┘ ▼
         ◄ (h*2/3) ►

w / h < 2 / 3:

         ◄─── w ───►
         ┌─────────┐ ▲
         │         │ │
       ▲ ├─────────┤ │
       │ │         │ │
       │ │         │ │
 (w*3/2) │         │ h
       │ │         │ │
       │ │         │ │
       ▼ ├─────────┤ │
         │         │ │
         └─────────┘ ▼

这意味着宽度需要是min(w, h * 2 / 3),在CSS中写成min(100%, 100vh * 2 / 3)

尝试一下:

<div id="mainContent">
  <div id="someOtherElem"></div>
  <div id="canvasContainer">
    <canvas></canvas>
  </div>
</div>
英文:

You can specify an aspect-ratio of 2 / 3 for canvas and a width of 100% or &lt;parent-height&gt; * 2 / 3, whichever smaller.

canvas {
  aspect-ratio: 2 / 3;
  width: min(100%, 100vh * 2 / 3);
  /* ...or height: min(100%, calc(100vw - 210px) * 3 / 2). Same spirit. */
}

Some math:

Let the width and height of the container be w and h, correspondingly. Since the canvas needs to be as large as possible it will always touch at least two borders of the container (or all 4), which means its size can be either w / (w / (2 / 3)) or (h * 2 / 3) / h, depends on the size of the container.

w / h > 2 / 3:

◄──────────── w ────────────►
┌────────┬─────────┬────────┐ ▲
│        │         │        │ │
│        │         │        │ │
│        │         │        │ │
│        │         │        │ h
│        │         │        │ │
│        │         │        │ │
│        │         │        │ │
└────────┴─────────┴────────┘ ▼
         ◄ (h*2/3) ►

w / h < 2 / 3:

         ◄─── w ───►
         ┌─────────┐ ▲
         │         │ │
       ▲ ├─────────┤ │
       │ │         │ │
       │ │         │ │
 (w*3/2) │         │ h
       │ │         │ │
       │ │         │ │
       ▼ ├─────────┤ │
         │         │ │
         └─────────┘ ▼

This means the width needs to be min(w, h * 2 / 3) or, in CSS, min(100%, 100vh * 2 / 3).

Try it:

<!-- begin snippet: js hide: true console: false babel: false -->

<!-- language: lang-css -->

canvas {
  aspect-ratio: 2 / 3;
  width: min(100%, 100vh * 2 / 3);
}

/* Demo only */

#canvasContainer {
  outline: 1px solid #000; /* Just so we know where it is */
}

body {
  margin: 0;
}

#mainContent {
  display: flex;
  align-items: center;
  height: 100vh;
}

#someOtherElem {
  margin-left: 1rem;
  width: 200px;
  height: 200px;
  background: red;
}

#canvasContainer {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

canvas {
  background: green;
}

<!-- language: lang-html -->

&lt;div id=&quot;mainContent&quot;&gt;
  &lt;div id=&quot;someOtherElem&quot;&gt;&lt;/div&gt;
  &lt;div id=&quot;canvasContainer&quot;&gt;
    &lt;canvas&gt;&lt;/canvas&gt;
  &lt;/div&gt;
&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年4月7日 01:22:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75952196.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定