A magasság animálása - a helyes út

Legyünk őszinték. A magasság animálása hatalmas fájdalmat okozhat. Számomra állandó küzdelem volt az, hogy szeretnék-e szép animációkat készíteni, és hogy nem vagyok hajlandó megfizetni az animációs magassággal járó hatalmas teljesítményköltségeket. Most - ez minden kész.

Az egész akkor kezdődött, amikor a mellékprojektemen dolgoztam - egy önéletrajz készítővel, ahol megoszthatja az önéletrajzához tartozó linkeket, amelyek csak egy bizonyos ideig aktívak.

Szerettem volna egy szép animációt készíteni az önéletrajz összes szakaszához, és felépítettem egy reakció komponenst, amely az animációt végrehajtotta. Hamarosan rájöttem, hogy ez az összetevő abszolút rombolta a teljesítményt az alsó kategóriás eszközökön és egyes böngészőkben. A pokolba, még a csúcskategóriás Macbook pro-m is küzdött az animáció sima fps-ével.

Ennek oka természetesen az, hogy a magasság tulajdonság animálása a CSS-ben azt eredményezi, hogy a böngésző drága elrendezési és festési műveleteket végez minden kereten. Van egy fantasztikus szakasz a teljesítmény rendereléséről a Google Web Fundamentals-on, javaslom, hogy nézze meg.

Röviden bár - valahányszor megváltoztat egy geometriai tulajdonságot a css-ben, a böngészőnek ki kell igazítania és számításokat kell végeznie arról, hogy ez a változás hogyan befolyásolja az oldal elrendezését, akkor az oldalt újra meg kell jelenítenie a paint nevű lépésben.

Miért is kellene számolnunk a teljesítménnyel?

Csábító lehet figyelmen kívül hagyni a teljesítményt. Nem bölcs, de csábító lehet. Üzleti szempontból rengeteg időt takarít meg, amelyet egyébként új funkciók felépítésére fordíthat.

A teljesítmény azonban közvetlenül befolyásolhatja az eredményt. Mire jó sok funkció felépítése, ha senki sem használja őket? Az Amazon és a Google által elvégzett több tanulmány szerint ez igaz. A teljesítmény közvetlenül kapcsolódik az alkalmazás használatához és az alsó bevételhez.

A teljesítmény másik oldala ugyanolyan fontos. Fejlesztőként mi vagyunk felelősek azért, hogy az internet mindenki számára elérhető maradjon - azért tesszük, mert helyes. Mivel az internet nem csak neked és nekem szól, hanem mindenki számára.

Addy Osmani kiváló cikkéből kiderül, hogy a csúcskategóriás készülékek jelentősen hosszabb ideig tartanak a javascript elemzése és futtatása a magasabb szintű társaikhoz képest.

Annak elkerülése érdekében, hogy az interneten osztályrész alakuljon ki, kérlelhetetlennek kell lennünk a teljesítményre való törekvésünkben. Számomra ez azt jelentette, hogy kreatívnak kell lennem, és az animációim elérésének másik eszközét kell találnom anélkül, hogy feláldoznék.

Animálja a magasságot a megfelelő módon

Ha nem érdekel a hogyan, és csak egy élő példát szeretne látni, kérjük, olvassa el az alábbi linkeket a bemutató webhelyhez, példákat és egy npm csomagot a reakcióhoz:

  • Demo site a technikát felhasználva
  • Élő példa vanília JS-ben
  • Egyszerű példa a reakcióban
  • NPM csomag és dokumentáció a reakcióhoz

Az a kérdés, amit feltettem magamnak, az volt, hogyan tudnám elkerülni az előadás költségeit, amelyek a magasság animálásával merülnek fel. Egyszerű válasz - nem lehet.

Ehelyett kreatívnak kellett lennem más CSS-tulajdonságokkal, amelyek nem merítik fel ezeket a költségeket. Mégpedig átalakul.

Mivel a transzformációknak nincs módjuk befolyásolni a magasságot. Nem egyszerűen alkalmazhatunk egy egyszerű tulajdonságot egy elemre, és kész. Ennél okosabbaknak kell lennünk.

A magasság performáns animációjának eléréséhez valójában az a tény, hogy a transzformációval hamisítjuk: scaleY. Az animáció több lépésben történik:

Íme egy példa:

 ${this.markup} `
  • Először meg kell kapnunk az elemtartály kezdeti magasságát. Ezután a külső tartály magasságát egyértelművé tesszük erre a magasságra. Ez azt eredményezi, hogy minden változó tartalom túlcsordítja a tárolót, ahelyett, hogy kibővítené a szülőjét.
  • A külső tartály belsejében van egy másik div, amely abszolút helyzetben van, hogy átfogja a div teljes szélességét és magasságát. Ez a mi hátterünk, és méretezésre kerül, ha váltjuk az átalakítást.
  • Van egy belső tartályunk is. A belső tartály tartalmazza a jelölést, és magasságát a benne foglalt tartalomnak megfelelően megváltoztatja.
  • Ez a trükk:  Miután váltottunk egy eseményt, amely megváltoztatja a jelölést, megkapjuk a belső tartály új magasságát, és kiszámoljuk azt az összeget, amelyre a háttérnek méreteznie kell az új magasság befogadásához. Ezután a hátteret az új összeggel skálázzuk Y-ra.
  • A vanília javascriptben ez némi trükköt jelent kettős rendereléssel. Egyszer, hogy megkapja a belső tartály magasságát a skála kiszámításához. Ezután ismét alkalmazzuk a skálát a háttér div-re, hogy az elvégezze az átalakítást.

Élő példát láthat itt a vanília JS-ben.

Ezen a ponton a hátterünket megfelelően méreteztük, hogy megteremtsük a magasság illúzióját. De mi van a környező tartalommal? Mivel az elrendezést már nem módosítjuk, a környező tartalmat nem érintik a változások.

Hogy a környező tartalom mozogjon. Be kell állítanunk a tartalmat a transformY használatával. A trükk az, hogy vegye ki a tartalom által kibővített mennyiséget, és ezzel használja a környező tartalmat átalakításokkal. Lásd a fenti példát.

Animációs magasság a React-ben

Mint korábban említettem, ezt a módszert úgy fejlesztettem ki, hogy egy személyes projekten dolgoztam a React-ben. Ez a bemutató webhely kizárólag ezt a módszert alkalmazza az összes „magassági animációban”. Nézze meg itt a bemutató oldalt.

Miután ezt sikeresen megvalósítottam, időt szántam arra, hogy ezt a komponenst és néhány támogató komponenst hozzáadjak egy kis animációs könyvtárhoz, amelyet a React-ben készítettem. Ha érdekli, a releváns információkat itt találja:

  • itt tekintheti meg az NPM könyvtárát
  • A dokumentáció itt található.

A könyvtár legfontosabb összetevői az AnimateHeight és az AnimateHeightContainer. Vizsgáljuk meg őket:

// Inside a React component // handleAnimateHeight is called inside AnimateHeight and is passed the // transitionAmount and optionally selectedId if you pass that as a prop to // AnimateHeight. This means that you can use the transitionAmount to // transition your surrounding content.const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; // Takes a style prop, a shouldchange prop and a callback. shouldChange // determines when the AnimateHeight component should trigger, which is // whenever the prop changes. The same prop is used to control which // content to show.  {this.state.open && } {!this.state.open && } 
  • Példa a környező tartalom mozgatására

A fenti példák bemutatják, hogyan kell használni az AnimateHeight alkalmazást, és a környező tartalmat manuálisan aktiválni a beállításhoz. De mi van akkor, ha sok tartalma van, és nem akarja ezt a folyamatot manuálisan elvégezni? Ebben az esetben használhatja az AnimateHeight-ot az AnimateHeightContainer-rel együtt.

Az AnimateHeightContainer használatához meg kell adnia az összes legfelső szintű gyermeknek az animateHeightId nevű támaszt, amelyet át kell adni az AnimateHeight összetevőinek is:

// Inside React Component const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; // AnimateHeight receives the transitionAmount and the active id of the AnimateHeight that fired. {this.state.open &&  {!this.state.open && }  // When AnimateHeight is triggered by state change // this content will move because the animateHeightId // is greater than the id of the AnimateHeight component above I will move I will also move 

Amint ebből a példából is látható, az AnimateHeight megkapja a tartalom beállításához szükséges információkat, amikor az AnimateHeight komponenst az állapotváltozás váltja ki.

Amint ez megtörténik, az AnimateHeight komponens kiváltja a visszahívást és a tulajdonságokat állapotba állítja. Inside AnimateHeight valami ilyennek tűnik (egyszerűsítve):

// Inside AnimateHeight componentDidUpdate() { if (update) { doUpdate() callback(transitionAmount, this.props.animateHeightId) } } // Equivalent to calling this function: const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; handleAnimateHeight(transitionAmount, this.props.animateHeight)

Most megadja a tartalom pixelben áttelepített összegét és az AnimateHeight összetevő azonosítóját. Miután átadta ezeket az értékeket az AnimateHeightContainer-nek, elveszi őket, és átállítja a többi összetevőt magában, feltéve, hogy növekvő animateHeightIds-t állít be a legfelsőbb szintű gyermekeken.

Haladóbb példák:

  • Moving surrounding content with AnimateHeightContainer
  • Accordion example

NOTE: If you are using this method to animate height and moving surrounding content, you need to add the transition amount to the height of your page.

Conclusion

You may have noticed in this article that we’re not actually animating height — and calling it that is wrong. You are of course, absolutely right. However, I firmly believe that what we call it does not matter. What matters is that we achieve the desired effect with the lowest possible cost to performance.

While I think I found a way that is better than animating the height property directly, I make no claims to have invented or otherwise thought of something that hasn’t been discovered before. Nor do I judge. Perhaps animating height works for you in your scenario — No problem.

All I want is to enable and simplify effects that we all need to do, but sometimes incur costs that are difficult to bear. At the very least, I want to spark a discussion that is worth having. How can we improve the internet for everyone?