如何以显示结尾为不透明度 0 制作过渡效果:无?

Posted

技术标签:

【中文标题】如何以显示结尾为不透明度 0 制作过渡效果:无?【英文标题】:how can I make a transition effect to opacity 0 with ending in display: none? 【发布时间】: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 谁能做到? 【参考方案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 完成。

你可以:

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

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

    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 结尾,那么我很抱歉,但我无法帮助您。

以上是关于如何以显示结尾为不透明度 0 制作过渡效果:无?的主要内容,如果未能解决你的问题,请参考以下文章

CSS不透明度忽略过渡时间

透明背景div上的背景颜色过渡效果?

css img过渡为不透明度

ULEAD GIF如何制作模糊过渡和透明过渡

如何让父层DIV的滤镜效果不影响到子层DIV,就是说避免父层透明度的继承问题

在显示上执行过渡效果:使用 hack 的无元素