【问题标题】:How to expand a SVG responsively?如何响应地扩展 SVG?
【发布时间】:2021-01-08 10:55:14
【问题描述】:

我在汉堡菜单下使用 SVG,因此当用户单击该菜单时,SVG 会展开并用其上的选项填充整个屏幕。我为此使用了 scale(),所以基本上发生的情况是 SVG 的比例为 1,当用户单击菜单时,SVG 得到一个 scale(35)。

现在的问题。该比例(35)不会在更大的分辨率上填充整个屏幕,甚至在某些具有更大高度的移动分辨率上。如果我为某些东西设置比例以确保我将覆盖大部分屏幕,例如比例(70),这将使关闭动画非常混乱,因为通过如此大的比例到 1。我如何扩展这个 SVG一个流畅的动画,让它填满各种类型的屏幕?

编辑 - 在下面添加了带有简单快速示例的代码

下面是一些解释发生了什么的图片。

关闭菜单/带比例的 SVG(1)

打开的菜单/带有比例的 SVG(70)

菜单关闭 / SVG 从 scale(70) 变为 scale(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>

【问题讨论】:

  • 请使用minimal reproducible example 更新您的问题。但仅根据您已经发布的内容,答案很可能涉及缩放 SVG 的 内容,而不是整个 SVG。
  • @PaulLeBeau 添加了一个示例。谢谢你的建议。

标签: javascript html css svg


【解决方案1】:

问题是如何响应地缩放 blob,而不是只有一个缩放值,这对于非常大的屏幕来说可能太小,而在缩小时反而会在非常小的屏幕上引起问题。

由于 JS 已经在单击时被调用,我们可以获取 blob 的基本大小并查看它分别适合窗口高度和宽度的“多少次”,并使用这些比率来计算将保证窗口被覆盖但没有大的缩放。

我们可以通过在 click 事件函数中计算一个 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>

注意:这个 sn-p 似乎可以在不同的窗口大小上工作,但是在 Windows10 的 Edge 上的移动“模拟器”中,我注意到缩小时有一个小混蛋。我无法解释这一点。希望有人可以。

【讨论】:

  • 经过测试并且有效!还在 Edge/windows 10 上的移动模拟器中进行了测试,并没有真正注意到你所说的“小混蛋”,所以它对我来说就像一个魅力。谢谢!
【解决方案2】:

这是一种不同的方法。

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>

【讨论】:

  • 感谢您采用不同的方法!它工作得非常好,但并没有完全达到预期的效果,因为它有点切断了动画,尽管如此,我还是必须改变很多已经开发出来的东西来实现它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
  • 2017-01-10
  • 2022-10-16
  • 2012-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多