CSS perspective: fit the trapezoid inside container bounds

190 views Asked by At

I have this snippet which puts a full-page <canvas> element into a 45-degree perspective using CSS. However, the transformed canvas exceeds the page's bounds and is clipped:

window.onload = window.onresize = function() {
  // draw a gradient on the canvas
  var canvas = document.querySelector('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  var ctx = canvas.getContext('2d');
  var grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
  grad.addColorStop(0, '#ff0000');
  grad.addColorStop(0.5, '#ffff00');
  grad.addColorStop(1, '#00ff00');
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
};
body {
  margin: 0;
  overflow: hidden;
}

canvas {
  transform-style: preserve-3d;
  transform: rotateX(45deg);
}

.container {
  width: 100%;
  height: 100%;
  perspective: 50vw;
  perspective-origin: 50% 0%;
}
<div class="container">
  <canvas></canvas>
</div>

How would I ensure the entire canvas stays within the page's bounds (bottom side of the trapezoid should have the exact same width as the page), while maintaining the perspective effect? Either CSS or JavaScript solutions are fine, as long as they work with any page size.

1

There are 1 answers

2
ashish singh On

translate it backwards using translateZ

look for a comment in CSS

window.onload = window.onresize = function() {
  // draw a gradient on the canvas
  var canvas = document.querySelector('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  var ctx = canvas.getContext('2d');
  var grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
  grad.addColorStop(0, '#ff0000');
  grad.addColorStop(0.5, '#ffff00');
  grad.addColorStop(1, '#00ff00');
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
};
body {
  margin: 0;
  overflow: hidden;
}

canvas {
  transform-style: preserve-3d;
  /* added translation here */
  transform: translateZ(-50vmax) rotateX(45deg);
}

.container {
  width: 100%;
  height: 100%;
  perspective: 50vw;
  perspective-origin: 50% 0%;
  
}
<div class="container">
  <canvas></canvas>
</div>