如何實現元素顯隱切換的過渡效果
最近看到餓了麼App和h5站上,在商家詳情頁點餐之後,底部放置了一個點擊之後能夠彈出模態框查看點餐詳情的元素,其中有個背景遮罩層的漸進顯隱的效果。
、
憑著我少許的經驗,第一時間的想法是覺得這個遮罩層應該是用display:none;來控制隱藏和顯示的,但是這個屬性會破壞transition動畫,也就是說如果遮罩層是使用了這個屬性來控制顯示與隱藏,那麼漸進顯隱的效果似乎很難達到,效果應該是瞬間顯示與隱藏才對。
使用Chrome 模擬移動端,查看了一下餓了麼的實現方式,這才想到餓了麼用到了vue,此動畫效果其實是利用了vue自帶的過渡動畫和鉤子函數實現的。
框架實作
基於 vue的動畫漸隱實作
利用框架實作這種效果真的是 so easy,不逼逼上程式碼。
// HTML<p id="app"> <button class="btn" @click="show = !show">click</button> <transition name='fade'> <p class="box1" v-if="show"></p> </transition> </p>// CSS.box1 { width: 200px; height: 200px; background-color: green; } .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-to{ opacity: 0; }
無圖無真相,看看效果助助興:
# 簡直不能更簡單
基於react的動畫漸隱實現
react本身的單獨庫沒有自帶過渡動畫,不過有個Animation Add-Ons: react-addons-css-transition-group
import React, {Component} from 'react'import ReactDOM from 'react-dom'import ReactCSSTransitionGroup from 'react-addons-css-transition-group'class TodoList extends React.Component { constructor(props) { super(props)this.state = { show: true} } render() {return (<p> <button onClick={this.changeShow.bind(this)}>click</button> <ReactCSSTransitionGroup component="p" transitionName="fade" transitionEnterTimeout={500} transitionLeaveTimeout={300}> { this.state.show && <p className="box1"> </p> } </ReactCSSTransitionGroup> </p>) } changeShow() {this.setState({ show: !this.state.show }) } }
樣式如下:
.box1 { width: 100px; height: 100px; background-color: green; transition: opacity .5s; } .fade-leave.fade-leave-active, .fade-enter { opacity: 0; } .fade-enter.fade-enter-active, .fade-leave { opacity: 1; }
依舊是很easy
##原生實作
以上都是框架實現,但如果專案歷史悠久,根本就沒用到這些亮瞎人眼的框架,充其量用了個1.2版本的jquery,那麼上面方法可都用不到了,我希望找到一種通用的原生方式,不利用任何框架。
visibility 取代display
其中一個方案如題所示,因為visibility這個屬性同樣能夠控制元素的顯隱,而且, visibility屬性在值visible 與hidden的來回切換中,不會破壞元素的transition 動畫。
不過 visibility與 display 之間控制元素顯隱的最終效果還是有些差異的。
設定了visibility:hidden; 的元素,視覺上確實是不可見了,但是元素仍然佔據該佔據的位置,仍然會存在於文檔流中,影響頁面的佈局,只不過設置了此屬性的元素在視覺上看不到,在頁面的原始位置上留下一片空白而已(如果此元素具有寬高並且使用預設定位)。
而設定了 display:none;的元素,其既視覺上不可見,同時也不會佔據空間,也就是說已經從文檔流中消失了。
visibility控制元素顯隱同樣是瞬時發生的,不過這種瞬時發生的情況又和display的那種瞬時發生不太一樣, display是根本不會理會設定的transition過渡屬性,設定了也跟沒設定一樣。
但 visibility是有可能會理會這個值的,不過只理會 過渡時間 transition-duration這個屬性。
例如,從visibility:hidden到visibility:visible;變化時,如果設定了過渡時間為3s,那麼在事件發生後,元素並不會立即呈現出從hidden到visible的效果,而是會像下圖一樣,先等待3s,然後再瞬間隱藏,從顯示到最終消失視線中的時間確實3s,只不過並不是逐漸過渡出現的。
#
上圖似乎有個問題,從顯示到隱藏確實是等待了3s,但從隱藏到顯示,好像還是瞬間完成的,並沒有等待3s的說法。
視覺上確實是這樣,不過這也只是視覺上的感覺而已,實際上這個等待時間真實存在的,只是看不到而已,另外,這裡的等待也不是真的什麼都沒做純粹的等待。
之所以 display会破坏 transition动画,有个说法是,因为 transition对元素在整个过渡过程中的状态控制,是根据元素过渡前后起始的状态来计算得出的,例如从 opacity:0 到 opacity:1的变化,用时 3s,那么 transition会计算在这 3s内的每一帧画面中元素该有的 opacity值,从而完成过渡效果,其他的一些属性,例如 width、 scale、 color等都可以转化为数字进行计算 (说明文档参见), 但 display是个尴尬的属性,从 display:none到 display:block 该怎么计算值呢?
计算不了,所以就只能 破坏了, visibility同样如此,只不过 visibility比 display稍好一点,因为最起码 visibility不会破罐子破摔,不会搞破坏。
从 visibility:hidden到 visibility:visible的过程中。因为没办法计算过渡阶段没帧的值,所以元素就直接显示出来了,但内在的过渡操作依旧在元素显示出来后显示了 3s,而从 visibility:visible 到 visibility:hidden,元素在视觉上看起来等待的 3s内,实际在内部已经在进行 transition过渡操作,只不过还是因为没办法计算值,所以到了过渡阶段的最后一刻时,就直接将元素设置为结束状态,也就是隐藏了。
想要验证这种说法,还需要配合另外一个属性: opacity,此属性也是配合 visibility完成过渡效果的搭配属性。
实现代码如下
// HTML<button class="btn">click</button> <p class="box1"></p>
// CSS.box1 { width: 200px; height: 200px; background-color: green; opacity: 0; visibility: hidden; transition: all 2s linear; } .show { opacity: .6; visibility: visible; }
js控制显隐效果代码如下:
let box1 = document.querySelector('.box1') let btn = document.querySelector('button') btn.addEventListener('click', ()=>{ let boxClassName = box1.className boxClassName.includes('show')? box1.className = boxClassName.slice(0, boxClassName.length-5) : box1.className += ' show'})
效果依旧没问题:
因为虽然 visibility没办法计算值,但 opacity可以,过渡的效果实际上是 opacity在起作用。
其实 opacity本身就能控制元素的显隐,把上面代码中的所有 visibility 全部删除,效果依旧不变,并且和 visibility 一样,设置了 opacity:0; 的元素依旧存在于文档流中, but,相比于 visibility:hidden, opacity:0 的元素并不会出现点透。
而 visibility:hidden的元素就会出现点透,点击事件会穿透 visibility:hidden的元素,被下面的元素接收到,元素在隐藏的时候,就不会干扰到其他元素的点击事件。
关于这个说法,似乎网上有些争论,但是我用迄今最新版的 Chrome Firefox 以及 360浏览器 进行测试, 都是上面的结果。
如果你只是想让元素简单的渐进显隐,不用管显隐元素会不会遮挡什么点击事件之类的,那么完全可以不用加 visibility 属性,加了反而是自找麻烦,但是如果需要考虑到这一点,那么最好加上。
setTimeOut
如果不使用 visibility的话还好,但是如果使用了此属性,那么上述的解决方案其实还有点小瑕疵,因为 visibility从 IE10以及 Android4.4才开始支持,如果你需要支持这种版本的浏览器,那么 visibility 就派不上用场了。
哎呦呦,公司网站最低要求都是 IE9,用不了了诶。
怎么办?再回到 display 这个属性上。
为什么 display 这个属性会影响到 transition 动画的原因上面已经大致说了下,既然问题是出在了 display上,那么我可以同样参考上面 visibility的做法,加个 opocity属性进行辅助,又因为考虑到 display 比起 visibility 来说破坏性较大,所以再让 opocity 与 display 分开执行不就行了吗?
你如果写成这种形式:
box1.style.display='block'box1.style.opacity=1
其实还是没用的,尽管 display值的设定在代码上看起来好像是在 opacity前面,但是执行的时候却是几乎同时发生的。
我的理解是应该是浏览器对代码进行了优化,浏览器看到你分两步为同一个元素设置 CSS属性,感觉有点浪费,为了更快地完成这两步,它帮你合并了一下,放在一个 tick(参见 [ http://md.barretlee.com/(http://www.infoq.com/cn/articles/javascript-high-performance-animation-and-page-rendering ] )内执行,变成一步到位了,也就是同步执行了这两句代码。
那么如何明确地让浏览器不要合并到一个 tick内执行呢? setTimeOut就派上了用场。
setTimeOut 一个重要功能就是延迟执行,只要将 opacity属性的设置延迟到 display后面执行就行了。
// CSS.box1 { width: 200px; height: 200px; background-color: green; display: none; opacity: 0; transition: all 2s linear; }
下面是控制元素渐进显示的代码:
// JSlet box1 = document.querySelector('.box1') let btn = document.querySelector('.btn') btn.addEventListener('click', ()=>{ let boxDisplay = box1.style.displayif(boxDisplay === 'none') { box1.style.display='block' setTimeout(()=> { box1.style.opacity = 0.4}) } })
上述代码中,最关键的就是 setTimeOut 这一句,延迟元素 opacity属性的设定。
setTiomeOut的第二个可选的时间 delay参数,我在最新版的 Chrome和 360 浏览器上测试,此参数可以不写,也可以写成 0或者其他数值,但是在 firefox上,此参数必须写,不然渐进效果时灵时不灵,而且不能为 0,也不能太小,我测出来的最小数值是 14,这样才能保证渐进效果,所以为了兼容考虑,最好还是都统一加上时间。
至于为什么是 14,我就不清楚了,不过记得以前看过一篇文章,其中说 CPU能够反应过来的最低时间就是 14ms,我猜可能与这个有关吧。
显示的效果有了,那么要隐藏怎么办? setTimeOut 当然也可以,在 JS代码的 if(boxDisplay==='none')后面再加个 else
else { box1.style.opacity = 0 setTimeout(()=>{ box1.style.display = 'none' }, 2000) }
隐藏时先设置 opacity,等 opacity过渡完了,再设置 display:none;。
但是这里有点不太合理,因为虽然 setTimeOut的 delay参数 2000ms和 transition 时间 2s一样大,但因为 JS是单线程,遵循时间轮询,所以并不能保证 display属性的设置刚好是在 opacity过渡完了的同时执行,可能会有更多一点的延迟,这取决于过渡动画完成之刻, JS主线程是否繁忙。
当然,就算是延迟,一般也不会延迟多长时间的,人眼不太可能感觉得到,如果不那么计较的话其实完全可以无视,但是如果我就吹毛求疵,要想做到更完美,那怎么办?
transitionend
transition 动画结束的时候,对应着一个事件: transitionend,MDN [ https://developer.mozilla.org/en-US/docs/Web/Events/transitionend ] 上关于此事件的详细如下:
transitionend 事件会在 CSS transition 结束后触发. 当 transition完成前移除 transition时,比如移除 css的 transition-property 属性,事件将不会被触发,如在 transition完成前设置 display:none,事件同样不会被触发。
如果你能够使用 transition,那么基本上也就能够使用这个事件了,只不过此事件需要加前缀的浏览器比较多(现在最新版的所有 主流浏览器,都已经不用写前缀了),大致有如下写法:
transitionend webkitTransitionEnd mozTransitionEnd oTransitionEnd
使用此属性,就可以避免上面 setTimeOut可能出现的问题了 ,使用示例如下:
// ...else { box1.style.opacity = 0 box1.addEventListener('transitionend', function(e) { box1.style.display = 'none'}); }
需要注意的是, transitionend 事件监听的对象是所有 CSS中transition属性指定的值,例如,如果你为元素设置了 transition:all3s;的 样式,那么元素可能无论是 left top还是 opacity 的改变,都会触发该事件,也就是说此事件可能会被触发多次,并且并不一定每次都是你想要触发的,针对这种情况,最好加一个判断。
既然是 涉及到了 JS实现的动画,那么其实可以考虑一下 把 setTimeout换成 requestAnimationFrame。
btn.addEventListener('click', ()=>{ let boxDisplay = box1.style.displayif(boxDisplay === 'none') { box1.style.display='block'// setTimeOut 换成 requestAnimationFrame requestAnimationFrame(()=> { box1.style.opacity = 0.6}) } else { box1.style.opacity = 0 box1.addEventListener('transitionend', function(e) { box1.style.display = 'none'}); } })
文章最开始说过的 vue 和 react这两个框架实现示例动画的方法,也利用到了这个 API,,监听动画过渡的状态,为元素添加和删除一系列过渡类名的操作,当然,并不是全部,此事件只能监听动画结束的这个时刻,其他时间点是无法监听的。
以下为 transitionEnd 在 react-addons-css-transition-group源码里面出现的形式:
react-addons-css-transition-group对 transitionend做了兼容,如果浏览器支持此属性,则使用,如果不支持,就使用 setTimeOut这种形式。
以下为 transitionEnd 在 vue源码里面出现的形式:
另外,順帶一提的是,除了transitionend 事件,還有一個animationend [ https://developer.mozilla.org/en-US/docs/Web/Events/animationend ] 事件,此事件是對應animation動畫, react-addons-css-transition-group 和vue中也都對應著transitionend 出現了此屬性的身影,這裡就不展開了。
以上是如何實現元素顯隱切換的過渡效果的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

CSS過渡效果:如何實現元素的淡入淡出效果引言:在網頁設計中,使元素具備過渡效果是提升使用者體驗的重要手段之一。而淡入淡出效果是一種常見而又簡潔的過渡效果,能夠使元素從無到有、由淺入深的顯示。本文將介紹如何使用CSS來實現元素的淡入淡出效果,並給出具體的程式碼範例。一、使用transition屬性實現元素的淡入淡出效果CSS的transition屬性可以為元素添

小米14Ultra是今年小米中非常火熱的機型之一,小米14Ultra不僅升級了處理器以及各種配置,而且還為用戶們帶來了很多新的功能應用,從小米14Ultra銷售就可以看出來手機的火爆程度,不過有一些常用的功能可能你還沒了解。那麼小米14Ultra如何切換4g和5g呢?下面小編就來為大家介紹一下具體的內容吧!小米14Ultra怎麼換4g和5g? 1.打開手機的設定選單。 2、設定選單中尋找並選擇「網路」、「行動網路」的選項。 3.在行動網路設定中,會看到「首選網路類型」選項。 4、點選或選擇該選項,會看到

Win11家庭版怎麼轉換成Win11專業版?在Win11系統中,分為了家庭版、專業版、企業版等,而大部分Win11筆電都是預先安裝Win11家用版系統。而今天小編就帶給大家win11家庭版切換專業版操作步驟!1、先在win11桌面此電腦上右鍵屬性。 2、點選更改產品金鑰或升級windows。 3、然後進入後點選更改產品金鑰。 4.再輸入啟動金鑰:8G7XN-V7YWC-W8RPC-V73KB-YWRDB,選擇下一步。 5.接著就會提示成功,這樣就可以將win11家用版升級win11專業版了。

很多朋友剛接觸win系統的時候可能用不習慣,電腦裡存雙系統,這時候其實是可以雙系統切換的,下面就一起來看看兩個系統切換的詳細步驟吧。 win10系統如何兩個系統切換方法一、快捷鍵切換1、按下“win”+“R”鍵開啟運行2、在運行框中輸入“msconfig”點擊“確定”3、在打開的“系統配置”介面中選擇自己需要的系統點擊“設為預設值”,完成後“重新啟動”即可完成切換方法二、開機時選擇切換1、擁有雙系統時開機會出現一個選擇操作介面,可以使用鍵盤“上下”鍵進行選擇系統

蘋果雙系統開機怎麼切換蘋果電腦作為一款功能強大的設備,除了搭載自家的macOS作業系統外,也可以選擇安裝其他作業系統,例如Windows,從而實現雙系統的切換。那麼在開機時,我們要如何切換這兩個系統呢?本文就來為大家介紹一下在蘋果電腦上如何實現雙系統的切換。首先,在安裝雙系統之前,我們需要確認自己的蘋果電腦是否支援雙系統切換。一般來說,蘋果電腦都是基於

在excel軟體的應用程式裡,我們已經習慣使用快捷鍵,讓有些操作變得更簡單和快捷,excel的多個表格之間有時候會有相關的數據,我們在查看時,要不停的切換工作簿,如果有更快捷的切換方法,就會省下很多切換浪費的時間,對工作效率的提高有很大的幫助,什麼辦法可以完成快速的切換呢,針對這個問題,小編今天要講的內容是:excel切換工作簿快速鍵的使用方法。 1.首先在開啟的excel表格的下方可以看到有多個工作簿,需要快速切換不同的工作簿,如下圖所示。 2、然後按下鍵盤上的Ctrl鍵不動,如果需要向右選擇工作

win11支援使用者使用alt+tab快捷鍵的方式來調出桌面切換工具,但是最近有朋友遇到了win11alt+tab切換不了介面的問題,不知道是什麼原因也不知道怎麼解決。 win11alt+tab切換不了介面什麼原因:答:因為快捷鍵功能被停用了,以下是解決方法:1、首先我們按下鍵盤「win+r」開啟運作。 2、接著輸入「regedit」並回車打開群組原則。 3.然後進入“HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer”

隨著智慧型手機的迅速發展,華為作為一家領先的科技公司,推出了許多備受歡迎的手機產品。其中,華為雙系統是一項讓許多用戶感到興奮的功能。透過華為雙系統,使用者可以在同一台手機上同時運行兩個作業系統,例如Android和HarmonyOS。這個功能可以帶來更大的靈活性和便利性。那麼,華為雙系統如何切換設定?讓我們來一起了解一下。首先,在華為手機上切換到雙系統設定之前,
