如何平滑地设置侧边栏隐藏的动画,这会影响其他区域的大小

sua*_*kim 5 html css animation css-transitions

我的屏幕有 3 个水平对齐的主要区域:

在此输入图像描述

侧边栏 (1) 可以折叠/隐藏(向左)。隐藏时,释放的空间应用于可视化 (3),同时菜单宽度 (2) 保持不变。

ATM 我正在​​这样调整内容:

  • (1)、(2) 和 (3) 的父容器: display: flex
  • (1): width: 260px;
  • (2): width: 293px;
  • (3): flex: 1;

折叠时,我只是设置width: 0为侧边栏。

我知道我可以简单地对width更改进行动画/过渡,或者通过更改和动画/过渡left属性或使用边距等来进行更改。但我能想到的所有这些解决方案都会触发浏览器布局步骤(更改widthleft动画margin、... )我想阻止这种情况,因为这会导致动画性能不佳,如此处所述

理想情况下,我想保留属性的 CSS 转换,这些转换只会触发浏览器的撰写步骤translate等。

不幸的是,我想不出一种方法来只使用那些“好的”CSS 属性,同时也满足我将释放的空间从隐藏侧边栏重新分配到可视化的目标 (3)。

是否甚至可以隐藏向左动画的侧边栏而不触发重新布局,但仍然重新分配释放的空间?如果不是,如何才能高效地完成此操作?

我认为这是 Web 开发中非常常见的用例,因此也欢迎链接到相关文献、博客等!

我在网上找到了很多关于侧边栏动画隐藏的示例,但它们要么为width属性设置动画,要么不将释放的空间重新分配给剩余的可见内容(例如,侧边栏仅显示在主要内容的“上方”等) ,所以到目前为止我发现的例子都没有真正满足我所描述的目标......

小智 3

请检查以下HTML, JS,CSS片段。您可以更改元素的实际宽度以完全匹配您需要的宽度。

操作width侧边栏不是问题。正如您提供的链接中所解释的,性能是。这篇文章的最后几行写道:

性能对用户来说很重要。Web 开发人员需要构建反应快速且渲染流畅的应用程序。Google 性能专家 Paul Lewis 可以帮助您消除卡顿并创建保持每秒 60 帧性能的 Web 应用程序。完成本课程后,您将获得分析应用程序和识别卡顿原因所需的工具。您将探索浏览器的渲染管道并发现可轻松构建高性能应用程序的模式。

因此,您可以使用此处Javascript requestAnimationFrame所示的方法重新创建以下示例的逻辑。

const side = document.querySelector('.side');
const sideToggle = document.querySelector('.sideToggle');
const main = document.querySelector('.main');
sideToggle.addEventListener('click', () => {
  if (!sideToggle.classList.contains('active')) {
    sideToggle.classList.add('active');
  } else {
    sideToggle.classList.remove('active');
  }

  if (!main.classList.contains('full')) {
    main.classList.add('full');
  } else {
    main.classList.remove('full');
  }
  if (!side.classList.contains('hidden')) {
    side.classList.add('hidden');
  } else {
    side.classList.remove('hidden');
  }
});
Run Code Online (Sandbox Code Playgroud)
.container {
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  width: 100%;
}

.side {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  background: #000;
  padding: 0;
  width: 20%;
  height: 100vh;
  transition: width 1s linear;
}

.side a {
  color: #fff;
  text-decoration: none;
  line-height: 1;
  height: 1.5rem;
  padding: 1rem;
}

.side a:hover {
  color: #000;
  background: #fff;
}

.side.hidden {
  width: 0;
  transition: width 1s linear;
}

.sideToggle {
  background: #000;
  color: #fff;
  width: 2rem;
  height: 2rem;
  position: fixed;
  right: .75rem;
  bottom: .75rem;
  border-radius: 50%;
  text-align: center;
  cursor: pointer;
  z-index: 1001;
}

.sideToggle:after {
  content: "\2630";
  font-size: 1.25rem;
  vertical-align: top;
}

.sideToggle.active:after {
  content: "\00D7";
  vertical-align: top;
  font-size: 1.75rem;
}

.main {
  background: red;
  width: 80%;
  height: 100vh;
  transition: width 1s linear;
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  width: 100%;
  color: #fff;
}

.main.full {
  width: 100%;
  transition: width 1s linear;
}

.left {
  width: 15rem;
  padding: 1rem;
}

.right {
  width: calc(100% - 15rem);
  background: indigo;
  padding: 1rem;
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
  <div class="side">
    <a href="#">Home</a>
    <a href="#">Page 1</a>
    <a href="#">Page 2</a>
    <a href="#">Page 3</a>
  </div>
  <span class="sideToggle active"></span>
  <div class="main">
    <div class="left">
        this width is ment to be static
    </div>
    <div class="right">
        this width is ment to be dynamic 
    </div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这是另一种可能的方式,主要使用侧边栏translateX而不更改width侧边栏。

const side = document.querySelector('.side');
const sideToggle = document.querySelector('.sideToggle');
const main = document.querySelector('.main');
sideToggle.addEventListener('click', () => {
  if (!sideToggle.classList.contains('active')) {
    sideToggle.classList.add('active');
  } else {
    sideToggle.classList.remove('active');
  }

  if (!main.classList.contains('full')) {
    main.classList.add('full');
  } else {
    main.classList.remove('full');
  }
  if (!side.classList.contains('hidden')) {
    side.classList.add('hidden');
  } else {
    side.classList.remove('hidden');
  }
});
Run Code Online (Sandbox Code Playgroud)
.container {
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  width: 100%;
}

.side {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  background: #000;
  padding: 0;
  width: 7rem;
  transform: translateX(0);
  height: 100vh;
  transition: transform 1s linear, z-index 1s linear;
  z-index: 9999;
  position: fixed;
  left: 0;
  top: 0;
  will-change: transform, z-index;
}

.side a {
  color: #fff;
  text-decoration: none;
  line-height: 1;
  height: 1.5rem;
  padding: 1rem;
}

.side a:hover {
  color: #000;
  background: #fff;
}

.side.hidden {
  transform: translateX(-100%);
  transition: transform 1s linear, z-index 1s linear;
  z-index: -1;
}

.sideToggle {
  background: #000;
  color: #fff;
  width: 2rem;
  height: 2rem;
  position: fixed;
  right: .75rem;
  bottom: .75rem;
  border-radius: 50%;
  text-align: center;
  cursor: pointer;
  z-index: 1001;
}

.sideToggle:after {
  content: "\2630";
  font-size: 1.25rem;
  vertical-align: top;
}

.sideToggle.active:after {
  content: "\00D7";
  vertical-align: top;
  font-size: 1.75rem;
}

.main {
  background: red;
  width: calc(100% - 7rem);
  height: 100vh;
  transition: transform 1s linear, width 1s linear;
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  align-content: space-evenly;
  justify-content: space-evenly;
  color: #fff;
  left: 0;
  top: 0;
  transform: translateX(7rem);
  position: absolute;
  will-change: transform, width;
}

.main.full {
  transform: translateX(0);
  width: 100%;
  transition: transform 1s linear, width 1s linear;
}

.main .left,
.main.full .left {
  flex-grow: 1;
  flex-shrink: 1;
  width: 15rem;
  padding: 1rem;
}

.right {
  flex-grow: 2;
  flex-shrink: 2;
  width: calc(100% - 15rem);
  background: indigo;
  padding: 1rem;
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
  <div class="side">
    <a href="#">Home</a>
    <a href="#">Page 1</a>
    <a href="#">Page 2</a>
    <a href="#">Page 3</a>
  </div>
  <span class="sideToggle active"></span>
  <div class="main">
    <div class="left">
      this width is ment to be static
    </div>
    <div class="right">
      this width is ment to be dynamic
    </div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)