如何平滑动画侧边栏的隐藏,从而影响其他区域的大小

时间:2019-04-26 13:44:26

标签: html css animation css-transitions

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

enter image description here

侧栏(1)可以折叠/隐藏(向左)。隐藏时,应为可视化对象(3)提供释放的空间,而菜单宽度(2)保持不变。

ATM我正在像这样对齐内容:

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

折叠后,我只需将侧边栏设置为width: 0

我知道我可以简单地对width进行更改动画或过渡,也可以通过更改left属性的动画和过渡或进行边距处理来实现它,但是我能想到的所有解决方案触发浏览器的布局步骤(更改widthleftmargin等),因为这会导致动画效果不佳,如here所述,这是我想防止的

理想情况下,我想保留CSS过渡属性,这些属性只会触发浏览器的编写步骤,例如translate等。

不幸的是,我想不出一种方法来仅使用这些“良好的” CSS属性,也无法实现将释放的空间从隐藏的侧边栏重新分配给可视化对象的目标(3)。

是否有可能在不触发重新布局的情况下隐藏左侧动画的侧边栏,但仍重新分配释放的空间?如果没有,那么如何仍然可以做到这一点呢?

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

我在网络上发现了很多有关侧边栏动画隐藏的示例,但是它们要么为width属性设置动画,要么不将释放的空间重新分配给其余可见内容(例如,侧边栏仅显示为“上方”),因此到目前为止我发现的所有示例均未达到我所描述的目标...

1 个答案:

答案 0 :(得分:3)

请检查以下HTMLJSCSS代码段。您可以更改元素的实际宽度以完全匹配所需的宽度。

操纵侧边栏的width没问题。如您提供的link中所述,性能是。在本文的最后几行中,它写为:

性能对用户很重要。 Web开发人员需要构建能够 反应迅速,渲染流畅。 Google性能大师Paul Lewis 在这里可以帮助您消除垃圾邮件并创建可保持60 每秒帧数性能。您将使用工具离开本课程 您需要分析应用程序并找出造成垃圾的原因。你会 探索浏览器的渲染管道并发现模式 使构建高性能应用程序变得容易。

因此,您可以使用here来使用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');
  }
});
.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;
}
<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>

这是另一种可能的方式,主要使用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');
  }
});
.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;
}
<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>