如何将Codepen交互式SVG蒙版嵌入540px高全屏宽容器?
解决方案:固定高度容器内嵌入SVG蒙版并保持宽高比
我明白你想要的效果:把这个交互式SVG蒙版放进一个固定高度540px的容器,容器宽度铺满浏览器边缘,同时SVG始终保持原有的16:9宽高比,还要保留所有交互功能。下面是调整后的完整代码和关键改动说明:
修改后的完整代码
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="svg-container"> <svg id="demo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="1600" height="900" viewBox="0 0 1600 900"> <defs> <radialGradient id="maskGradient"> <stop offset="50%" stop-color="#fff"/> <stop offset="100%" stop-color="#000"/> </radialGradient> <mask id="theMask"> <circle id="masker" r="150" fill="url(#maskGradient)" cx="800" cy="450" /> </mask> </defs> <image id="lines" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomSketch.jpg" x="0" y="0" width="1600" height="900" /> <g id="maskReveal" mask="url(#theMask)" > <image id="regular" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomColor.jpg" x="0" y="0" width="1600" height="900" /> </g> <circle id="ring" r="20" fill="none" stroke="#dc143c" stroke-width="2" cx="800" cy="450" /> <circle id="dot" r="4" fill="#dc143c" cx="800" cy="450" /> </svg> <div id="instructions"> <svg id="dial" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"> <path id="progressRing" d="M50,10A40,40,0,1,1,10,50,40,40,0,0,1,50,10Z" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="6"/> <circle r="43" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5" /> <circle r="37" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5"/> <text transform="translate(55 56)" text-anchor="start" font-size="20" fill="#fff">%</text> <text id="counter" transform="translate(55 56)" text-anchor="end" font-size="20" fill="#fff">0</text> </svg> <p>Hover mouse to move mask around.</p> <p>Hold & release mouse button to expand & contract mask.</p> </div> </div>
CSS
body { padding: 0; margin: 0; font-family: "Signika", sans-serif; background: #262626; width: 100%; color: white; } p { margin: 0; text-align: center; white-space: nowrap; } * { box-sizing: border-box; } /* 新增的容器样式,固定高度540px,宽度铺满浏览器 */ #svg-container { height: 540px; width: 100%; position: relative; overflow: hidden; /* 隐藏SVG超出容器的部分 */ background: #262626; } #demo { cursor: none; position: absolute; top: 50%; /* 垂直居中基准 */ } #instructions { position: absolute; padding: 12px; bottom: 20px; background: rgba(0, 0, 0, 0.75); left: 50%; cursor: none; padding-top: 100px; user-select: none; border-radius: 4px; transform: translateX(-50%); /* 水平居中 */ } #dial { position: absolute; top: 0; left: 50%; transform: translateX(-50%); /* 水平居中 */ }
JavaScript
console.clear(); var svg = document.querySelector("#demo"); var tl = new TimelineMax({onUpdate:onUpdate}); var pt = svg.createSVGPoint(); var data = document.querySelector(".tlProgress"); var counter = document.querySelector("#counter"); var ratio = 9/16; // 原SVG是16:9,这里用高度/宽度的比例 var container = document.querySelector("#svg-container"); // 获取容器元素 TweenMax.set("#instructions, #dial", {xPercent: -50}); TweenMax.set("#progressRing", {drawSVG:0}); tl.to("#masker", 2, {attr:{r:2400}, ease:Power2.easeIn}); tl.reversed(true); function mouseHandler() { tl.reversed(!tl.reversed()); } function getPoint(evt){ pt.x = evt.clientX; pt.y = evt.clientY; return pt.matrixTransform(svg.getScreenCTM().inverse()); } function mouseMove(evt) { var newPoint = getPoint(evt); TweenMax.set("#dot", {attr:{cx:newPoint.x, cy:newPoint.y}}); TweenMax.to("#ring, #masker", 0.88, {attr:{cx:newPoint.x, cy:newPoint.y}, ease:Power2.easeOut}); } function onUpdate() { var prog = (tl.progress() * 100); TweenMax.set("#progressRing", {drawSVG:prog + "%"}); counter.textContent = prog.toFixed(); } function newSize() { var containerWidth = container.offsetWidth; var containerHeight = 540; // 固定容器高度 var targetWidth, targetHeight; // 根据容器宽度计算SVG的尺寸,保持16:9比例 if (containerWidth > containerHeight * (16/9)) { // 容器足够宽,SVG宽度铺满容器,高度按比例计算 targetWidth = containerWidth; targetHeight = containerWidth * ratio; // 垂直居中SVG,裁剪上下超出部分 TweenMax.set("#demo", { attr: { width: targetWidth, height: targetHeight }, x: 0, y: -(targetHeight - containerHeight)/2 // 向上平移,让中间区域显示 }); } else { // 容器较窄,SVG高度铺满容器,宽度按比例计算,水平居中 targetHeight = containerHeight; targetWidth = containerHeight / ratio; TweenMax.set("#demo", { attr: { width: targetWidth, height: targetHeight }, x: (containerWidth - targetWidth)/2, // 水平居中 y: 0 }); } } window.addEventListener("mousedown", mouseHandler); window.addEventListener("mouseup", mouseHandler); window.addEventListener("mousemove", mouseMove); newSize(); window.addEventListener("resize", newSize);
关键改动说明
- 新增容器元素:添加了
#svg-container,固定高度540px、宽度100%,并设置overflow:hidden来隐藏SVG超出容器的部分,确保视觉上符合要求。 - 调整CSS定位:
- 将SVG设置为绝对定位,配合JS计算的偏移值实现居中或铺满。
- 调整
#instructions和#dial的定位,确保它们始终在容器底部居中显示。
- 重写尺寸计算逻辑:
- 不再基于窗口尺寸计算,而是以容器的宽高为基准。
- 分两种情况处理:容器足够宽时,SVG宽度铺满容器,垂直居中裁剪;容器较窄时,SVG高度铺满容器,水平居中显示。
- 修正比例变量:将
ratio改为9/16(高度/宽度),更直观地计算对应尺寸。
这样修改后,SVG蒙版就能完美嵌入到固定高度540px的容器中,宽度铺满浏览器边缘,同时始终保持16:9的宽高比,所有交互功能也能正常使用。
内容的提问来源于stack exchange,提问作者Thisura De Silva
相关产品推荐
相关产品推荐

