如何响应式地扩展SVG?

4
我在汉堡菜单下使用SVG,点击菜单后SVG会扩展并填满整个屏幕。我使用scale()实现此功能,因此基本上发生的情况是SVG具有1的比例,当用户单击菜单时,SVG将获得scale(35)的比例。
现在问题来了。该比例(scale(35))在更大的分辨率甚至一些具有更大高度的移动分辨率上都不能填满整个屏幕。如果我设置比例为scale(70),以确保覆盖大多数屏幕,这将使关闭动画变得非常混乱,因为SVG需要从如此大的比例缩小到1。如何扩展此SVG并使其平稳地填充各种屏幕?
以下是一些解释发生情况的图片:
关闭菜单/SVG比例为1 关闭菜单/SVG比例为1 打开菜单/SVG比例为70 打开菜单/SVG比例为70 菜单关闭/SVG从70的比例缩小到1,并且看起来很凌乱 菜单关闭/SVG从70的比例缩小到1,并且看起来很凌乱

function menuOnClick() {
  document.getElementById("menu-bar").classList.toggle("change");
  document.getElementById("nav").classList.toggle("change");
  document.getElementById('blob').classList.toggle("change-bg");
}
#menu {
  z-index: 2;
}

#menu-bar {
  width: 45px;
  height: 40px;
  margin: 30px 0 20px 20px;
  cursor: pointer;
  float: right;
}

.bar {
  height: 5px;
  width: 100%;
  background-color: #00d1a9;;
  display: block;
  border-radius: 5px;
  transition: 0.3s ease;
}

#bar1 {
  transform: translateY(-4px);
}

#bar3 {
  transform: translateY(4px);
}

.nav {
  transition: 0.3s ease;
  display: none;
}

.nav ul {
  padding: 0 22px;
}

.nav li {
  list-style: none;
  padding: 12px 0;
}

.nav li a {
  color: white;
  font-size: 20px;
  text-decoration: none;
}

.nav li a:hover {
  font-weight: bold;
}

.menu-bg, #menu {
  top: 0;
  left: 0;
  position: absolute;
}

.change {
  display: block;
}

.change .bar {
  background-color: white;
}

.change #bar1 {
  transform: translateY(4px) rotateZ(-45deg);
}

.change #bar2 {
  opacity: 0;
}

.change #bar3 {
  transform: translateY(-6px) rotateZ(45deg);
}

.change-bg {
  transform: scale(70);
}
.blob {
  margin-top:-32px;
  top: 0;
  z-index: 1;
  pointer-events: none;
  -webkit-transition: all 0.75s linear;
  transition: all 0.75s linear;
  display: block;
  will-change: auto;
    filter: none;
  -webkit-filter: blur(0);
  -moz-filter: blur(0);
  -ms-filter: blur(0);
  filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='0');
}
<div id="menu">
  <div id="menu-bar" onclick="menuOnClick()">
    <div id="bar1" class="bar"></div>
    <div id="bar2" class="bar"></div>
    <div id="bar3" class="bar"></div>
  </div>
  <nav class="nav" id="nav">
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Blog</a></li>
    </ul>
  </nav> 
</div>
                                <svg class="blob" id="blob" xmlns="http://www.w3.org/2000/svg" width="265.42" height="151.973" viewBox="0 0 265.42 151.973">
                                    <title>Menu Blob</title>
                                    <desc>The blob that grows to be the menu background</desc>
                                    <path class="blobPath" id="blobPath" shape-rendering="auto" d="M-1377.154,10877.442c-10.882-7.812-24.262-11.1-36.627-16.251s-24.764-13.355-28.853-26.112c-.135.766,251.322-30.752,251.3-30.855s-9.766,33.5-15.478,42.831c-9.83,16.055-20.015,32.053-32.926,45.756a125.25,125.25,0,0,1-18.85,16.492,89.6,89.6,0,0,1-28.133,13.538,70.507,70.507,0,0,1-29.47,1.6,56.7,56.7,0,0,1-24.487-10C-1354.7,10904.193-1363.044,10887.567-1377.154,10877.442Z" transform="translate(2763.902 -10547.315) rotate(7)" />
                                </svg>

<div class="menu-bg" id="menu-bg"></div>


1
请在您的问题中更新一个 [mcve] 。但仅基于您已经发布的内容,答案很可能涉及缩放 SVG 的 内容,而不是整个 SVG。 - Paul LeBeau
@PaulLeBeau添加了一个示例。感谢你的建议。 - Pedro Fragata
2个回答

3
问题是如何使blob响应式缩放,而不只是有一个缩放值,在非常大的屏幕上可能太小,在非常小的屏幕上缩小时可能会导致问题。
由于JS已经在单击时被调用,因此我们可以获取blob的基本大小,并查看它分别适合窗口高度和宽度的“次数”,并使用这些比率计算一个缩放比例,以保证窗口被覆盖但没有巨大的缩放。
我们可以通过在点击事件函数中计算CSS变量来实现这一点,然后在change-bg类中使用它(但在未设置该类时将被忽略)。这样做的优点是,如果窗口已调整大小,则会自动重新计算比例。

function menuOnClick() {
  document.getElementById("menu-bar").classList.toggle("change");
  document.getElementById("nav").classList.toggle("change");
  document.getElementById('blob').classList.toggle("change-bg");
  /* added */
  let blob = document.getElementById('blob');
  let rect = blob.getBoundingClientRect();
  document.getElementById('blob').style.setProperty('--scale', Math.max(4*window.innerWidth/rect.width,4*window.innerHeight/rect.height));
}
#menu {
  z-index: 2;
}

#menu-bar {
  width: 45px;
  height: 40px;
  margin: 30px 0 20px 20px;
  cursor: pointer;
  float: right;
}

.bar {
  height: 5px;
  width: 100%;
  background-color: #00d1a9;;
  display: block;
  border-radius: 5px;
  transition: 0.3s ease;
}

#bar1 {
  transform: translateY(-4px);
}

#bar3 {
  transform: translateY(4px);
}

.nav {
  transition: 0.3s ease;
  display: none;
}

.nav ul {
  padding: 0 22px;
}

.nav li {
  list-style: none;
  padding: 12px 0;
}

.nav li a {
  color: white;
  font-size: 20px;
  text-decoration: none;
}

.nav li a:hover {
  font-weight: bold;
}

.menu-bg, #menu {
  top: 0;
  left: 0;
  position: absolute;
}

.change {
  display: block;
}

.change .bar {
  background-color: white;
}

.change #bar1 {
  transform: translateY(4px) rotateZ(-45deg);
}

.change #bar2 {
  opacity: 0;
}

.change #bar3 {
  transform: translateY(-6px) rotateZ(45deg);
}

.blob {
  transform: scale(1); /* added */
  margin-top:-32px;
  top: 0;
  z-index: 1;
  pointer-events: none;
  -webkit-transition: all 0.75s linear;
  transition: all 0.75s linear;
  display: block;
  will-change: auto;
    filter: none;
  -webkit-filter: blur(0);
  -moz-filter: blur(0);
  -ms-filter: blur(0);
  filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='0');
}
.change-bg { /* moved after .blob so takes precedence */
  transform: scale(var(--scale));/* Changed from 70 */
}
<div id="menu">
  <div id="menu-bar" onclick="menuOnClick()">
    <div id="bar1" class="bar"></div>
    <div id="bar2" class="bar"></div>
    <div id="bar3" class="bar"></div>
  </div>
  <nav class="nav" id="nav">
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Blog</a></li>
    </ul>
  </nav> 
</div>
                                <svg class="blob" id="blob" xmlns="http://www.w3.org/2000/svg" width="265.42" height="151.973" viewBox="0 0 265.42 151.973">
                                    <title>Menu Blob</title>
                                    <desc>The blob that grows to be the menu background</desc>
                                    <path class="blobPath" id="blobPath" shape-rendering="auto" d="M-1377.154,10877.442c-10.882-7.812-24.262-11.1-36.627-16.251s-24.764-13.355-28.853-26.112c-.135.766,251.322-30.752,251.3-30.855s-9.766,33.5-15.478,42.831c-9.83,16.055-20.015,32.053-32.926,45.756a125.25,125.25,0,0,1-18.85,16.492,89.6,89.6,0,0,1-28.133,13.538,70.507,70.507,0,0,1-29.47,1.6,56.7,56.7,0,0,1-24.487-10C-1354.7,10904.193-1363.044,10887.567-1377.154,10877.442Z" transform="translate(2763.902 -10547.315) rotate(7)" />
                                </svg>

<div class="menu-bg" id="menu-bg"></div>

注意:这段代码似乎在不同的窗口大小上都能正常工作,但在Windows10的Edge移动模拟器中,当缩小时会出现一个小的抖动。 我无法解释这个问题。希望有人可以解决。

测试过并且可行!在Edge/Windows 10上的移动模拟器中也进行了测试,我并没有注意到你所说的“小抽搐”,所以对我来说它非常完美。谢谢! - Pedro Fragata

3

这里有一个不同的方法。

document.getElementById("menu-bar").addEventListener('click', function(evt) {
  evt.target.parentElement.classList.toggle("open");
});
body, html {
  margin: 0;
}

#menu {
  position: relative;
}



#blob {
  position: absolute;
  top: 0;
  right: 0;
  transition: 0.3s ease;
  z-index: -1;
}

#blob g {
  fill: #00d1a9;
  transition: 0.3s ease;
  transform-origin: 150px 32px;
  transform-box: fill-box;
}

.open #blob {
  width: 100%;
  height: 100%;
}

.open #blob g {
  transform: scale(20);
}


#menu-bar {
  position: absolute;
  top: 40px;
  right: 100px;
  width: 45px;
  height: 40px;
  cursor: pointer;
}

.bar {
  height: 5px;
  width: 100%;
  background-color: rgba(255, 255, 255, 0.8);
  display: block;
  border-radius: 5px;
  transition: 0.3s ease;
  pointer-events: none;
}

#bar1 {
  transform: translateY(-4px);
}

#bar3 {
  transform: translateY(4px);
}

.open #bar1 {
  transform: translateY(4px) rotateZ(-45deg);
}

.open #bar2 {
  opacity: 0;
}

.open #bar3 {
  transform: translateY(-6px) rotateZ(45deg);
}




.nav {
  display: inline-block;
  opacity: 0;
  pointer-events: none;
}

.nav ul {
  padding: 0 22px;
  margin: 0;
}

.nav li {
  list-style: none;
  padding: 12px 0;
}

.nav li a {
  color: black;
  font-size: 20px;
  text-decoration: none;
}

.nav li a:hover {
  font-weight: bold;
}

.open .nav {
  transition: 0.3s ease;
  transition-delay: 0.2s;
  opacity: 1;
  pointer-events: auto;
}
<div id="menu">
  <svg class="blob" id="blob" width="256" height="108" viewBox="10 31 256 108">
    <g>
      <path class="blobPath" id="blobPath" shape-rendering="auto" d="M-1377.154,10877.442c-10.882-7.812-24.262-11.1-36.627-16.251s-24.764-13.355-28.853-26.112c-.135.766,251.322-30.752,251.3-30.855s-9.766,33.5-15.478,42.831c-9.83,16.055-20.015,32.053-32.926,45.756a125.25,125.25,0,0,1-18.85,16.492,89.6,89.6,0,0,1-28.133,13.538,70.507,70.507,0,0,1-29.47,1.6,56.7,56.7,0,0,1-24.487-10C-1354.7,10904.193-1363.044,10887.567-1377.154,10877.442Z" transform="translate(2763.902 -10547.315) rotate(7)" />
    </g>
  </svg>

  <div id="menu-bar">
    <div id="bar1" class="bar"></div>
    <div id="bar2" class="bar"></div>
    <div id="bar3" class="bar"></div>
  </div>

  <nav class="nav" id="nav">
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Blog</a></li>
    </ul>
  </nav> 
</div>


谢谢你提供这种不同的方法!它确实非常有效,但并不完全符合预期,因为它有点切断了动画。而且即使如此,我也需要改变很多已经开发好的内容才能实现它。 - Pedro Fragata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接