You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用html2canvas截取CSS生成的马克杯包裹图案出现裁切问题

格式化后的提问内容

我正在尝试截取一段通过CSS生成的图像。

该CSS生成的图案效果如下:
预期效果

当前使用html2canvas输出的截图效果如下:
实际裁切效果

我目前尝试过的代码如下:

html2canvas(document.querySelector("#capture"), {
  allowTaint: true
}).then(canvas => {
  document.body.appendChild(canvas)
});
body {
  background: #0000007a;
}

h1 {
  font: small-caps 167% Arial, Helvetica, sans-serif
}

#container {
  margin-left: -56px;
  top: 450px;
  width: 550px;
  -moz-perspective: 800px;
  -webkit-perspective: 800px;
  margin-top: 130px;
}

#container:hover * {
  -moz-animation-play-state: paused;
  -webkit-animation-play-state: paused
}

#frame {
  margin-top: 95px;
  width: 23px;
  -moz-transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  /* translate must be last */
  -moz-transform: rotateX(-1deg) rotateY(45deg) rotateZ(0deg) translate3d(325px, -70px, 50px);
  -webkit-transform: rotateX(-1deg) rotateY(45deg) rotateZ(0deg) translate3d(325px, -70px, 50px)
}

.strip {
  -moz-transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  animation: spin 0.01s forwards;
}

.mastercontainer {
  width: 400px;
  height: 400px;
  display: inline-block;
  overflow: hidden;
}

.strip div {
  position: absolute;
  background: #000 url(http://automation.stickermonkey.shop/codeplayground/images/djmug2.jpg);
  border: solid rgb(145, 87, 0);
  border-width: thin 0;
  height: 275px;
  width: 34px;
  opacity: 1;
}

.strip .a {
  background-position: 0 0;
  -moz-transform: rotateY(0deg) translateZ(124px);
  -webkit-transform: rotateY(0deg) translateZ(124px)
}

.strip .b {
  background-position: 759px 0;
  -moz-transform: rotateY(15deg) translateZ(124px);
  -webkit-transform: rotateY(15deg) translateZ(124px)
}

.strip .c {
  background-position: 726px 0;
  -moz-transform: rotateY(30deg) translateZ(124px);
  -webkit-transform: rotateY(30deg) translateZ(124px)
}

.strip .d {
  background-position: 693px 0;
  -moz-transform: rotateY(45deg) translateZ(124px);
  -webkit-transform: rotateY(45deg) translateZ(124px)
}

.strip .e {
  background-position: 660px 0;
  -moz-transform: rotateY(60deg) translateZ(124px);
  -webkit-transform: rotateY(60deg) translateZ(124px)
}

.strip .f {
  background-position: 627px 0;
  -moz-transform: rotateY(75deg) translateZ(124px);
  -webkit-transform: rotateY(75deg) translateZ(124px)
}

.strip .g {
  background-position: 594px 0;
  -moz-transform: rotateY(90deg) translateZ(124px);
  -webkit-transform: rotateY(90deg) translateZ(124px)
}

.strip .h {
  background-position: 561px 0;
  -moz-transform: rotateY(105deg) translateZ(124px);
  -webkit-transform: rotateY(105deg) translateZ(124px)
}

.strip .i {
  background-position: 528px 0;
  -moz-transform: rotateY(120deg) translateZ(124px);
  -webkit-transform: rotateY(120deg) translateZ(124px)
}

.strip .j {
  background-position: 495px 0;
  -moz-transform: rotateY(135deg) translateZ(124px);
  -webkit-transform: rotateY(135deg) translateZ(124px)
}

.strip .k {
  background-position: 462px 0;
  -moz-transform: rotateY(150deg) translateZ(124px);
  -webkit-transform: rotateY(150deg) translateZ(124px)
}

.strip .l {
  background-position: 429px 0;
  -moz-transform: rotateY(165deg) translateZ(124px);
  -webkit-transform: rotateY(165deg) translateZ(124px)
}

.strip .m {
  background-position: 396px 0;
  -moz-transform: rotateY(180deg) translateZ(124px);
  -webkit-transform: rotateY(180deg) translateZ(124px)
}

.strip .n {
  background-position: 363px 0;
  -moz-transform: rotateY(195deg) translateZ(124px);
  -webkit-transform: rotateY(195deg) translateZ(124px)
}

.strip .o {
  background-position: 330px 0;
  -moz-transform: rotateY(210deg) translateZ(124px);
  -webkit-transform: rotateY(210deg) translateZ(124px)
}

.strip .p {
  background-position: 297px 0;
  -moz-transform: rotateY(225deg) translateZ(124px);
  -webkit-transform: rotateY(225deg) translateZ(124px)
}

.strip .q {
  background-position: 264px 0;
  -moz-transform: rotateY(240deg) translateZ(124px);
  -webkit-transform: rotateY(240deg) translateZ(124px)
}

.strip .r {
  background-position: 231px 0;
  -moz-transform: rotateY(255deg) translateZ(124px);
  -webkit-transform: rotateY(255deg) translateZ(124px)
}

.strip .s {
  background-position: 198px 0;
  -moz-transform: rotateY(270deg) translateZ(124px);
  -webkit-transform: rotateY(270deg) translateZ(124px)
}

.strip .t {
  background-position: 165px 0;
  -moz-transform: rotateY(285deg) translateZ(124px);
  -webkit-transform: rotateY(285deg) translateZ(124px)
}

.strip .u {
  background-position: 132px 0;
  -moz-transform: rotateY(300deg) translateZ(124px);
  -webkit-transform: rotateY(300deg) translateZ(124px)
}

.strip .v {
  background-position: 99px 0;
  -moz-transform: rotateY(315deg) translateZ(124px);
  -webkit-transform: rotateY(315deg) translateZ(124px)
}

.strip .w {
  background-position: 66px 0;
  -moz-transform: rotateY(330deg) translateZ(124px);
  -webkit-transform: rotateY(330deg) translateZ(124px)
}

.strip .x {
  background-position: 33px 0;
  -moz-transform: rotateY(345deg) translateZ(124px);
  -webkit-transform: rotateY(345deg) translateZ(124px)
}

@-moz-keyframes spin {
  from {
    -moz-transform: rotateY(360deg)
  }
  to {
    -moz-transform: rotateY(230deg)
  }
}

@-webkit-keyframes spin {
  from {
    -webkit-transform: rotateY(360deg)
  }
  to {
    -webkit-transform: rotateY(230deg)
  }
}
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
<div id="capture" class="mastercontainer">
  <div id="container">
    <div id="frame">
      <div class="strip">
        <div class="a"></div>
        <div class="b"></div>
        <div class="c"></div>
        <div class="d"></div>
        <div class="e"></div>
        <div class="f"></div>
        <div class="g"></div>
        <div class="h"></div>
        <div class="i"></div>
        <div class="j"></div>
        <div class="k"></div>
        <div class="l"></div>
        <div class="m"></div>
        <div class="n"></div>
        <div class="o"></div>
        <div class="p"></div>
        <div class="q"></div>
        <div class="r"></div>
        <div class="s"></div>
        <div class="t"></div>
        <div class="u"></div>
        <div class="v"></div>
        <div class="w"></div>
        <div class="x"></div>
      </div>
    </div>
  </div>
</div>

补充说明:我也尝试过配置foreignObjectRendering: true参数,此时截图的形状正确,但整体显示为全黑图像,效果见:
全黑效果

二次补充:我也接受其他实现方案,要么可以实现将矩形图像包裹在马克杯上的效果,要么可以替代截图获取我当前已生成的图案。


解决方案

问题根源

html2canvas本身对CSS 3D变换属性的支持度非常有限:

  • 默认模式下会忽略transform-style: preserve-3d、3D旋转/位移这类属性,直接按平面元素渲染,就会出现你碰到的错位裁切问题
  • 开启foreignObjectRendering模式后,浏览器安全限制会阻止跨域图片资源在foreignObject中渲染,因此出现全黑。

可选方案

方案1:替换截图工具,适配现有CSS代码

将html2canvas替换为dom-to-image库,它对CSS 3D的支持度更好,只需提前给用到的贴图资源配置CORS跨域允许,就能正常生成截图,参考代码如下:

domtoimage.toPng(document.querySelector("#capture"))
  .then(dataUrl => {
    const img = new Image();
    img.src = dataUrl;
    document.body.appendChild(img);
  })
  .catch(error => console.error('截图生成失败', error));
方案2:直接用Canvas实现杯身贴图(更稳定,推荐)

如果核心需求是把矩形图贴到杯型上再导出,直接用Canvas实现效果更稳定,也不需要额外的截图工具:

  1. 加载原始矩形贴图,按杯身弧度切割为24等份竖条
  2. 对每个竖条做对应的透视变形后绘制到Canvas上
  3. 直接调用canvas.toDataURL()就能导出最终效果,完全不存在渲染兼容问题。
    如果需要支持角度调整、旋转交互,也可以用Three.js创建圆柱模型,把贴图贴到圆柱上渲染,后续调整参数、替换素材都更灵活。

内容的提问来源于stack exchange,提问作者Glen Keybit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:06:01