【问题标题】:how can I make a transition effect to opacity 0 with ending in display: none?如何以显示结尾为不透明度 0 制作过渡效果:无?
【发布时间】:2021-01-07 05:47:04
【问题描述】:

使用此代码,我正在模拟sidemenu,因此如果我单击包含overlaybutton,则将打开包含sidemenu 并且sidemenu 向右移动。如果我clickoutsideoverlay 消失,菜单返回到初始位置。

.html

<div class="menuside_container" (click)="fn_hideSideMenu()" [ngClass]="showSideMenuContainer?showSideMenuContainer:''">
  <div class="menuside" [ngClass]="{showmenu:showMenu, hidemenu:!showMenu}">
    

    <a  class="menu-item d-block" style="height:46px">
      option 1
    </a>
    <a  class="menu-item d-block" style="height:46px">
      option 2
    </a>
    <a  class="menu-item d-block" style="height:46px">
      option 3
    </a>
    <hr class="m-0">
  </div>

</div>
<button (click)="fn_showSideMenu()">show menu</button>

.ts

showMenu: boolean = false;
showSideMenuContainer: any = "d-none";

 fn_showSideMenu() {
  setTimeout(() => {
    this.showMenu = true;
  });
  this.showSideMenuContainer = "d-block";
}
fn_hideSideMenu() {
  this.showMenu = false;
  setTimeout(() => {
    this.showSideMenuContainer = "d-none";
  }, 400);
}


.menuside {
  position: absolute;
  top: 0px;
  width: 304px;
  transition: all 0.3s linear;
  background-color: #eaeaea;
  height: 100%;
}

.menuside_container {
  position: fixed;
  left: 0px;
  top: 0px;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 999;
}

.css

.showmenu {
  left: 0px;
}

.hidemenu {
  left: -500px;
}

此代码有效,但我认为我使事情复杂化了很多,也许我不需要将代码放在我的 .ts 中,但我的想法是,我只想知道我是否可以解决相同的效果有来自css 和/或htmlangular 代码

我希望当我单击button 以显示overlay 然后从sidemenu 向右过渡,当我单击覆盖显示后,它将显示从我的过渡sidemenu 到它的起点。

关于问题标题,我之所以这么说是因为如果我把一个display: none开头的.menuside_containersidemenu的过渡不会显示出来

谢谢。 我只是在为我的问题寻找最佳解决方案

这是我的实时代码(见app/app.component.html/ts/css):

https://stackblitz.com/edit/angular-ng-bootstrap-wa3xto?file=app%2Fapp.component.html

注意:

我基本上想做 gif 中显示的内容,但以更优化的方式。我使用setTimeouts 来实现它。但正如问题所说,我对如何将具有不透明度效果的元素从 1 转换为 0 但最后具有属性 display: none 很感兴趣。为什么?我想完全隐藏一个元素,但是使用opacity: 0 它仍然会占据space,即使它不可见

【问题讨论】:

  • 嘿@yavg,你能澄清一下你的问题,或者至少进一步解释一下吗??
  • 我认为你应该使用角度动画,而不是 CSS 会更有效。
  • @OwaisAhmedKhan 朋友,我基本上想做 gif 中显示的内容,但以更优化的方式。我使用settimeouts 来实现它。但正如问题所说,我对如何将具有不透明度效果的元素从 1 转换为 0 但最后具有属性 display: none 很感兴趣。为什么?我想完全隐藏一个元素,但是使用opacity: 0 它仍然会占据空间,即使它不可见
  • 我认为,更好的方法是在您的菜单上用animationend 事件替换setTimeout
  • @CedricCholley 谁能做到?

标签: css angular


【解决方案1】:

您可以使用非常简单的基于 html 和 CSS 的动画菜单。看看这个来自你的stackblitz

例如:

function closeMenu() {
  document.querySelector(".menuside_container").classList.add("hidemenu");
  document.querySelector(".menuside_container").classList.remove("showmenu");
}

function showMenu() {
  document.querySelector(".menuside_container").classList.remove("hidemenu");
  document.querySelector(".menuside_container").classList.add("showmenu");
}
body,
html {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px;
  background: blue;
}

@keyframes menuOpen {
  from {
    opacity: 0.5;
    transform: translateX(-500px);
    display: none;
  }
  to {
    opacity: 1;
    transform: translatX(0);
    display: block;
    background-color: rgba(0, 0, 0, 0.5);
  }
}

@keyframes menuClose {
  from {
    opacity: 1;
    transform: translateX(0);
    display: block;
  }
  to {
    opacity: 0.5;
    transform: translateX(-500px);
    display: none;
    z-index: -1;
    background-color: transparent;
  }
}

.menuside {
  position: absolute;
  top: 0px;
  width: 304px;
  height: 100%;
  background-color: #eaeaea;
}

.menuside_container {
  position: fixed;
  top: 0px;
  width: 100%;
  height: 100%;
  z-index: 999;
}

.showmenu,
.hidemenu {
  animation-duration: 0.4s;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

.showmenu {
  animation-name: menuOpen;
}

.hidemenu {
  animation-name: menuClose;
}

.d-block {
  display: block;
}
<div class="menuside_container hidemenu" onclick="closeMenu()">
  <div class="menuside">
    <a class="menu-item d-block" style="height:46px">
      option 1
    </a>
    <a class="menu-item d-block" style="height:46px">
      option 2
    </a>
    <a class="menu-item d-block" style="height:46px">
      option 3
    </a>
    <hr class="m-0">
  </div>

</div>
<button onclick="showMenu()">show menu</button>

【讨论】:

  • 当然你可以在Angular中使用jQuery,但你应该避免这样做
  • @Eliseo 它不需要 jQuery。在我的纯 HTML 示例中,我只是使用它来添加和删除类。将我的示例更新为仅包含香草 JS。此外,如果您查看 stackblitz 代码,它没有 jQuery 作为依赖项。
  • 是的,抱歉,我看到document.querySelector 让我抓狂:) (无论如何,我认为这不是“Angular 方式”,-在 Angular 方式中,您可以使用 ViewChildren-)
  • @Eliseo 确定我没有在仅 html css 代码中使用角度。你有没有看过附加的 stablitz?
  • 是的!,[ngClass] 是“Angular 方式”,我喜欢你在 stackblitz 中的解决方案 :) -对不起,我只看到了答案-
【解决方案2】:

您实际上已经实现了您想要做的事情。如果你检查控制台,你会看到.menuside_container在动画运行之前有display:none,并在菜单关闭后恢复到这个。这是因为您正在对其应用 d-none 类,该类应用以下声明:display: none!important;

您还可以采取其他措施来改进您的代码。正如其他人指出的那样,Angular 确实有自己的动画系统,您可能想研究一下。此外,您可以使用translateX() 函数代替使用left 属性来制作动画,这被认为具有更高的性能。这是通过进行以下更改来实现的:

.showmenu {
  /* left: 0px; */
  transform: translateX(0)
}

.hidemenu {
  /* left: -500px; */
  transform: translateX(-500px)
}

【讨论】:

    【解决方案3】:

    如果您希望display: none 阻止点击该元素,您可以使用pointer-events: none;

    您还可以有一个类来显示菜单并假设正常状态是隐藏的。

    所以我的建议是

    .menuside {
      [...]
      transition: transform 0.3s linear;
      [...]
      transform: translateX(-500px)
    }
    
    .menuside_container {
      [...]
      pointer-events: none;
      background-color: rgba(0, 0, 0, 0.5);
      transition: opacity 0.3s linear;
      opacity: 0;
    }
    
    .menuside.showmenu {
      transform: translateX(0)
    }
    
    .menuside_container.showmenu {
      pointer-events: auto;
      opacity: 1;
    }
    

    .ts 中的函数只需设置showMenu 属性

    
     fn_showSideMenu() {
       this.showMenu = true;
     }
     fn_hideSideMenu() {
       this.showMenu = false;
     }
    

    html 是:

    <div class="menuside_container" (click)="fn_hideSideMenu()" [ngClass]="{showmenu:showMenu}">
      <div class="menuside" [ngClass]="{showmenu:showMenu}">
        <a  class="menu-item d-block" style="height:46px">
          option 1
        </a>
        <a  class="menu-item d-block" style="height:46px">
          option 2
        </a>
        <a  class="menu-item d-block" style="height:46px">
          option 3
        </a>
        <hr class="m-0">
      </div>
    
    </div>
    <button (click)="fn_showSideMenu()">show menu</button>
    

    你可以看看我在你的 Stackblitz 上制作的叉子

    https://stackblitz.com/edit/angular-ng-bootstrap-rcwejo?file=app/app.component.css

    【讨论】:

      【解决方案4】:

      您可以通过使用JavascriptElement.animate() 或使用CSS 创建相同的动画来做到这一点(您需要两个帮助类,例如关闭,打开)。使用translateX() 而不是left 制作动画。

      只有在动画结束后,您才需要使用animationend 事件才能应用display: none

      此效果不需要某些元素。例如,不需要.menuside_container,只使用了一个简单的帮助类。

      请检查以下示例的逻辑:

      const menuside = document.querySelector('.menuside');
      
      menuside.addEventListener('animationend', () => {
        menuside.style.display = 'none';
      
      });
      
      menuside.addEventListener('click', () => {
        menuside.animate([
          // keyframes
          {
            transform: 'translateX(0)',
            opacity: '1'
          },
          {
            transform: 'translateX(-304px)',
            opacity: '0'
          }
        ], {
          // timing options
          duration: 1000,
          fill: 'forwards',
          direction: 'normal',
          iterations: 1
        });
        menuside.classList.add('closed');
      });
      
      document.querySelector('button').addEventListener('click', () => {
        if (menuside.classList.contains('closed')) {
          menuside.style.display = 'block';
          menuside.animate([
            // keyframes
            {
              transform: 'translateX(0)',
              opacity: '1'
            },
            {
              transform: 'translateX(-304px)',
              opacity: '0'
            }
          ], {
            // timing options
            duration: 1000,
            fill: 'forwards',
            direction: 'reverse',
            iterations: 1
          });
          menuside.classList.remove('closed');
        }
      });
      .menuside {
        position: fixed;
        top: 0;
        left: 0;
        display: block;
        width: 304px;
        background-color: #eaeaea;
        height: 100%;
      }
      
      body {
        width: 100%;
        height: 100%;
        background-color: red;
      }
      
      button {
        position: fixed;
        top: 3rem;
        right: 1rem;
      }
      <div class="menuside">
        <a class="menu-item d-block" style="height:46px">
            option 1
          </a>
        <a class="menu-item d-block" style="height:46px">
            option 2
          </a>
        <a class="menu-item d-block" style="height:46px">
            option 3
          </a>
        <hr class="m-0">
      </div>
      <button>show menu</button>

      【讨论】:

        【解决方案5】:

        这很好用,我得到了与你的 gif 中显示的相同的东西,但没有使用 setTimeout,但正如你所看到的,尽管在 @keyframes 中使用了等于 none 的显示属性,但它不会显示任何更改,因为显示属性是不可动画 .要查看动画属性的完整列表,请访问https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties

        var overlay=document.getElementById('overlay');
            var menuside=document.getElementById('menuside');
            
            function show_menu(){
        overlay.style.display="block";
            overlay.style.animation="show_overlay 0.6s 1";
            overlay.style.animationFillMode="forwards";
            menuside.style.animation="show_menu_pane 0.6s 1";
            menuside.style.animationFillMode="forwards";
        
        }
            
            function hide_menu(){
            menuside.style.animation="hide_menu_pane 0.6s 1";
            menuside.style.animationFillMode="forwards";
            overlay.style.animation="hide_overlay 0.6s 0.3s 1";
            overlay.style.animationFillMode="forwards";
            
            }
        *{
                    
                    margin: 0px;
                    padding: 0px;
                    font-family: 'Arial';
                }
                body{
                    background-color: blue;
                }
            .menuside {
          position: absolute;
          top: 0px;
          width: 304px;
          transition: all 0.3s linear;
          background-color: #eaeaea;
          height: 100%;
          z-index: 900;
          transform: translateX(-304px);
         
        }
        .menuside li{
            padding: 10px;
        }
        .menuside li a{
          text-decoration: none;
            font-size: 18px;
            color:#707070;
            transition: 0.4s;
        }
        .menuside li a:hover{
            margin-left: 20px;
        }
        .menuside_container {
          position: absolute;
          left: 0px;
          top: 0px;
          width: 100%;
          height: 100%;
          
          z-index:-1;
         
        }
        .overlay{
            display:none;
            position:absolute;
            width:100%;
            height:100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index:8;
            transition:0.6s;
            opacity: 1;
        }
        
        @keyframes hide_overlay
        {
            from
            {
            opacity: 1; 
            display: block;
            z-index: 8;
            }
            to
            {
        opacity: 0;
        display: none;
        z-index: 0;
            }
        }
        
        @keyframes show_overlay
        {
            from
            {
            opacity: 0; 
            z-index: 0;
            }
            to
            {
        opacity: 1;
            z-index: 8;
            }
        }
        @keyframes show_menu_pane
        {
            from
            {
            transform: translateX(-304px);
            }
            to
            {
            transform: translateX(0px);
            }
        }
        @keyframes hide_menu_pane
        {
            from
            {
            transform: translateX(0px);
            }
            to
            {
            transform: translateX(-304px);
            }
        }
        
        
        button{
            position: absolute;
            z-index: 1;
            padding: 10px;
            border:1px solid black;
            font-size: 18px;
            outline: none;
        }
        <div class="menuside_container" >
          <div class="overlay" id="overlay" onclick="hide_menu()"></div>
          <div class="menuside" id="menuside">
            
            <ul>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 1
            </a>
            </li>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 2
            </a>
            </li>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 3
            </a>
            </li>
            <hr class="m-0">
            </ul>
          </div>
        <button onclick="show_menu()">Show Menu</button>
        </div>

        2。 display:none 的另一种替代方法是将宽度和高度设为零,结果将与 gif 相同,但不透明度转换不起作用。

        var overlay=document.getElementById('overlay');
            var menuside=document.getElementById('menuside');
            
            function show_menu(){
        overlay.style.display="block";
            overlay.style.animation="show_overlay 0s 1";    
            overlay.style.animationFillMode="forwards";
            menuside.style.animation="show_menu_pane 0.6s 1";
            menuside.style.animationFillMode="forwards";
            
        }
        
            function hide_menu(){
            menuside.style.animation="hide_menu_pane 0.6s 1";
            menuside.style.animationFillMode="forwards";
            overlay.style.animation="hide_overlay 0s 0.6s 1";
            overlay.style.animationFillMode="forwards";
        
            }
            
            *{
                    
                    margin: 0px;
                    padding: 0px;
                    font-family: 'Arial';
                }
                body{
                    background-color: blue;
                }
            .menuside {
          position: absolute;
          top: 0px;
          width: 304px;
          transition: all 0.3s linear;
          background-color: #eaeaea;
          height: 100%;
          z-index: 900;
          transform: translateX(-304px);
         
        }
        .menuside li{
            padding: 10px;
        }
        .menuside li a{
            font-size: 18px;
            color:#707070;
            text-decoration: none;
            transition: 0.4s;
        }
        .menuside li a:hover{
            margin-left: 20px;
        }
        .menuside_container {
          position: absolute;
          left: 0px;
          top: 0px;
          width: 304px;
          height: 100%;
         
        }
        .overlay
        {
            display:none;
            position:absolute;
            width:100vw;
            height:100vh;
            background-color: rgba(0, 0, 0, 0.5);
            z-index:14;
            transition:0.6s;
        }
        
        @keyframes hide_overlay{
            from{
        width:100vw;
        height:100vh;
            
        }
            to{
        width:0vw;
        height:0vh; 
            }
        }
        @keyframes show_overlay{
            from{
        width:0vw;
        height:0vh;
        }
            to{
        width:100vw;
        height:100vh;   
            }
        }
        @keyframes show_menu_pane
        {
            from
            {
            transform: translateX(-304px);
            }
            to
            {
            transform: translateX(0px);
            }
        }
        @keyframes hide_menu_pane
        {
            from
            {
            transform: translateX(0px);
            }
            to
            {
            transform: translateX(-304px);
            }
        }
        
        
        button{
            position: absolute;
            z-index: 13;
            padding: 10px;
            border:1px solid black;
            font-size: 18px;
            outline: none;
        }
          <div class="overlay" id="overlay" onclick="hide_menu()"></div>  
        
        <div class="menuside_container" >
          
          <div class="menuside" id="menuside">
            <ul>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 1
            </a>
            </li>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 2
            </a>
            </li>
            <li>
            <a href="#/" class="menu-item d-block" style="height:46px">
              option 3
            </a>
            </li>
            <hr class="m-0">
            </ul>
          </div>
        </div>
        <button onclick="show_menu()" id="button">Show Menu</button>

        【讨论】:

          【解决方案6】:

          如果你不仅想不显示,还想从 DOM 中移除,你可以使用 Angular 动画来实现。在你的组件中定义

          @Component({
            selector: "my-app",
            templateUrl: "./app.component.html",
            styleUrls: ["./app.component.css"],
            animations: [
              trigger("menuOpenClose", [
                transition(":enter", [
                  style({ left: "-300px"}), //state initial
                  animate("100ms", style({ left: 0 }))  //animate to a final state
                  ]),
                transition(":leave", [animate("100ms", style({ left: "-300px" }))])
              ])
            ]
          })
          

          所以你只需声明一个变量

          open=false;
          

          还有一个类似的html

          <div @menuOpenClose class="menuside" *ngIf="open">
            <button (click)="open=false">close</button>
          </div>
          <button (click)="open=true">open</button>
          

          very ugly stackblitz

          更新改进“菜单”

          你声明了两个辅助变量

          submenuOpen=false;
          openFinished=false;
          

          还有一个类似的.class

          .fade {
            position: absolute;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.3);
            z-index: 999;
          }
          

          查看 .html - 您使用 open=true 和 (@menuOpenClose.done) 的地方-

          <!--
            if you want close when click in any place of "#menu" add
               (click)="open=false"
            if you want close ONLY y you click in "menu" (but not if click in a button inside "menu") e.g. you has a "submenu"
               (click)="$event.target==menu && open=false"
          -->
          
          <div #menu @menuOpenClose (@menuOpenClose.done)="openFinished=!openFinished" 
                   class="menuside" *ngIf="open"
                   (click)="$event.target==menu && open=false">
              <button (click)="open=false">close</button>
              <div>
                  <button (click)="submenuOpen=!submenuOpen" >menu</button>
              </div>
              <div *ngIf="submenuOpen" (click)="open=false">
                  <hr />
                  <button (click)="doIt('I\'m menu 1')">menu-1</button>
                  <button (click)="doIt('I\'m menu 2')">menu-2</button>
              </div>
          </div>
          <button (click)="open=true">open</button>
          <div class="fade" *ngIf="openFinished" (click)="open=false"></div>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eius
          

          【讨论】:

          • 我觉得这个答案很简单,用最有效的方式解决问题
          【解决方案7】:

          display:none 不受转换速度的影响,因此不能由纯 CSS 完成。

          你可以:

          1. 使用解决方法。 (例如,您可以使用visibility:hidden;width:0;height:0;overflow:hidden;margin:0;,它们会受到转换延迟的影响。

          1. 您可以使用 javascript,就像您在示例中所做的那样,

          1. Angular 本身实际上具有内置动画支持,您可以将其设置为在*ngIf 触发时触发。例如,这里:angular 2 ngIf and CSS transition/animation

          【讨论】:

            【解决方案8】:

            从此 repo 获取代码。你想要的东西是在响应模式下实现的。

            代码:https://github.com/muhammadawaisshaikh/gamelist-ui-test/tree/master/header
            预览直播:https://muhammadawaisshaikh.github.io/gamelist-ui-test/header/

            【讨论】:

            • 谢谢,但我不知道如何做我需要的。以display: none结束的过渡
            • 请不要发布仅链接的答案。相反,请将解决方案包含在您的答案正文中。
            • 您必须将显示属性转换为在您的情况下可以正常工作的可见性。
            【解决方案9】:

            实际上你将不得不使用 translateX 来实现流畅的 60fps 动画。

            您可以在本文 (https://medium.com/outsystems-experts/how-to-achieve-60-fps-animations-with-css3-db7b98610108) 中阅读其背后的理论,或者直接获取文章末尾的代码

            【讨论】:

            • 谢谢,但我不知道如何做我需要的。以display: none结尾的过渡
            • 您面临的问题是无法将显示属性从块切换到无。我分享的文章解释了它。如果您查看代码,您会发现它实现了相同的结果,但方式更高效、更流畅。如果您仍然需要以 display: none 结尾,那么我很抱歉,但我无法帮助您。
            猜你喜欢
            • 2021-01-08
            • 2017-04-15
            • 1970-01-01
            • 2014-05-25
            • 2021-07-26
            • 2015-10-13
            • 2018-08-01
            • 2021-08-02
            • 1970-01-01
            相关资源
            最近更新 更多