Web Animation using JavaScript - Programmer Books€¦ · CHAPTER 2 ANIMATING WITH VELOCITY.JS...
Transcript of Web Animation using JavaScript - Programmer Books€¦ · CHAPTER 2 ANIMATING WITH VELOCITY.JS...
WebAnimationusingJavaScript:DevelopandDesignJulianShapiro
PeachpitPresswww.peachpit.com
Toreporterrors,pleasesendanotetoerrata@peachpit.comPeachpitPressisadivisionofPearsonEducation.
Copyright2015byJulianShapiro
Editor:VictorGavendaDevelopmenteditor:MargaretS.AndersonProjectmanager:MargaretS.AndersonTechnicaleditor:JayBlanchardCopyeditor:GretchenDykstraProductioneditor:DavidVanNessProofreader:PatriciaPaneCompositor:DanielleFosterIndexer:JackLewisCoverdesign:ArenStraigerInteriordesign:MimiHeft
NoticeofRights
Allrightsreserved.Nopartofthisbookmaybereproducedortransmittedinanyformbyanymeans,electronic,mechanical,photocopying,recording,orotherwise,withoutthepriorwrittenpermissionofthepublisher.Forinformationongettingpermissionforreprintsandexcerpts,[email protected].
NoticeofLiability
Theinformationinthisbookisdistributedonan“AsIs”basis,withoutwarranty.Whileeveryprecautionhasbeentakeninthepreparationofthebook,neithertheauthornorPeachpitshallhaveanyliabilitytoanypersonorentitywithrespecttoanylossordamagecausedorallegedtobecauseddirectlyorindirectlybytheinstructionscontainedinthisbookorbythecomputersoftwareandhardwareproductsdescribedinit.
Trademarks
Manyofthedesignationsusedbymanufacturersandsellerstodistinguishtheirproductsareclaimedastrademarks.Wherethosedesignationsappearinthisbook,andPeachpitwasawareofatrademarkclaim,thedesignationsappearasrequestedbytheownerofthetrademark.Allotherproductnamesandservicesidentifiedthroughoutthisbookareusedineditorialfashiononlyandforthebenefitofsuchcompanieswithnointentionofinfringementofthetrademark.Nosuchuse,ortheuseofanytradename,isintendedtoconveyendorsementorotheraffiliationwiththisbook.
ISBN-13:978-0-134-09666-7ISBN-10:0-134-09666-5
987654321
PrintedandboundintheUnitedStatesofAmerica
IdedicatethisbooktopeoplewhoplayCounter-Strike.AndtopeoplewholiketheshowRickandMorty.
Acknowledgements
IwouldliketothankYehonatanDanivforprovidingsupporttoVelocity’susersonGitHub,AnandSharmaforregularlyinspiringmewithhismotiondesignwork,andDavidDeSandroforwritingthisbook’sforeword.I’dalsoliketothankMatVogels,HarrisonShoff,AdamSinger,DavidCaplan,andMuratAyferforreviewingdraftsofthisbook.
Contents
Foreword
Introduction
CHAPTER1ADVANTAGESOFJAVASCRIPTANIMATION
JavaScriptvs.CSSanimation
Greatperformance
Features
Pagescrolling
Animationreversal
Physics-basedmotion
Maintainableworkflows
Wrappingup
CHAPTER2ANIMATINGWITHVELOCITY.JS
TypesofJavaScriptanimationlibraries
InstallingjQueryandVelocity
UsingVelocity:Basics
VelocityandjQuery
Arguments
Properties
Values
Chaining
UsingVelocity:Options
Duration
Easing
BeginandComplete
Loop
Delay
DisplayandVisibility
UsingVelocity:Additionalfeatures
ReverseCommand
Scrolling
Colors
Transforms
UsingVelocity:WithoutjQuery(intermediate)
Wrappingup
CHAPTER3MOTIONDESIGNTHEORY
Motiondesignimprovestheuserexperience
Utility
Borrowconventions
Previewoutcomes
Distractionoverboredom
Leverageprimalinstincts
Makeinteractionsvisceral
Reflectgravitas
Reduceconcurrency
Reducevariety
Mirroranimations
Limitdurations
Limitanimations
Elegance
Don’tbefrivolous
Youroneopportunitytobefrivolous
Considerpersonality
Gobeyondopacity
Breakanimationsintosteps
Staggeranimations
Flowfromthetriggeringelement
Usegraphics
Wrappingup
CHAPTER4ANIMATIONWORKFLOW
CSSanimationworkflow
IssueswithCSS
WhenCSSmakessense
Codetechnique:Separatestylingfromlogic
Standardapproach
Optimizedapproach
Codetechnique:Organizesequencedanimations
Standardapproach
Optimizedapproach
Codetechnique:Packageyoureffects
Standardapproach
Optimizedapproach
Designtechniques
Timingmultipliers
UseVelocityMotionDesigner
Wrappingup
CHAPTER5ANIMATINGTEXT
Thestandardapproachtotextanimation
PreparingtextelementsforanimationwithBlast.js
HowBlast.jsworks
Installation
Option:Delimiter
Option:customClass
Option:generateValueClass
Option:Tag
Command:Reverse
Transitioningtextintooroutofview
Replacingexistingtext
Staggering
Transitioningtextoutofview
Transitioningindividualtextparts
Transitioningtextfancifully
Textualflourishes
Wrappingup
CHAPTER6SCALABLEVECTORGRAPHICSPRIMER
Creatingimagesthroughcode
SVGmarkup
SVGstyling
SupportforSVG
SVGanimation
Passinginproperties
Presentationalattributes
Positionalattributesvs.transforms
Implementationexample:Animatedlogos
Wrappingup
CHAPTER7ANIMATIONPERFORMANCE
Therealityofwebperformance
Technique:Removelayoutthrashing
Problem
Solution
jQueryElementObjects
Force-feeding
Technique:BatchDOMadditions
Problem
Solution
Technique:Avoidaffectingneighboringelements
Problem
Solution
Technique:Reduceconcurrentload
Problem
Solution
Technique:Don’tcontinuouslyreacttoscrollandresizeevents
Problem
Solution
Technique:Reduceimagerendering
Problem
Solution
Sneakyimages
Technique:Degradeanimationsonolderbrowsers
Problem
Solution
Findyourperformancethresholdearlyon
Wrappingup
CHAPTER8ANIMATIONDEMO
Behavior
Codestructure
Codesection:Animationsetup
Codesection:Circlecreation
Codesection:Containeranimation
3DCSSprimer
Properties
Options
Codesection:Circleanimation
Valuefunctions
Opacityanimation
Translationanimation
Reversecommand
Wrappingup
Index
Foreword
It’saspecialtimewhenadeveloperfirstdiscoversjQuery’s.animate().Iremembertryingtoanimateanypartofthepagethatwasn’tboltedtothemaincontent.Icreatedaccordions,fly-outmenus,hovereffects,scrolltransitions,magicalreveals,andparallaxsliders.Turningmywebsitesfromcold,staticdocumentsintomoving,visualexperiencesfeltlikeIwasreachinganotherlevelasawebdesigner.Butitwasjustbellsandwhistles.IrealizenowthatforalltheanimationIadded,Ihadn’tactuallyimprovedtheuserexperienceofmywebsites.
Allthesame,itwasthrilling.Sowhatmakesanimationsoexciting?
MyapartmentlooksoverdowntownBrooklyn.Iseepeoplewalkdownthestreet.Plumesfromsmokestacksbillowup.Pigeonsfluttertoperchonaledge.Aconstructioncraneraisesasectionofabuilding.Asingle,heart-shapedballoonfloatsupintotheBrooklynsky(corny,Iknow,butIliterallysawthishappentwice).CarsdriveovertheWilliamsburgBridge.Cloudspassoverhead.
Theworldisinmotion.
Thisishowyouexpecttheuniversetowork.Thingsmove.Likethemovementsoutsidemywindow,eachoneisaone-sentencestory.Togethertheytellthelargerstoryofwhatishappening.
Yetthisisn’thowdigitalinterfaceswork.Thoselittlestoriesaremissing.Whenthingschange,youhavetofillinthestoryforyourself.WhenyoupresstheNextbuttonatanATM,thescreensuddenlychanges.Diditmoveforwardsuccessfully?Wasthereanerror?Youhavetoreadthescreenagaintointerprettheresultsofyouraction.Utilizingmotionremovesthisleapofunderstandingbetweeninteractions.Motioninherentlycommunicateswhathaschanged.It’slikewritingtinystoriesbetweenstates.
Whenaslidetransitiontakesyoutothenextscreen,animationhelpsyoubetterunderstandwhatjusthappened.Wieldingthispoweriswhatmakesanimationsothrilling.Likelayout,color,andtypography,animationhelpsyoushapeanddirecttheuserexperience.Animationismorethanjustmakingthingsmove.It’sdesigningmoreeffectively,anddoingitthoughtfully.
Unfortunately,inthehistoryofwebanimation,thoughtfulnesshasn’talwaysbeenthehighestpriority.Asdevelopers,we’veusedFlash,animatedGIFs,Javaapplets,marqueetags,and,morerecently,CSS,JavaScript,andSVGtocreateanimationthat’sbeen,atbest,alevelofpolishor,atworst,agimmick.Theideaofcreatinganimationthat’sbothhigh-performanceanduser-friendlyisrelativelynew.
Soit’sagoodthingyouhavethisbookinfrontofyou.JulianShapiroisoneoftheprincipalexpertsonanimationontheweb.IncreatingandsupportingVelocity.js,hehasdevelopedanintimateknowledgeofallthequirksandadvantagesofusingmotiononwebsites.WebAnimationusingJavaScriptwillgiveyounotonlythetechnicalknow-howrequiredtoimplementanimationinyourwebsites,but,moreimportantly,theinsightsyou’llneedtouseanimationeffectivelyandcraftcompellinguserexperiences.
Animationlibrariesandtechnologieshavemademotiondesignmoreaccessiblethanever.Butnoteverydeveloperabidesbybestpractices.Thepastcoupleofyearshaveseenseveraltrendyanti-patternscomeandgo.Scrollbehaviorhasbeenhijacked.Mobilenavigationhasbeenpushedintomenusaccessibleonlyviagestures.Whileaddinganimationiswithinthegraspofanyonewhostumblesacross.animate(),utilizingittoimprovetheuserexperienceisoneofthehallmarksofadedicateddeveloper.Thisbookwillhelpyoubecomeoneofthem.
DavidDeSandroFebruary2015Brooklyn,NewYork
DavidDeSandroisthefounderofMetafizzyandauthor/developerofMasonryandIsotope.
Introduction
Intheearlydaysoftheweb,animationwasprimarilyusedbynovicedevelopersasalast-ditchefforttocallattentiontoimportantpartsofapage.Andeveniftheywantedanimationtotranscenditsniche,itcouldn’t:browsers(andcomputers)weresimplytooslowtodeliversmoothweb-basedanimation.
We’vecomealongwaysincethedaysofflashingbannerads,scrollingnewstickers,andFlashintrovideos.Today,thestunningmotiondesignofiOSandAndroiddramaticallyimprovestheuserexperience—insteadofdetractingfromit.Developersofthebestsitesandappsleverageanimationtoimprovethefeelandintuitivenessoftheiruserinterfaces.Animation’srisetorelevancyisn’tjustaby-productofimprovedprocessingpower;itreflectsabetterappreciationforbestpracticeswithinthewebdevelopmentcommunity.Thetoolsyouusetomakeawebsitearenowconsideredlessimportantthanthequalityoftheresultinguserexperience.Asobviousasthisseems,itwasn’talwaysthecase.
So,whatmakesanimationinparticularsouseful?Whetherit’stransitioningbetweenchunksofcontent,designingintricateloadingsequences,oralertingtheuserwhattodonext,animationcomplementstextandlayouttoreinforceyoursite’sintendedbehavior,personality,andvisualsophistication.Doesyourcontentbounceintoviewinafriendlyway,ordoesitwhipacrossthescreen?Thisisthedomainofmotiondesign,andthedecisionsyoumakewillestablishthetranscendentfeelingofyourapp.
Whenusersrecommendyourapptoothers,they’lloftentrytodescribeitwithwordslike“sleek”or“polished.”Whattheydon’trealizeisthatthey’remostlyreferringtothemotiondesignworkthat’sgoneintotheinterface.Thisinabilityofthelaymantomakethedistinctionispreciselywhatgreatuserinterface(UI)designersstrivefor:animationsthatreinforcetheinterface’sobjectivesbutdon’totherwisediverttheuser’sattention.
Thisbookprovidesyouwiththefoundationnecessarytoimplementanimationconfidentlyandinawaythat’sbothtechnicallymaintainableandvisuallyimpactful.Throughout,itconsidersthebalancebetweenenrichingapagewithmotiondesignandavoidingunnecessaryflourishes.
Whyisallofthissoimportant?Whyisitworthyourtimetoperfectyourtransitionsandeasingcombinations?Forthesamereasonthatdesignersspendhoursperfectingtheirfontandcolorcombinations:refinedproductssimplyfeelsuperior.Theyleaveuserswhisperingtothemselves,“Wow,thisiscool,”rightbeforetheyturntoafriendandexclaim,“Yougottaseethis!”
Note
Ifyou’reunfamiliarwithbasicCSSproperties,youshouldpickupanintroductoryHTMLandCSSbookbeforereadingthisone.
Chapter1.AdvantagesofJavaScriptAnimation
Inthischapter,wecompareJavaScripttoCSSforthepurposesofanimation,andintroducetheuniquefeaturesandworkflowadvantagesprovidedbyJavaScript.
Inshort,weprovidethecontextneededtohelpyouunderstandeverythingyou’lllearnaboutJavaScriptinthisbook.
JavaScriptvs.CSSanimationThere’safalsebeliefinthewebdevelopmentcommunitythatCSSanimationistheonlyperformantwaytoanimateontheweb.ThismisconceptionhasledmanydeveloperstoabandonJavaScript-basedanimationaltogether,forcingthemto
Managetheentiretyofuserinterface(UI)interactionwithinstylesheets,whichcanquicklybecomedifficulttomaintain.
Sacrificereal-timeanimationtimingcontrol,whichisachievableonlywithinJavaScript.(TimingcontrolisnecessaryfordesigninganimationintoUIsthatrespondtoauser’sdraginput,likethosefoundinmobileapps.)
Forgophysics-basedmotiondesign,whichallowselementsonawebpagetobehavelikeobjectsintherealworld.
Losesupportforolderbrowserversions,whichremainpopularthroughouttheworld.
JavaScript-basedanimationisactuallyoftenasfastasCSS-basedanimation.CSSanimationismistakenlyconsideredtohaveasignificantlegupbecauseit’smostoftencomparedtojQuery’sanimationfeatures,whichareinfactveryslow.However,alternativeJavaScriptanimationlibrariesthatbypassjQueryentirelydeliverfantasticperformancebystreamliningtheirinteractionwithapage.
Note
Onelibraryofnote,whichwe’llbeusingthroughoutthisbook,isVelocity.js.It’slightweightyetincrediblyfeaturerich,anditmirrorsjQuery’sanimationsyntaxtohelpeliminatethelearningcurve.
Ofcourse,CSSisperfectlysuitedforhoverstateanimations(turningalinkbluewhenthemouseispositionedoverit,forexample),whichareveryoftentheextenttowhichbasicwebpagesincludeanimation.CSStransitionsfitseamlesslyintoexistingstylesheets,allowingdeveloperstoavoidbloatingtheirpageswithunnecessaryJavaScriptlibraries.What’smore,CSSanimationdeliversblazingperformanceoutofthebox.
ButthisbookwilldemonstratewhyJavaScriptisoftenthesuperiorchoiceforanimationsbeyondsimplehoverstateanimations.
GreatperformanceJavaScriptandjQueryarefalselyconflated.JavaScriptanimationisfast.jQueryslowsitdown.DespitejQuerybeingtremendouslypowerful,itwasn’tdesignedtobeahigh-performanceanimationengine.Ithasnomechanismtoavoid“layoutthrashing,”inwhichabrowserbecomesovertaskedwithlayoutprocessingworkwhileit’sintheprocessofanimating.
Further,becausejQuery’scodebaseservesmanypurposesbeyondanimation,itsmemoryconsumptiontriggersgarbagecollectionswithinthebrowser,causinganimationstostutterunpredictably.Lastly,duetodecisionsmadebythejQueryteaminthenoblepursuitofhelpingnoviceusersavoidsabotagingtheirUIwithbadcode,jQueryforgoestherecommendedpracticeofusingtherequestAnimationFramefunction,whichbrowsersmakeavailabletodrasticallyimproveframeratesforwebanimation.
JavaScriptanimationlibrariesthatbypassjQueryentirelydeliverfantasticperformancebystreamliningtheirinteractionwithapage.Onelibraryofnote,whichwe’llbeusingthroughoutthisbook,isVelocity.js.It’slightweight,yetincrediblyfeaturerich,anditmirrorsjQuery’sanimationsyntaxtohelpeliminatethelearningcurve.
Thisisatopicwe’llexplorein-depthinChapter7,“AnimationPerformance.”Bylearningthenuancesofbrowserrenderingperformance,you’llgainafoundationonwhichtobuildreliableanimationsforallbrowsersanddevices,regardlessoftheirindividualprocessingpower.
FeaturesSpeedis,ofcourse,nottheonlyreasontouseJavaScript—itsabundanceoffeaturesisequallyasimportant.Let’srunthroughafewofthenotableanimationfeaturesthatareexclusivetoJavaScript.
PagescrollingPagescrollingisoneofthemostpopularusesforJavaScript-basedanimation.Arecenttrendinwebdesignistocreatelongwebpagesthatanimatenewpiecesofcontentintoviewasthepageisscrolleddown.
JavaScriptanimationlibraries,suchasVelocity,providesimplefunctionsforscrollingelementsintoview:Clickheretoviewcodeimage
$element.velocity(“scroll”,1000);
Thisscrollsthebrowsertowardthetopedgeof$elementoveradurationof1000msusingVelocity’s"scroll"command.NoticethatVelocity’ssyntaxisnearlyidenticaltojQuery’s$.animate()function,whichiscoveredlaterinthischapter.
AnimationreversalAnimationreversalisausefulshorthandforundoinganelement’spreviousanimation.Byinvokingthereversecommand,you’reinstructinganelementtoanimatebacktoitsvaluespriortoitslastanimation.Acommonuseforreversalisanimatingamodaldialogueintoview,thenhidingitwhentheuserpressestocloseit.
Anunoptimizedreversalworkflowconsistsofkeepingtrackofthespecificpropertiesthatwerelastanimatedoneachelementthatmaylaterbesubjectedtoreversal.Unfortunately,keepingtrackofprioranimationstatesinUIcodequicklybecomesunwieldy.Incontrast,withthereversecommand,Velocityrememberseverythingforyou.
MimickingthesyntaxofVelocity’sscrollcommand,thereversecommandiscalledbypassing"reverse"asVelocity’sfirstargument:Clickheretoviewcodeimage
//Firstanimation:Animateanelement’sopacitytoward0
$element.velocity({opacity:0});
//Secondanimation:Animatebacktowardthestartingopacityvalueof1
$element.velocity(“reverse”);
WhenitcomestoJavaScript’sanimationtimingcontrol,there’smorethanjustreversal:JavaScriptalsoallowsyoutogloballyslowdownorspeedupallJavaScriptanimationscurrentlyrunning.You’lllearnmoreaboutthispowerfulfeatureinChapter4,“AnimationWorkflow.”
Physics-basedmotionTheutilityofphysicsinmotiondesignreflectsthecoreprincipleofwhatmakesforagreatuserexperience(UX)onyoursite:interfacesthatflownaturallyfromtheuser’sinput.Putanotherway,interfacesthatpaytributetohowobjectsmoveintherealworld.
Asasimpleyetpowerfulintroductiontophysics-basedmotionVelocityoffersaneasingtypebasedonspringphysics.(We’llfullyexploretheconceptofeasinginthenextchapter.)Withtypicaleasingoptions,youpassinastringcorrespondingtoapredefinedeasingcurve(forexample,"ease"or"easeInOutSine").Thespringphysicseasingtype,incontrast,acceptsatwo-itemarray.Clickheretoviewcodeimage
//Animateanelement’swidthto“500px”usingaspringphysicseasingof500
tensionsunitsand20frictionunits
$element.velocity({width:“500px”},{easing:[500,20]});
Thefirstitemintheeasingarrayrepresentsthetensionofthesimulatedspringandtheseconditemrepresentsfriction.Ahighertensionvalueincreasesthetotalspeedandbouncinessoftheanimation.Alowerfrictionvalueincreasesthevibrationspeedatthetailendoftheanimation.Bytweakingthesevalues,youcangiveeachanimationonyourpageauniquemovementprofile,whichhelpstoreinforcethedifferentiationbetweentheirindividualbehaviors.
MaintainableworkflowsDesigninganimationisanexperimentalprocessthatrequiresrepeatedtweakingoftimingandeasingvaluestoachieveauniformfeelacrossthepage.Inevitably,justwhenyou’veperfectedyourdesign,aclientwillrequestsignificantchanges.Inthesesituations,maintainablecodebecomescritical.
TheJavaScript-basedsolutiontothisworkflowproblemiswonderfullyelegant,andit’scoveredindepthinChapter4,“AnimationWorkflow.”Fornow,here’stheshortexplanation:TherearetechniquesforchainingtogetherindividualJavaScriptanimations—allwithdifferingdurations,easings,andsoon—suchthatthetimingofoneanimationdoesnotaffectanother.Thismeansyoucanchangeindividualdurationswithoutredoingmathandyoucangobackandeasilysetanimationstoruneitherinparallelorconsecutively.
WrappingupWhendesigninganimationsinCSS,you’reinherentlylimitedtothefeaturesthattheCSSspecificationprovides.InJavaScript,becauseoftheverynatureofprogramminglanguages,third-partylibrarieshaveaninfiniteamountoflogicalcontrolovermotiondesign.Animationenginesleveragethistoprovidepowerfulfeaturesthatdrasticallyimproveworkflowandexpandthepossibilitiesofinteractivemotiondesign.That’swhatthisbookisallabout:Designingbeautifulanimationsasefficientlyaspossible.
Thenextchapterexplainshowtousethisbook’sJavaScriptanimationengineofchoice:Velocity.js.InmasteringVelocity.js,you’llunderstandhowtoleveragethefeatureswe’vejustintroduced,andmanymore.
Chapter2.AnimatingwithVelocity.js
Inthischapter,you’lllearnthefeatures,commands,andoptionsprovidedbyVelocity.js.Ifyou’refamiliarwithjQuery-basedanimation,youalreadyknowhowtouseVelocity;itfunctionsnearlyidenticallytojQuery’s$.animate()function.
Butregardlessofyourexistingknowledge,themethodicalfeaturebreakdownsinthischapterwillintroduceyoutothenuancesofanimationenginebehavior.Masteringthesenuanceswillhelptakeyoufromnovicetoprofessional.Evenifyou’realreadyintimatelyfamiliarwithJavaScriptanimationandVelocity.js,doyourselfafavorandskimthischapter.You’reboundtodiscoversomethingyoudidn’trealizeyoucoulddo.
TypesofJavaScriptanimationlibrariesTherearemanytypesofJavaScriptanimationlibraries.Somereplicatephysicsinteractionsinthebrowser.SomemakeWebGLandCanvasanimationseasiertomaintain.SomefocusonSVGanimation.SomeimproveUIanimation—thislasttypeisthefocusofthisbook.
ThetwopopularUIanimationlibrariesareGSAP(downloaditatGreenSock.com)andVelocity(downloaditatVelocityJS.org).You’llworkwithVelocitythroughoutthisbooksinceit’sfreeundertheMITlicense(GSAPrequireslicensingfeesdependingonasite’sbusinessmodel),plusitboastsincrediblypowerfulfeaturesforwritingcleanandexpressiveanimationcode.It’sinuseonmanypopularsites,includingTumblr,Gap,andScribd.
Oh,anditwascreatedbytheauthorofthisbook!
InstallingjQueryandVelocityYoucandownloadjQueryfromjQuery.com,andVelocityfromVelocityJS.org.Tousethemonyourpage—aswithanyJavaScriptlibrary—simplyinclude<script></script>tagspointingtowardtherespectivelibrariesbeforeyourpage’s</body>tag.Ifyou’relinkingtopre-hostedversionsofthelibraries(asopposedtolocalcopiesonyourcomputer),yourcodemightlooklikethis:Clickheretoviewcodeimage
<html>
<head>MyPage</head>
<body>
Mycontent.
<scriptsrc=”//code.jquery.com/jquery-2.1.1.min.js”></script>
<scriptsrc=”//cdn.jsdelivr.net/velocity/1.1.0/velocity.min.js”>
</script>
</body>
</html>
WhenusingjQueryandVelocitytogether,includejQuerybeforeVelocity.
That’sit!Nowyou’rereadytoroll.
UsingVelocity:BasicsTogetorientedtoVelocity,we’llstartwiththebasiccomponents:arguments,properties,values,andchaining.SincejQueryissoubiquitous,itisalsoimportanttolookattherelationshipbetweenVelocityandjQuery.
VelocityandjQueryVelocityfunctionsindependentlyofjQuery,butthetwocanbeusedincombination.It’softenpreferabletodosotobenefitfromjQuery’schainingcapabilities:Whenyou’vepreselectedanelementusingjQuery,youcanextenditwithacallto.velocity()toanimateit:Clickheretoviewcodeimage
//AssignavariabletoajQueryelementobject
var$div=$(“div”);
//AnimatetheelementusingVelocity
$div.velocity({opacity:0});
ThissyntaxisidenticaltojQuery’sownanimatefunction:
$div.animate({opacity:0});
AlltheexamplesinthisbookuseVelocityincombinationwithjQuery,andthereforefollowthissyntax.
ArgumentsVelocityacceptsmultiplearguments.ItsfirstargumentisanobjectthatmapsCSSpropertiestotheirdesiredfinalvalues.ThepropertiesandtheiracceptedvaluetypescorresponddirectlytothoseusedinCSS(ifyou’reunfamiliarwithbasicCSSproperties,pickupanintroductoryHTMLandCSSbookbeforereadingthisone):Clickheretoviewcodeimage
//Animateanelementtoawidthof“500px”andtoanopacityof1.
$element.velocity({width:“500px”,opacity:1});
Tip
InJavaScript,ifyou’reprovidingapropertyvaluethatcontainsletters(insteadofonlyintegers),putthevalueinquotes.
Youcanpassinanobjectspecifyinganimationoptionsasasecondargument:Clickheretoviewcodeimage
$element.velocity({width:“500px”,opacity:1},{duration:400,easing:
“swing”});
There’salsoashorthandargumentsyntax:Insteadofpassinginanoptionsobjectasasecondargument,youcanusecomma-separatedargumentsyntax.Thisentailslistingvaluesforduration(whichacceptsanintegervalue),easing(astringvalue),andcomplete(afunctionvalue)inanycomma-separatedorder.(You’lllearnwhatalloftheseoptionsdomomentarily.)
Clickheretoviewcodeimage
//Animatewithadurationof1000ms(andimplicitlyusethedefaulteasing
valueof“swing”)
$element.velocity({top:50},1000);
//Animatewithadurationof1000msandaneasingof“ease-in-out”
$element.velocity({top:50},1000,“ease-in-out”);
//Animatewithaneasingof“ease-out”(andimplicitlyusethedefault
durationvalueof400ms)
$element.velocity({top:50},“ease-out”);
//Animatewithadurationof1000msandacallbackfunctiontobetriggered
uponanimationcompletion
$element.velocity({top:50},1000,function(){alert(“Complete.”)});
Thisshorthandsyntaxisaquickwayofpassinginanimationoptionswhenyouonlyneedtospecifythebasicoptions(duration,easing,andcomplete).Ifyoupassinananimationoptionotherthanthesethree,youmustswitchalloptionstotheobjectsyntax.Hence,ifyouwanttospecifyadelayoption,changethefollowingsyntax:Clickheretoviewcodeimage
$element.velocity({top:50},1000,“ease-in-out”);
tothissyntax:Clickheretoviewcodeimage
//Re-specifytheanimationoptionsusedabove,butincludeadelayvalueof
500ms
$element.velocity({top:50},{duration:1000,easing:“ease-in-out”,
delay:500});
Youcan’tdothis:Clickheretoviewcodeimage
//Incorrect:Dividesanimationoptionsbetweenthecomma-separatedsyntax
andtheobjectsyntax
$element.velocity({top:50},1000,{easing:“ease-in-out”,delay:500});
PropertiesTherearetwodifferencesbetweenCSS-basedandJavaScript-basedpropertyanimation.
First,unlikeinCSS,VelocityacceptsonlyasinglenumericvalueperCSSproperty.So,youcanpassin:Clickheretoviewcodeimage
$element.velocity({padding:10});
orClickheretoviewcodeimage
$element.velocity({paddingLeft:10,paddingRight:10});
Butyoucan’tpassin:Clickheretoviewcodeimage
//Incorrect:TheCSSpropertyisbeingpassedmorethanonenumericvalue.
$element.velocity({padding:“10101010”});
Ifyoudowanttoanimateallfourpaddingvalues(top,right,bottom,andleft),
listthemoutasseparateproperties://Correct
$element.velocity({
paddingTop:10,
paddingRight:10,
paddingBottom:10,
paddingLeft:10
});
OthercommonCSSpropertiesthatcantakemultiplenumericvaluesincludemargin,transform,text-shadow,andbox-shadow.
Breakingupcompoundpropertiesintotheirsub-propertiesforthepurposesofanimationgivesyouincreasedcontrolovereasingvalues.InCSS,youcanspecifyonlyoneproperty-wideeasingtypewhenanimatingmultiplesub-propertieswithintheparentpaddingproperty,forexample.InJavaScript,youcanspecifyindependenteasingvaluesforeachsub-property—theadvantagesofthiswillbecomeapparentduringthediscussionofCSStransformpropertyanimationlaterinthischapter.
Listingoutindependentsub-propertiescanalsomakeyouranimationcodeeasiertoreadandeasiertomaintain.
TheseconddifferencebetweenCSS-basedandJavaScript-basedpropertyanimationisthatJavaScriptpropertiesdropthedashesbetweenwordsandallwordspastthefirstmustbecapitalized.Forexample,padding-leftbecomespaddingLeft,andbackground-colorbecomesbackgroundColor.FurthernotethatJavaScriptpropertynamesshouldnotbeinquotes:Clickheretoviewcodeimage
//Correct
$element.velocity({paddingLeft:10});
//Incorrect:Usesadashanddoesn’tcapitalize
$element.velocity({padding-left:10});
//Incorrect:UsesquotesaroundtheJavaScript-formattedpropertyname
$element.velocity({“paddingLeft”:10});
ValuesVelocitysupportsthepx,em,rem,%,deg,vw,andvhunits.Ifyoudon’tprovideaunittypewithanumericvalue,anappropriateoneisautomaticallyassignedbasedontheCSSpropertytype.Formostproperties,pxisthedefaultunit,butapropertythatexpectsarotationangle,suchasrotateZforexample,wouldbeautomaticallyassignedthedeg(degree)unit:Clickheretoviewcodeimage
$element.velocity({
top:50,//Defaultstothepxunittype
left:“50%”,//Wemanuallyspecifythe%unittype
rotateZ:25//Defaultstothedegunittype
});
Explicitlydeclaringunittypesforallpropertyvaluesincreasesyourcode’slegibilitybymakingthecontrastbetweenthepxunitanditsalternativesmoreobviouswhenquickly
eyeballingyourcode.
AnotheradvantageofVelocityoverCSSisthatitsupportsfourvalueoperatorsthatcanbeoptionallyprefixedtoapropertyvalue:+,-,*,and/.ThesedirectlycorrespondtotheirmathoperatorsinJavaScript.Youcancombinethesevalueoperatorswithanequalssign(=)toperformrelativemathoperations.Refertotheinlinecodecommentsforexamples:Clickheretoviewcodeimage
$element.velocity({
top:“50px”,//Nooperator.Animatetoward50asexpected.
left:“-50”,//Negativeoperator.Animatetoward-50asexpected.
width:“+=5rem”,//Convertthecurrentwidthvalueintoitsrem
equivalentandadd5moreunits.
height:“-10rem”,//Convertthecurrentheightvalueintoitsrem
equivalentandsubtract10units.
paddingLeft:“*=2”//DoublethecurrentpaddingLeftvalue.
paddingRight:“/=2”//DividethecurrentpaddingLeftvalueintotwo.
});
Velocity’sshorthandfeatures,suchasvalueoperators,retainanimationlogicentirelywithintheanimationengine.Thisnotonlykeepsthecodemoreconcisebyeliminatingmanualvaluecalculation,butalsoimprovesperformancebytellingVelocitymoreabouthowyouplantoanimateyourelements.ThemorelogicthatisperformedwithinVelocity,thebetterVelocitycanoptimizeyourcodeforhigherframerates.
ChainingWhenmultipleVelocitycallsarechainedback-to-backonanelement(oraseriesofelements),theyautomaticallyqueueontooneanother.Thismeansthateachanimationbeginsoncetheprecedinganimationhascompleted:Clickheretoviewcodeimage
$element
//Animatethewidthandheightproperties
.velocity({width:“100px”,height:“100px”})
//Whenwidthandheightaredoneanimating,animatethetopproperty
.velocity({top:“50px”});
UsingVelocity:OptionsToroundoutthisintroductiontoVelocity,let’srunthroughthemostcommonlyusedoptions:duration,easing,beginandcomplete,loop,delay,anddisplay.
DurationYoucanspecifythedurationoption,whichdictateshowlongananimationcalltakestocomplete,inmilliseconds(1/1000thofasecond)orasoneofthreeshorthanddurations:"slow"(equivalentto600ms),"normal"(400ms),or"fast"(200ms).Whenspecifyingadurationvalueinmilliseconds,provideanintegervaluewithoutanyunittype:Clickheretoviewcodeimage
//Animatewithadurationof1000ms(1second)
$element.velocity({opacity:1},{duration:1000});
orClickheretoviewcodeimage
$element.velocity({opacity:1},{duration:“slow”});
Theadvantagetousingthenamedshorthanddurationsisthattheyexpressthetempoofananimation(isitsloworisitfast?)whenyou’rereviewingyourcode.Ifyouusetheseshorthandsexclusively,they’llalsonaturallyleadtomoreuniformmotiondesignacrossyoursite,sinceallofyouranimationswillfallintooneofthreespeedcategoriesinsteadofeachbeingpassedanarbitraryvalue.
EasingEasingsarethemathematicalfunctionsthatdefinehowfastorslowanimationsoccurindifferentpartsofananimation’stotalduration.Forexample,aneasingtypeof"ease-in-out"indicatesthattheanimationshouldgraduallyaccelerate(easein)duringthefirstpartthengraduallydecelerate(easeout)duringthefinalpart.Incontrast,aneasingtypeof"ease-in"producesananimationthatacceleratesuptoatargetspeedduringthefirstpartofananimationbutthereafterremainsataconstantspeeduntiltheanimationcompletes.Aneasingtypeof"ease-out"istheconverseofthis:theanimationstartsandcontinuesataconstantspeedbeforeitgraduallydeceleratesduringthefinalpartoftheanimation.
Muchlikethephysics-basedmotiondiscussedinChapter1,“AdvantagesofJavaScriptAnimation,”easingsgiveyouthepowertoinjectpersonalityintoyouranimations.Take,forexample,howroboticananimationthatusesthelineareasingfeels.(Alineareasingproducesananimationthatstarts,runs,andendsatthesamevelocity.)Theroboticfeelistheresultofanassociationwithlinearroboticmotionintherealworld:Self-guidedmechanicalobjectstypicallymoveinstraightlinesandoperateatconstantspeedsbecausethere’sneitheranaestheticnoranorganicreasonforthemtodootherwise.
Incontrast,livingthings—whetherit’sthehumanbodyortreesblowinginthewind—nevermoveatconstantspeedintherealworld.Frictionandotherexternalforcescausethemtomoveatvaryingspeeds.
Greatmotiondesignerspayhomagetoorganicmotionbecauseitgivestheimpressionthattheinterfaceisrespondingfluidlytotheuser’sinteraction.Inmobileapps,forexample,youexpectamenutoquicklyaccelerateawayfromyourfingerswhenyouswipeitoff-screen.Ifthemenuweretoinsteadmoveawayfromyourfingersataconstantspeed—likearoboticarm—you’dfeelasiftheswipemerelysetoffachainofmotioneventsthatwereoutsideyourcontrol.
You’lllearnmoreaboutthepowerofeasingtypesinChapter3,“MotionDesignTheory.”Fornow,let’srunthroughallofVelocity’savailableeasingvalues:
jQueryUI’strigonometriceasings.Foracompletelistingoftheseeasingequations,aswellasinteractivedemonstrationsoftheiraccelerationprofiles,refertothedemosoneasings.net.
Clickheretoviewcodeimage
$element.velocity({width:“100px”},“easeInOutSine”);
CSS’seasings:"ease-in","ease-out","ease-in-out",and"ease"(asubtlerversionof"ease-in-out").
Clickheretoviewcodeimage$element.velocity({width:“100px”},“ease-in-out”);
CSS’sBéziercurves:TheBéziercurveeasingallowscompletecontroloverthestructureofaneasing’saccelerationcurve.ABéziercurveisdefinedbyspecifyingtheheightoffourequidistantpointsonachart,whichVelocityacceptsintheformatofafour-itemarrayofdecimalvalues.Visitcubic-bezier.comforaninteractiveguidetocreatingBéziercurves.
Clickheretoviewcodeimage
$element.velocity({width:“100px”},[0.17,0.67,0.83,0.67]);
Springphysics:Thiseasingtypemimicsthebouncybehaviorofaspringthat’sbeenstretchedthensuddenlyreleased.Aswiththeclassicalphysicsequationthatdefinesthemotionofaspring,thiseasingtypeletsyoupassinatwo-itemarrayintheformof[tension,friction].Ahighertension(default:500)increasestotalspeedandbounciness.Alowerfriction(default:20)increasesendingvibrationspeed.
Clickheretoviewcodeimage$element.velocity({width:“100px”},[250,15]);
"spring"easingisapredefinedimplementationofthespringphysicseasingthat’shandytousewhenyoudon’twanttoexperimentwithtensionandfrictionvalues.
Clickheretoviewcodeimage
$element.velocity({width:“100px”},“spring”);
Rememberthatyoucanalsopassintheeasingoptionasanexplicitlydefinedpropertyinanoptionsobjectargument:Clickheretoviewcodeimage
$element.velocity({width:50},{easing:“spring”});
Donotbeoverwhelmedbythenumberofeasingoptionsavailabletoyou.You’llmostoftenrelyontheCSSeasingtypesandthe“spring”easing,whichsuitthevastmajorityofanimationusecases.Themostcomplexeasingtype,theBéziercurve,ismostoftenemployedbydeveloperswhohaveahighlyspecificeasingstyleinmindandaren’tafraidtogettheirhandsdirty.
Note
TherestoftheVelocityoptionsinthissectionmustbeexplicitlypassedintoanoptionsobject.Unlikethosealreadydescribed,theseadditionaloptionscannotbesuppliedtoVelocityintheshorthandcomma-separatedsyntax.
BeginandCompleteThebeginandcompleteoptionsallowyoutospecifyfunctionstobetriggeredatcertainpointsinananimation:Passthebeginoptionafunctiontobecalledpriortothestartofananimation.Conversely,passthecompleteoptionafunctiontobecalledatthecompletionofananimation.
Withbothoptions,thefunctioniscalledonceperanimationcall,evenifmultipleelementsarebeinganimatedatonce:Clickheretoviewcodeimage
var$divs=$(“div”);
$divs.velocity(
{opacity:0},
//Openanalertboxrightbeforetheanimationbegins
{
begin:function(){console.log(“Begin!”);},
//Openanalertboxoncetheanimationcompletes
complete:function(){console.log(“Complete!”);}
}
);
CallbackFunctions
Theseoptionsarecommonlyreferredtoas“callbackfunctions”(or“callbacks”)sincetheyare“called”whencertaineventsoccurinthefuture.Callbacksareusefulforfiringeventsthataredependentonthevisibilityofelements.Forexample,ifanelementstartsatinvisiblethenanimatestowardanopacityof1,itmaybeappropriatetosubsequentlytriggeraUIeventthatmodifiesthenewcontentonceusersareabletoseeit.
Rememberthatyoudon’tneedtousecallbackstoqueueanimationsontooneanother;animationsautomaticallyfiresequentiallywhenmorethanoneisassignedtoasingleelementorsetofelements.Callbacksareforthequeuingofnon-animationlogic.
LoopSettheloopoptiontoanintegertospecifythenumberoftimesananimationshouldalternatebetweenthevaluesinthecall’spropertymapandtheelement’svaluespriortothecall:Clickheretoviewcodeimage
$element.velocity({height:“10em”},{loop:2});
Iftheelement’soriginalheightwas5em,itsheightwouldalternatebetween5emand10emtwice.
Ifthebeginorcompleteoptionsareusedwithaloopedcall,theyaretriggeredonceeach—attheverybeginningandendofthetotalloopsequence,respectively;theyarenotretriggeredforeachloopalternation.
Insteadofpassinginaninteger,youcanalsopassintruetotriggerinfinitelooping:
Clickheretoviewcodeimage
$element.velocity({height:“10em”},{loop:true});
Infiniteloopsignorethecompletecallbacksincetheydon’tnaturallyend.Theycan,however,bemanuallystoppedviaVelocity’sstopcommand:
$element.velocity(“stop”);
Non-infiniteloopsareusefulforanimationsequencesthatwouldotherwiserequiretherepetitionofchainedanimationcode.Forexample,ifyouweretobounceanelementupanddowntwice(perhapstoalerttheuserofanewmessageawaitingthem),thenon-optimizedcodewouldlooklikethis:Clickheretoviewcodeimage
$element
//AssumetranslateYstartsat“0px”
.velocity({translateY:“100px”})
.velocity({translateY:“0px”})
.velocity({translateY:“100px”})
.velocity({translateY:“0px”});
Themorecompactandeasiertomaintainversionofthiscodewouldlooklikethis:Clickheretoviewcodeimage
//Repeat(loop)thisanimationtwice
$element.velocity({translateY:“100px”},{loop:2});
Withthisoptimizedversion,ifyouhaveachangeofheartabouthowmuchthetopvalueshouldbechangedby(currently"100px"),youneedonlychangethetopvalueinonepartofthecode.Iftherearemanysuchinstancesofrepetitioninyourcode,itquicklybecomesobvioushowmuchloopingbenefitsyourworkflow.
Infiniteloopingistremendouslyhelpfulforloadingindicators,whichtypicallyanimateindefinitelyuntildatahasfinishedloading.
First,maketheloadingelementappeartopulsatebyinfinitelyloopingitsopacityfromvisibletoinvisible:Clickheretoviewcodeimage
//Assumeopacitystartsat1(fullyvisible)
$element.velocity({opacity:0},{loop:true});
Later,oncethedatahasfinishedloading,youcanstoptheanimation,thenhidetheelement:Clickheretoviewcodeimage
$element
//Firststoptheinfiniteloop…
.velocity(“stop”)
//…soyoucangivetheelementanewanimation,
//inwhichyoucananimateitbacktoinvisibility
.velocity({opacity:0});
DelaySpecifythedelayoptioninmillisecondstoinsertapausebeforeananimationbegins.Thedelayoption’spurposeistoretainananimation’stiminglogicentirelywithinVelocity—asopposedtorelyingonjQuery’s$.delay()functiontochangewhenaVelocityanimationstarts:Clickheretoviewcodeimage
//Wait100msbeforeanimatingopacitytoward0
$element.velocity({opacity:0},{delay:100});
Youcansetthedelayoptionwiththeloopoptiontocreateapausebetweenloopalternations:Clickheretoviewcodeimage
//Loopfourtimes,waiting100msbetweeneachloop
$element.velocity({height:“+=50px”},{loop:4,delay:100});
DisplayandVisibilityVelocity’sdisplayandvisibilityoptionscorresponddirectlytotheirCSScounterparts,andacceptthesamevalues,including:"none","inline","inline-block","block","flex",andsoon.Inaddition,Velocityallowsforavalueof"auto",whichinstructsVelocitytosetthedisplaypropertytotheelement’sdefaultvalue.(Forreference,anchorsandspansdefaultto"inline",whereasdivsandmostotherelementsdefaultto"block".)Velocity’svisibilityoption,likeitsCSScounterpart,acceptsthe"hidden","visible",and"collapse"values.
WithinVelocity,whenthedisplayoptionissetto"none"(orwhenvisibilityissetto"hidden"),theelement’sCSSpropertyissetaccordinglyoncetheanimationhascompleted.Thiseffectivelyworkstohideanelementuponcompletionofananimation,andisusefulinconjunctionwithanimatinganelement’sopacitydownto0(wheretheintentionistofadeanelementoffthepage):Clickheretoviewcodeimage
//Fadeanelementtoopacity:0thenremoveitfromthepage’sflow
$element.velocity({opacity:0},{display:“none”});
Note
ThecodeaboveeffectivelyreplacesthejQueryequivalent:$element
.animate({opacity:0})
.hide();
QuickReviewofVisibilityandDisplay
Forreference,theCSSdisplaypropertydictateshowanelementaffectsthepositioningoftheelementssurroundingitandcontainedwithinit.Incontrast,theCSSvisibilitypropertyexclusivelyaffectswhetheranelementcanbeseen.Ifanelementissetto"visibility:hidden",itwillcontinuetotakeupspaceonthepage,butitsspacewillsimplyberepresentedbyanemptygap—nopartoftheelementwillbeseen.Ifanelementisinsteadsetto"display:none",theelementwillbefullyremovedfromthepage’sflow,andallelementswithinandarounditwillfillintotheremovedelement’sspaceasiftheelementneverexisted.
Notethat,insteadofremovinganelementfromthepage’sflow,youcansimplymarktheelementasbothinvisibleandnon-interactivebysettingitsvisibilityto"hidden".Thisisusefulforwhenyouwantahiddenelementtocontinuetakingupspaceonthepage:Clickheretoviewcodeimage
//Fadeanelementtoopacity:0thenmakeitnon-interactive
$element.velocity({opacity:0},{visibility:“hidden”});
Now,let’sconsideranimationsintheoppositedirection(showingelementsinsteadofhidingelements):Whendisplayorvisibilityissettoavalueotherthan"none"or"hidden",thevalueissetbeforetheanimationbeginssotheelementisvisiblethroughoutthedurationoftheensuinganimation.Inotherwords,you’reundoingthehidingthatoccurredwhentheelementwaspreviouslyremovedfromview.
Below,displayissetto"block"beforetheelementbeginsfadingin:Clickheretoviewcodeimage
$element.velocity({opacity:1},{display:“block”});
ThiseffectivelyreplacesthejQueryequivalent:$element
.show()
.animate({opacity:0});
Tip
ForacompleteoverviewofVelocity’sanimationoptions,consultthedocumentationatVelocityJS.org.
ContainingAnimationLogic
AswithVelocity’sdelayoption,Velocity’sincorporationofCSSdisplayandvisibilitysettingallowsforanimationlogictobefullycontainedwithinVelocity.Inproductioncode,wheneveranelementisfadedintooroutofview,it’salmostalwaysaccompaniedbyachangeindisplayorvisibility.LeveragingVelocityshorthandslikethesehelpsyoukeepyourcodecleanandmaintainable,sinceit’slessdependentonexternaljQueryfunctionsandfreeofrepetitivehelperfunctionsthatcommonlybloatanimationlogic.
NotethatVelocityincludesshorthandsfortheopacitytogglinganimationsdemonstratedabove.TheyfunctionidenticallytojQuery’sfadeInandfadeOutfunctions.YousimplypassthecorrespondingcommandintoVelocityasthefirstargument,andyoupassinanoptionsobject,ifdesired,asnormal:
Clickheretoviewcodeimage
$element.velocity(“fadeIn”,{duration:1000});
$element.velocity(“fadeOut”,{duration:1000});
UsingVelocity:AdditionalfeaturesAdditionalVelocity.jsfeaturesthatareworthyofnoteinclude:thereversecommand,scrolling,colors,andtransforms(translation,rotate,andscale).
ReverseCommandToanimateanelementbacktothevaluespriortoitslastVelocitycall,passin"reverse"asVelocity’sfirstargument.ThereversecommandbehavesidenticallytoastandardVelocitycall;itcantakeoptionsandisqueuedupwithotherchainedVelocitycalls.
Reversedefaultstotheoptions(duration,easing,etc.)usedintheelement’spriorVelocitycall.However,youcanoverridetheseoptionsbypassinginanewoptionsobject:Clickheretoviewcodeimage
//AnimatebacktotheoriginalvaluesusingthepriorVelocitycall’s
options
$element.velocity(“reverse”);
orClickheretoviewcodeimage
//Dothesameasabove,butreplacethepriorcall’sdurationwithavalue
of2000ms
$element.velocity(“reverse”,{duration:2000});
Note
Thepreviouscall’sbeginandcompleteoptionsareignoredbythereversecommand;reverseneverre-callscallbackfunctions.
ScrollingToscrollthebrowsertothetopedgeofanelement,passin"scroll"asVelocity’sfirstargument.ThescrollcommandbehavesidenticallytoastandardVelocitycall;itcantakeoptionsandisqueuedupwithotherchainedVelocitycalls:Clickheretoviewcodeimage
$element
.velocity(“scroll”,{duration:1000,easing:“spring”})
.velocity({opacity:1});
Thisscrollsthebrowsertothetopedgeoftheelementusinga1000msdurationanda"spring"easing.Then,oncetheelementhasscrolledintoview,itfadesinfully.
Toscrolltowardanelementinsideaparentelementwithscrollbars,youcanusethecontaineroption,whichacceptseitherajQueryobjectorarawelement.NotethatthecontainerelementoftheCSSpositionpropertymustbesettoeitherrelative,absolute,orfixed—staticwon’tdothetrick:Clickheretoviewcodeimage
//Scroll$elementintoviewof$(“#container”)
$element.velocity(“scroll”,{container:$(“#container”)});
Inbothcases—whetherscrollingisrelativetothebrowserwindowortoaparentelement—thescrollcommandisalwayscalledontheelementthat’sbeingscrolledintoview.
Bydefault,scrollingoccursonthey-axis.Passintheaxis:"x"optiontoscrollhorizontallyinsteadofvertically:Clickheretoviewcodeimage
//Scrollthebrowsertothe*left*edgeofthetargeteddiv.
$element.velocity(“scroll”,{axis:“x”});
Finally,thescrollcommandalsouniquelytakesanoffsetoption,specifiedinpixels,whichoffsetsthetargetscrollposition:Clickheretoviewcodeimage
//Scrolltoaposition50px*above*theelement’stopedge.
$element.velocity(“scroll”,{duration:1000,offset:“-50px”});
//Scrolltoaposition250px*beyond*theelement’stopedge.
$element.velocity(“scroll”,{duration:1000,offset:“250px”});
ColorsVelocitysupportscoloranimationfortheseCSSproperties:color,backgroundColor,borderColor,andoutlineColor.InVelocity,colorpropertiesacceptonlyhexstringsasinputs,forexample,#000000(black)or#e2e2e2(lightgray).Formoregranularcolorcontrol,youcananimatetheindividualred,green,andbluecomponentsofacolorproperty,aswellasthealphacomponent.Red,green,andbluerangeinvaluefrom0to255,andalpha(whichisequivalenttoopacity)rangesfrom0to1.
Refertotheinlinecommentsbelowforexamples:
Clickheretoviewcodeimage
$element.velocity({
//AnimatebackgroundColortothehexvalueforblack
backgroundColor:“#000000”,
//Simultaneouslyanimatethealpha(opacity)ofthebackgroundto50%
backgroundColorAlpha:0.5,
//Alsoanimatetheredcomponentoftheelement’stextcolortohalfits
totalvalue
colorRed:125
});
TransformsTheCSStransformpropertyperformstranslation,scale,androtationmanipulationstoelementsinboth2Dand3Dspace.Itconsistsofseveralsubcomponents,ofwhichVelocitysupportsthefollowing:
translateX:Moveanelementalongthex-axis.
translateY:Moveanelementalongthey-axis.
rotateZ:Rotateanelementalongthez-axis(effectivelyclockwiseorcounter-clockwiseona2Dsurface).
rotateX:Rotateanelementalongthex-axis(effectivelytowardorawayfromtheuserin3Dspace).
rotateY:Rotateanelementalongthey-axis(effectivelyleftwardorrightwardin3Dspace).
scaleX:Multiplythewidthdimensionofanelement.
scaleY:Multiplytheheightdimensionofanelement.
InVelocity,youanimatethesecomponentsasindividualpropertieswithinapropertyobject:
$element.velocity({
translateZ:“200px”,
rotateZ:“45deg”
});
UsingVelocity:WithoutjQuery(intermediate)Ifyou’reanintermediatedeveloperwhopreferstoworkinJavaScriptwithouttheaidofjQuery,you’llbehappytoknowthatVelocityalsoworkswhenjQueryisnotpresentonthepage.Accordingly,insteadofchainingananimationcallontoajQueryelementobject—asshowninthepreviousexamplesinthischapter—thetargetedelement(s)arepasseddirectlyintotheanimationcallasthefirstargument:Clickheretoviewcodeimage
Velocity(element,{opacity:0.5},1000);//Velocity
VelocityretainsthesamesyntaxasjQuery’s$.animate()evenwhenit’susedwithoutjQuery;thedifferenceisthatallargumentsareshiftedonepositiontotherighttomakeroomforpassinginthetargetedelementsinthefirstposition.Further,theglobal
VelocityobjectisusedtoinvokeanimationsinsteadofspecificjQueryelementobjects.
Whenyou’reusingVelocitywithoutjQuery,you’renolongeranimatingjQueryelementobjects,butratherrawDocumentObjectModel(DOM)elements.RawDOMelementscanberetrievedusingthefollowingfunctions:
document.getElementByID():RetrieveanelementbyitsIDattribute.
document.getElementsByTagName():Retrieveallelementswithaparticulartagname(e.g.a,div,p).
document.getElementsByClassName():RetrieveallelementswithaparticularCSSclass.
document.querySelectorAll():ThisfunctionworksnearlyidenticallytojQuery’sselectorengine.
Let’sfurtherexploredocument.querySelectorAll()sinceitwillprobablybeyourweaponofchoicewhenselectingelementswithouttheaidofjQuery.(It’saperformantfunctionthat’swidelysupportedacrossbrowsers.)AswithjQuery’selementselectorsyntax,yousimplypassquerySelectorAllaCSSselector(thesameselectorsyouuseinyourstylesheetsfortargetingelements),anditwillreturnallmatchedelementsintheformofanarray:Clickheretoviewcodeimage
document.querySelectorAll(“body”);//Getthebodyelement
document.querySelectorAll(“.squares”);//Getallelementswiththe“square”
class
document.querySelectorAll(“div”);//Getalldivs
document.querySelectorAll(“#main”);//Gettheelementwithanidof“main”
document.querySelectorAll(“#maindiv”);//Getalldivswithin“main”
Ifyouassigntheresultofoneoftheselookupstoavariable,youcanthenreusethatvariabletoanimatethetargetedelement(s):Clickheretoviewcodeimage
//Getalldivelements
vardivs=document.querySelectorAll(“div”);
//Animateallthedivs
Velocity(divs,{opacity:0},1000);
Sinceyou’renolongerextendingjQueryelementobjects,youmaybewonderinghowtochainanimationsback-to-back,likethis:Clickheretoviewcodeimage
//Thesechainontooneanother
$element
.velocity({opacity:0.5},1000)
.velocity({opacity:1},1000);
ToreenactthispatternwithouttheaidofjQuery,simplycallanimationsoneafteranother:Clickheretoviewcodeimage
//Animationsonthesameelementautomaticallychainontooneanother.
Velocity(element,{opacity:0},1000);
Velocity(element,{opacity:1},1000);
WrappingupNowthatyou’rearmedwithanunderstandingofthebenefitsofusingJavaScriptforwebanimation,plusagraspofthebasicsofVelocity,you’rereadytoexplorethefascinatingtheoreticalfoundationthatunderliesprofessionalmotiondesign.
Chapter3.MotionDesignTheory
Utilityandelegancearethegoalsofeverygreatmotiondesigner,andthischapterexploresahandfuloftechniquesforachievingthosegoals.Becausethefocushereisonthetheoryofmotiondesign—notitsimplementation—therearenocodeexamples.Thetechniquesdiscussedcanbebroadlyabstractedacrossalllanguages,devices,andplatforms.
MotiondesignimprovestheuserexperienceLet’sexaminethephrasemotiondesign:Todesignmotionistodecidewhichvisualpropertiesofanobjectshouldchange,andhowthatchangeshouldaccelerate.Forexample,sayyouwanttocallattentiontoabuttonbychangingitscolor:youmightchangethebackgroundcolorfromredtoblueovera1000msdurationwithaneasingstyleofease-in-out.Inthiscase,background-coloristhetargetpropertyandredisthedesiredendvalue.Thetimingoftheproperty’stransitiontowarditsendvalueissubjecttoa1000msdurationwhoseaccelerationcurveisdefinedbyease-in-out.Greatmotiondesignersdeliberatelychooseeachoneofthesecomponents—notbecausetheylookgoodorhitonpopulartrends,butbecausetheyreinforcetheintentionsofaUI.Whimsicalmotiondesign,incontrast,isnotonlyinconsistent,butalsoappearsinelegantanddivertingtotheuser.
TherearehundredsoftutorialsontheminutiaeofUIdesign,butveryfewonmotiondesign.Thisisn’tsurprisinggiventhatmotiondesignislessimportanttoawebpagethanUIdesign.Untilrecently,browsersanddevicesweren’tactuallyfastenoughtoaccommodaterichmotiondesign.ButwhileUIdesignlaysthestructuralfoundationforinteractingwithapage,motiondesignenrichesthatfoundationwiththefurnishinganddecorationthatmakethepageusableandcomfortable.Furnishingistheutilitythatmotiondesignserves,anddecorationistheeleganceitprovides.
Greatappsleverageutilityandelegancetomaketheuserfeellikeshe’sinteractingwithaninterfacethat’sliving,breathing,andtangible.Aninterfacethatreactsthewaythingsdointherealworldisonethatshe’llengagewithmoredeeply.Incontrast,aninterfacethat’sdevoidofmotiondesignremindstheuserthatshe’ssimplydraggingacursoracrossascreenortappingherfingeronapieceofglass.AUIwithoutmotiondesignmakestheuserpainfullyawareoftheartificebeforeher.
Theutilityofmotiondesignleveragesuserpsychology.Whenauserpressesabutton,canshebeconfidentthatthepresswasacknowledgedbytheUI?Aneasywaytoensureherconfidenceistoanimatethebutton’stransitiontoadepressedstate.Whenauseriswaitingforcontenttoload,canshebeconfidentthatprogressisbeingmadeorissheleftwiththeunsettlingfeelingthattheapphasfrozen?ThesearepsychologicalexpectationsthatmotiondesigncanaddressbyprovidingongoingvisualindicationsoftheUI’sstate.
Thecomplementaryeleganceofmotiondesigniswhatelevatesanappfrommerelylookinggoodtofeelinggood.It’sthesourceofthat“oohahh”feelingthatremindstheuserhowmagicaltechnologycanbe.
Let’smasterbothoftheseaspects.Let’sdivein.
UtilityHowdoyouensureyourmotiondesignchoicesarevaluableadditionstoyoursite?Herearesometechniques.
BorrowconventionsLetyourselfbeinspiredbythemotiondesigninyourfavoritesitesandapps.Popularmotiondesignconventionsareworthleveragingbecausetheyalreadyholdmeaningintheuser’smind.Repeatedexposuretoconventionsleadstheusertoformexpectationsabouthowcertainanimations“should”look.Ifyouuseaconventionforapurposeotherthanwhattheuserhascometoexpect,yourappwillfeelunintuitive.
Themoreyoucopymotiondesigneffectsfromelsewhere,themorefamiliaryourappwillfeeltotheuser.Themorefamiliaranappfeels,thequickertheuserwillfeelcomfortablewithitandconfidentaboutit.Whilethere’sutilityinnovelty,themotiondesignofeverydayUIelementsshouldn’tbenovel.Reservenoveltyforanimationsequencesthatcarrylittlemeaningorarehardtomisconstrue,suchasapage’sloadingsequenceorastatusindicatoranimation,respectively.
PreviewoutcomesWhenanelementonyourpagehasanambiguouspurpose,givetheuserapreviewoftheoutcomeofinteraction.Thisprovidesreassurancethattheelementdoeswhattheuserthinksitdoes.Asimpleexampleofthiswouldbeabuttonthatinitiatesafiletransfersendingoutvisualradiowavepulseswhenhoveredover.Thisleveragesacommongraphicdesigntropetotelltheuserthatadatatransferactionwilloccur.
Alessambiguouskindofpreviewingoutcomesistoshowpartoftheanimationthatoccurswhentheuseractuallytakesanaction.Forexample,ifanin-progressfiletransferindicatoranimationbeginsrunningwhentheuserclicksabutton,implementmotiondesignsuchthathoveringoverthetriggeringelementpartiallyrunsthein-progressanimation.Whentheuserhoversofftheelement,reversethepartialanimationsothefiletransferindicatorreturnstoitsdefaultstate.Thistypeofpreviewingtechniquehelpstheuserimmediatelyunderstandtheeffectthatheractionswilltrigger,whichhelpstoreassureherofthepurposeofUIelements.Themoreconfidenttheuserfeels,themoreincontrolshefeels.Themoreincontrolshefeels,themorepleasantherexperience.
DistractionoverboredomWhenauserperformsarote,non-engagingtaskonyourpage—suchasfillingoutalongform—youcanusecolorandmovementtoraiseherlevelofawarenessandintrigue.Forexample,youmightanimateacheckmarkwhenshesuccessfullycompleteseachformfield.Thiskeepstheuser’smindsuperficiallyengagedwiththeinterface,whichlessensthedullnessofthetaskathand.Similarly,youcouldshowtheuseraneye-catchingloadingindicatorwhileshewaitsforcontenttoload.AgreatexampleofthiscanbefoundinLyft,apopularride-sharingapp,whichanimatesaballoonrhythmicallyfloatingupanddownonablankcanvaswhiletheapploadsintomemory.
Allowingtheuser’sbraintorelaxandfeelthepleasurablemomentumofrepeatedmovementkeepshermoreengagedwithyourcontent.Howeversuperficialthismayseem,itworks.Butrecognizethatthistechniqueshouldbeusedonlyinsituationswheretheuserwillexperienceanunavoidablestretchofboredom;avoidusingitasaBand-AidanytimeyoufeellikespicingupyourUI.
Let’sconsideranotherexample:whenFacebookloadstextcontentintoitsNewsFeed,itanimatesacontinualblurringofdummytextuntiltherealtextisreadytobeshown.Thisrhythmicblurringanimationnotonlyindicatesthattheinterfaceishardatwork(asopposedtohavingstalled),butalsospecificallytellstheuserwhichportionoftheUIshe’swaitingon.Thistechniqueiscalledinlinestatusindication.Comparethistotheubiquitoussinglestatusindicator,whichisasoldasthewebitself:thesuperimpositionofasingle,loopedanimationgraphiconapagethat’sdiscomfortinglydevoidofcontent.
Usersaretiredofthis.Inlinestatusindication,incontrast,letsyoushowasmuchoftheinterfaceaspossiblebyblockingoutonlythespecificsubsectionswhosecontenthasyettoload.Thisisnotonlymorenuanced,butalsogivestheusermorecontenttofixhereyesonwhileshetwiddlesherthumbswaitingforthepagetofullyload.
Thetakeawayhereissimple:themoreyougiveuserstoengagewith,thelongerit’lltakeforthemtogetbored.
LeverageprimalinstinctsThehumanbrainhasaregiondedicatedtovisualprocessing.We’reprogrammedtorespondtosuddenmovementswhetherwewanttoornot.So,ifanimportantactionisoccurringonthepagethatrequirestheuser’simmediateattention,considerleveragingmovementtoflagherattention.Acommonwaytoalerttheuseristo“bounce”anelementbyrepeatedlytranslatingitupanddown.Thisimplementationsitsincontrasttoanimatingtheelement’scolor,whichdoesn’texploitprimalinstincts;we’renotprogrammedtoinstinctivelyinterpretcolorchangesasworthyofourimmediateattention.(However,considerhowthroughrepeatedexposureinsomecountries,peoplearetrainedtointerpretredas“stop”andgreenas“go”,whichareexamplesofsociallyreinforcedmeaning.Whendesigningmotion,takethisphenomenonintoconsiderationaswell.)
Divingabitdeeperintopsychology,theuserinterpretsmovementtowardherasanurgentnoticethatrequiresaction,whereassheinterpretsmovementawayfromherasgettingoutofherwayand,consequently,notrequiringaction.
MakeinteractionsvisceralBig,squishybuttonswithrichcolorgradientsmaketheuserwanttoclick.Elementsliketheserewardclickingwithasatisfyingsenseofpressureexertionandcolorexplosion.Thelessonhereisoneofincentivization:themoreintriguingitistoclickabutton,themoreauserwilldoit.Leveragethisphenomenonforimportantcallstoactionthatyouwanttheusertoengagewith,suchasbuttonsforregisteringanewaccountorcheckingoutofashoppingcart.
ReflectgravitasIftheuserhastakenanactionwithirreversibleconsequences,reinforcethatnotionbyusingmotiondesignthatfeelsequallyimportant.Forexample,theanimationassociatedwithclickingaDeletebuttonshouldfeelmoresignificantthantheanimationassociatedwithhoveringoverastandardnavigationdropdown.Whilethelattermayentailasimplecolorchange,theformermightconsistofasuddenjumpinsizeandathickeningoftheelement’sborder.Bydivvyingupmotiondesignalongagradientofseverity,you’llhelptheuserintuitivelygraspthehierarchyoftheavailableactions.Thistechnique,alongwiththeothersdetailedinthischapter,servesthegoalofincreasinguserunderstandingandconfidence.
ReduceconcurrencyTosomeextent,usersarealwaystryingtomakesenseofyourUI.Consciouslyorsubconsciously,theyascribemeaningtoeverydesignandmotiondesignchoiceyoumake.So,ifyoupresenttheuserwithextendedanimationsequencesconsistingofmanyelementsanimatingintoviewconcurrently,you’llcompromiseherabilitytoparsethemeaningofallthemovementstakingplace.
Inshort,ifyou’reusingmotiondesigntoindicatesomethingimportant,makesureyou’renotindicatingmanydifferentthingsatonce.Ifyouare,considerbreakinganimationsintostepsorreducingthetotalanimationcount.
ReducevarietyRelatedtothebestpracticeofreducingconcurrencyistheconceptoflimitinganimationvariety:thefeweranimationvariationsyouhave,themorereassuredtheuserwillfeelthatshe’sfullyabreastofwhateachanimationinyourUIconnotes.Forexample,ifyouuseonetypeofanimationforbringingbigimagesintoview,butadifferenttypeforbringingsmallimagesintoview,considerconsolidatingthemintoone.Ifthedifferentiationbetweenthemwasmerelyforaestheticpurposesratherthanforimprovingusability,you’vesuccessfullyeliminatedunnecessarycomplexityfromyourUI,andreinforcedbehavioralconsistencyintheprocess.Consistencyleadstopatternrecognitionandunderstanding.Understandingleadstoincreaseduserconfidence.
MirroranimationsAtangentialaspectoflimitinganimationvarietyisconsistencyinyourchoiceofanimationpropertyandoptioncombinations.Forexample,ifyouhaveamodalthatanimatesintoviewbytransitioningopacityandscale,ensurethatthemodalanimatesoutofviewwiththesetwopropertiesrevertingtotheiroriginalvalues.Don’tchangepropertiesforthetwosidesofthesamecoin.Doingsowillmaketheuserquestionwhatpromptedthedifferentiation,andneedlesslyraisedquestionsarethehallmarkofabaduserexperience.
Whenworkingwithpropertiesthataffecttranslation(forexample,translateX,left,marginLeftinCSS),mirroringappliesliterally:ifamodalanimatesintoviewbyslidingdownfromthetopofthepage,haveitanimateoutofviewbyslidingbackuptowardthetopofthepage.Conversely,ifyouweretohavethemodalanimateoutofviewbyfurtherslidingdownoffthepage,you’dbeindicatingtotheuserthatthemodalhasbeensentsomewherenewasopposedtohavinggonebackwhereitcamefrom.Typically,youwanttoimplythatthemodaldialoghasgonebackwhereitcamefromnowthattheuserisdone,say,changingaccountsettings.Iftheuserwereinsteadsendinganemail,thenhavingthemodalanimatedownoffthepagewouldbecontextuallyappropriatebecauseitreinforcestheideathattheemailisbeingsentfromitsorigin(theuser)toanewlocation(therecipient).
LimitdurationsDesignersoftenmakethemistakeoflettinganimationsruntoolong,causingtheusertowaitneedlessly.NeverletUIflourishesslowdowntheapparentspeedofyourpage.Ifyouhavealotofcontentfadingintoviewwithinalargeranimationsequence,ensurethatthetotaldurationacrosstheentiresequenceisshort.
Similarly,ifthere’sapartofyourUI—aprofileimage,forinstance—thattransitionsintooroutofviewonafrequentbasisduetothewayusersinteractwithyourpage,beextracarefulnottoallowprotracteddurations.Seeingapieceofmotiondesignunfoldisnicethefirsttime,butseeingitunfoldadozentimeseverytimeauserinteractswithanappbecomesburdensomeveryquickly—especiallyiftheuserfeelsthatrepeatedlywaitingfortheanimationtoplayoutissignificantlyincreasingtheoverallUIwaittime.
Sinceit’sdifficulttojudgetheappropriatenessofyouranimationdurationsafterseeingthemplayoutdozensoftimesduringtesting,agoodruleofthumbistospeedupallanimationsby25percentbeforeyoupushasitelivetoproduction.Thiswillhelpensurethattheyalwaysleantowardthefasterside.(SeeChapter4,“AnimationWorkflow”fortipsonhowtoquicklytime-shiftyouranimations.)
LimitanimationsIfremovingananimationaltogetherdoesn’tdetractfromtheuser’sunderstandingofyourinterface,considerdroppingitandusinganinstantstylingchangeinitsplace.ThemoreanimationyouhavethroughoutyourUI,themoretheuserwillgetusedtoseeingthem.Themoreshegetsusedtoseeingthem,thelessattentionshe’llpaytothem,andthelesslikelyshe’llbeabletodifferentiatebetweenthedifferenttypesofmotiondesignandwhateachsignifies.
Thevastmajorityofyourmotiondesignshouldbesubtle—minorcolorchangesonhovers,forexample—sothefewinstancesofgrandiosemotiondesignthatdoexistshouldpoptoconveytheirintendedmessage.
EleganceThelinebetweenfrivolousandconsequentialmotiondesignisaneasyonetodiscern:doesaparticularpieceofmotiondesignsatisfyoneofthebestpracticesdiscussedinthe“Utility”sectionofthischapter?Ifnot,removeit.It’sfrivolous,andit’sjeopardizingtheusabilityofyourUI.
Don’tbefrivolousTohoneyourjudgmentaboutwhatisfrivolous,downloadthemostpopularapps,playwitheachextensively,andjudgewhethertheyfeatureanimationtoagreaterorlesserextentthanyourappdoes.Playclosetoattentiontowhateachanimationconveys,andwhyitconveysit.Ifyoufeelthattheseappsuseanimationtoamuchlesserextentthanyoursdoes,considertoningbackthemotiondesigninyourUI.
There’soneexceptiontothisdon’t-be-frivolousmantra—readon!
YouroneopportunitytobefrivolousApage’sloadingsequence—whenallofyourelementsanimateintoviewfromaninitialstateofinvisibility—isyouroneopportunitytobeover-the-topandfrivolouswithyouranimations.Why?Becausethissequencehappensonlyonce,anditwon’trepeatedlygetinthewayoftheuser’sinteractionwithyoursite.Also,thisisyourmomenttoleverageyourmotiondesignskillstodeliveragreatfirstimpressiononyoursite.
Ifyouhaveareallycoolideaforanimatingyourcontentintoview,thendoithere.Butbesuretorespectalltheotherrulesinthischapter,especiallylimitingdurations.
ConsiderpersonalityIfyouweredesigningacorporatesite,youwouldn’tuseabounceeffecttotransitionelementsintoview.Bouncinessisplayful—notaqualitythatcorporatesitesoftenwanttoconvey.Andifyouweredesigninganeducationalorgovernmentapp,youwouldn’tuseeasingsthatresultinmovementthatstartsveryquicklybeforefinishingveryslowly(therebyconveyingawhizzing-by-your-facefuturisticslickness)—thesewouldprobablybetooglossyandstylizedforthecontentathand.
Alwaysbeconsiderateofthepersonalityexpressedbyyouranimationdecisions.Asadesigner,it’shardtojudgethetoneofyourownwork,soit’sagoodideatogetthird-partyfeedbackearlyandoften.AsktestuserswhetheraUIfeelssuitablyprofessional,friendly,andsleek,andtweakyourmotiondesignaccordingtoyourpreferenceforeachofthosethreetraits.
GobeyondopacityThemostcommonmeansoftransitioninganelementintooroutofviewistoanimateitsopacityfrom0to1,andviceversa.Thiscanberatherboring.Opacityisjustthebasepropertythathastobeanimatedwhendisplayingorhidingcontent—it’snottheonlyproperty.Youcanspiceupyourpropertychoicesbyscalinganelementdownintoview,slidingitupoutofview,orchangingitsbackgroundcolor.Asyouaddmorepropertiestoananimation,considerleveragingmultistepeffects,whichyou’lllearnaboutinthenexttechnique.
BreakanimationsintostepsThesimplestpathtoprofessional-lookingmotiondesignistobreakanimationsintomultistepeffects.Forexample,ifyou’reanimatinganimageintoviewbytransitioningitsopacityandscalefrom0to1,insteadconsiderfirstanimatingtheelement’sopacityto0.5—halfofitsfinalvalue—followedbyanimatingitsscalefrom0whilesimultaneouslyanimatingtheremaininghalfofopacity.Breakingtheanimationsofpropertiesintostepslikethisremovesthelinearitythat’scommontomostamateurmotiondesignontheweb—whereinallpropertiesanimateperfectlyinsync.Intherealworld,thepropertiesofobjectsinmotiondon’tallaccelerateinsync:Considerhow,whenabirdflies,itmovesforward(translateX)atadifferentratethanitmovesupanddown(translateY).IfitwereinsteadtomovelinearlyinbothofitsXandYaxes,itwouldlookmorelikeabulletthanananimal.Greatmotiondesignborrowsfromthemovementofliving,breathingthingsbecauseUIsaremadeforhumans—notmachines—andhumansliketofeelexpressionandreaction.
IfyoupayattentiontothefuturisticUIanimationdepictedinmovies,you’llnoticethatintricatemultistepanimationsareakeycomponentinmakingthemlooksosleek.Thereasonforthisissimple,anditfurthersupportsthecaseforavoidinglinearity:humansareattractedtovarietyandcontrast.Considerhow,whenyoubreakupananimation,you’recontrastingandjuxtaposingtheindividualcomponentsofthatanimationagainsteach
other.Justlikelayeringupclothingtocreatepleasantcolorandtexturecombinations,youshouldlayeranimationstocreatepleasantmotiondesigncombinations.
Foradviceonthetechnicalimplementationofmultistepeffects,readChapter4,“AnimationWorkflow.”
StaggeranimationsWhenmultiplesiblingelements—say,aseriesofimagesinagallery—areanimatingintoviewatthesametime,consideraddingatinysuccessivedelaybetweenthem.(Thatis,afterthefirstimageloads,adelayoccursbeforethesecondimageloads,andsoon.)Todelaytheanimationofsiblingelementsinthiswayiscalledstaggering,anditspurposeissimilartothatofbreakingananimationintosteps:itaddsvisuallayeringbypreventingallyourelementsfromanimatingperfectlyinsync,whichcanlookplainandinelegantcomparedtostaggeredloading.Why?Becauseanimatingaseriesofelementsinsynclacksanysemblanceofgranularityorgradience.Considerthis:Birdsdon’tflysidebysideinastraightline.Whatmakestheiraerialmovementssogracefulistheirsuccessiveformationandtiming.It’stheirjuxtaposition,andthemotionoftheirjuxtaposition,thatmakesthemsoeleganttothehumaneye.
FlowfromthetriggeringelementIfclickingabuttoncausesamodaltoappear,havethemodalanimateoutfromthebutton’slocation.Inotherwords,haveanimationsflowfromtheelementsthattriggerthem.Thisbridgesthecause-and-effectrelationshipsinyourUI,makingindividualelementsfeelbettercoupledandbetterorganized.
Tounderstandthepsychologicalbenefitofthistechnique,considerhowmotionworksintherealworld:whenyoupullalever,aseriesofmechanicalpartscausesaconnectedobjecttomove.Connectedisthekeyword:realobjectsdon’tmoveunlessaforceisexerteduponthem.Likewise,it’simportanttotreateveryelementinyourUIasanelementcapableofexertingitsownforce.Everyactionshouldfeelconnectedtoatrigger.Thissortofseamlessexperienceiswhathelpsaninterfacetranscendfromthedigitalintothephysical.Themorephysicalaninterfaceis,themoreresponsiveandemotiveitfeels.
UsegraphicsMakeuseofscalablevectorgraphics(SVG)toanimateindividualgraphiccomponentsofalargerelementthattheusercaninteractwith(learnmoreinChapter6,“ScalableVectorGraphicsPrimer”).Acommonexampleofthisisthetrioofhorizontallinesthatconstitutea“hamburgermenu”icon,orthedotsthatformacircleinaloadingindicator.Inbothoftheseexamples,arbitraryshapesaregroupedtogethertoformacommonUIcomponent.BeforeSVGanimationwaspossibleontheweb,thecommonapproachtoanimatingagraphiclikeeitherofthetwodescribedwastoembedthefullgraphicasaPNGimageandthenanimatetheentireshapebytransitioningitsopacityinCSS.ByleveragingSVG,however,youcananimatetheseuniqueelementsonanindividualshape-by-shapebasisandsubjectthemtomanytypesofpropertyanimations.
GraphicanimationisasurefirewaytoaddnuancetokeyportionsofyourUI.This
nuanceispartiallyaresultofthefactthatweb-basedanimationprimarilydealswithsolid,rectangularshapes.(Sometimestheyhaveroundedcorners,buttheshapesnonethelessremainsolidandwhole.)Animatingtheindividualshapesofanelementinsteadletsyoudelighttheuserwithmotiondesignthatshemightnothaverealizedwasevenpossible.
Beyondnovelty,youcanalsouniquelyleverageSVGanimationtotransformshapesintobrand-newones.Pairingthiswiththetechniquesforpreviewingoutcomesandflowingfromthetriggeringelement,youcanusegraphictransformationstoindicateUIbehaviorandprovidefeedbacktotheuser.Forexample,ifhoveringoverthedotsinaloadingindicatorcausesthosedotstorearrangethemselvesintoanXshape,thatwouldindicatetotheuserthatclickingthestatusindicatorgraphicwouldcanceltheloadingofcontent.
ExperimentRepeatedly
Findingtherightduration,stagger,easing,andpropertycombinationsforeachanimationisnotaskillthatdesignersarebornwith.It’saskillthateverygreatdesignerhashadtolearn.So,remember:yourfirstattemptatacombinationofanimationpropertiesmightlookgood,butit’sprobablynotthebestcase.Thereareonlytwowaystofindthebestcase:experimentbysystematicallychangingeachfactorinthemotiondesignequationuntilyoustumbleontosomethingsublime,orborrowideasfromotherpeoples’work.Onceyou’vefoundacombinationyoulike—evenifit’soneyou’vealreadyborrowedelsewherepixel-for-pixel—experimentfurther.Considercuttingthedurationinhalf,switchingtoacompletelydifferenteasingtype,orswappingoutaproperty.
Designersareoftenaversetoextendedexperimentationbecause—eventhoughthereareamillionwaystoanimateabuttonintoview—eachwayeffectivelyfulfillsthegoalathand:makingthebuttonvisible.Consequently,onceyoustumbleontoacombinationofpropertiesthatlookgood,you’relikelytostickwithitbecauseitlooksgoodanditworks.Butdon’tforgetthatgoodnessisn’tarespectabledesigngoal—greatnessis.Greatnessentailssteppingoutsideyourcomfortzone,andnotnecessarilyrelyingonwhatyoualreadyknowworks.
WrappingupUtilityandeleganceareyourgoals.Atminimum,allanimationcodemustfulfilloneortheother.
Whenimplementedproperly,animationcodeshouldprovideconcretevaluetoyourUXandnotadverselyimpactthewebsite’sperformance.Nomatterhowsleekyourmotiondesignis,iftheinterfaceislaggyasaresultofitsimplementation,theoveralluserexperiencewillnotbeelegant.You’lllearnmoreabouttheimportanceofperformanceintheChapter7,“AnimationPerformance.”
Chapter4.AnimationWorkflow
Theanimationcodefoundonmostsitesisnothingshortofamess.Ifthere’sonethingexperiencedmotiondesignersmissabouttheold,uglydaysofFlash,it’sastructuredapproachtomotiondesign.
Thecontemporaryapproachtostructuringanimationcodeistwofold:leveragetheworkflowfeaturesofananimationengine(inthiscase,Velocity.js)tomakeyourcodemoreterseandexpressive,andusecodeorganizationbestpracticessothatit’seasytomodifyyourworklater.
Saygoodbyetodeep-nestingJavaScriptcallbacksandtodirtyingyourstylesheetswithunwieldyCSSanimations.It’stimetoupyourwebanimationgame.
CSSanimationworkflowInanattempttobettermanageUIanimationworkflow,developerssometimesswitchfromJavaScripttoCSS.Unfortunately,onceanimationsreachamediumlevelofcomplexity,CSSanimationstypicallyresultinasignificantlyworseworkflow.
IssueswithCSSWhileCSStransitionsareconvenientwhenusedsparinglyinastylesheet,they’reunmanageableincomplexanimationssequences(forexample,whenallelementssequentiallyloadintoviewuponpageload).
CSStriestoaddressthisissuewithakeyframesfeature,whichletsyouseparateanimationlogicintodiscretetimeranges:Clickheretoviewcodeimage
@keyframesmyAnimation{
0%{opacity:0;transform:scale(0,0);}
25%{opacity:1;transform:scale(1,1);}
50%{transform:translate(100px,0);}
100%{transform:translate(100px,100px);}
}
#box{animation:myAnimation2.75s;}
Thisspecifiesseparatepointswithinananimation’stimelineatwhichparticularpropertyvaluesshouldbereached.ItthenassignstheanimationtoanelementwithanIDof#box,andspecifiesthedurationofthekeyframesequencetocompletewithin.Don’tworryifyoudon’tfullygraspthesyntaxabove—youwon’tbeusingitinthisbook.Butbeforemovingon,considerthis:whathappenswhenaclientasksyoutomaketheopacityanimationonesecondlonger,butkeeptherestofthepropertiesanimatingattheircurrentdurations?Fulfillingthisrequestrequiresredoingthemathsothepercentagevaluesproperlyalignwitha1-secondincrease.Doingthisisn’ttrivial,anditcertainlyisn’tmanageableatscale.
WhenCSSmakessenseIt’simportanttopointoutasituationinwhichyoushouldbeusingCSSratherthanJavaScriptforUIanimation:whenyou’reanimatingsimplestylechangestriggeredbyauserhoveringoveranelement.CSStransitionslendthemselvesbeautifullytothesetypesofmicro-interactions,allowingyoutoaccomplishthetaskinjustafewlinesofverymaintainablecode.
WorkinginCSS,youfirstdefineatransitiononthetargetelementsothatchangesinthespecifiedCSSpropertiesanimateoverapredeterminedduration:Clickheretoviewcodeimage
/*Whenthisdiv’scolorpropertyismodified,animateitschangeovera
durationof200ms*/
div{
transition:color200ms:
}
YouthenspecifythevaluethateachparticularCSSpropertyshouldchangetoward,perthetransitionrule.Inthecaseofthehoverexample,thediv’stextcolorwillchangetobluewhentheuserhoversoverit:
div:hover{
color:blue;
}
That’sit.Inonlyafewlinesofcode,CSShandlesinteractionstateforyou:whentheuserhoversawayfromthediv,CSSwillanimatethechangefrombluebacktothepreexistingtextcoloroveradurationof200ms.
WhatDoesGoodCodeLookLike?
Goodcodeisexpressive,meaningthatitspurposeiseasytograsp.Thisiscrucialnotonlyforcoworkersattemptingtointegrateyourforeigncode,butalsoforyourselfinthefuture,onceyou’veforgottenyouroriginalapproach.Goodcodeisalsoterse,meaningthatitaccomplisheswhatitneedstoinasfewlinesaspossible;everylineservesanimportantpurpose,anditcan’tberewrittenaway.Lastly,goodcodeisalsomaintainable,meaningthatitsindividualpartscanbeupdatedwithoutfearofcompromisingtheintegrityofthewhole.
Incontrast,codingthissameeffectinjQuerywouldentailthefollowing:Clickheretoviewcodeimage
$div
//Registeramouseovereventonthisdiv,whichcallsananimation
function
.on(“mouseover”,function(){
$(this).animate({color:“blue”},200);
})
//Whentheuserhoversofftheelement,animatethetextcolorbackto
black
.on(“mouseout”,function(){
//Note:Wehavetorememberwhattheoriginalpropertyvaluewas
(black)
$(this).animate({color:“black”},200);
});
Thismightnotlooksobad,butthecodeisn’ttakingadvantageofthefactthatJavaScriptprovidesaninfiniteamountoflogicalcontrol.ItgoesoutofitswaytodosomethingthatCSSisdesignedfor:triggeringlogiclessanimationsthatoccuronthesameelementthattheuserisinteractingwith.Above,you’redoinginJavaScriptwhatyoucouldhavedoneinfewer,moreexpressive,andmoremaintainablelinesofCSS.Evenworse,you’renotgettinganyadditionalfeaturebenefitsbyimplementingthisfunctionalityinJavaScript.
Inshort,ifyoucaneasilyuseCSStransitionstoanimateanelementthat’sneverbeinganimatedbyJavaScript(meaningthere’snopotentialforconflict),thenyoushouldcodethatanimationinCSS.ForallotherUIanimationtasks—multi-elementandmultistepsequences,interactivedraganimations,andmuchmore—JavaScriptanimationisthesuperiorsolution.
Let’sexplorethefantasticworkflowtechniquesJavaScriptprovides.
Codetechnique:SeparatestylingfromlogicThefirsttechniquehasprofoundworkflowbenefits,especiallyforteams.
StandardapproachInjQueryanimation,it’scommontoanimateCSSclassesontoelementsusingtheUIadd-onplugin(jQueryUI.com).Whenthemoduleisloaded,jQuery’saddClass()andremoveClass()functionsareupgradedwithanimationsupport.Forexample,let’ssayyouhaveaCSSclassdefinedinastylesheetasfollows:
.fadeInAndMove{
opacity:1;
top:50px;
}
YoucanthenanimatetheCSSpropertiesofthatclass(opacityandtopinthiscase)ontothetargetelementalongwithaspecifiedduration:Clickheretoviewcodeimage
//Animatethepropertiesofthe.fadeInAndMoveclassovera1000msduration
$element.addClass(“fadeInAndMove”,1000);
ThemorecommonimplementationofjQueryanimationconsistsofinliningthedesiredanimationpropertieswithinan$.animate()call,whichusesthesyntaxdemonstratedinChapter1,“AdvantagesofJavaScriptAnimation”:Clickheretoviewcodeimage
$element.animate({opacity:1,top:50},1000);
Bothimplementationsproducethesameresult.Thedifferenceistheirseparationoflogic:ThefirstimplementationdelegatesthestylingrulestoaCSSstylesheet,wheretherestofthepage’sstylingrulesreside.ThesecondmixesstylingruleswiththeJavaScriptlogicresponsiblefortriggeringthem.
Thefirstapproachispreferableduetotheorganizationalcleanlinessandflexibilitygainedbyknowingwheretolooktomaketheappropriatestyleorlogicchangestoyourcode.CSSstylesheetsexistforareason;seasoneddevelopersdonotinlineCSSintotheirHTML.ThatwouldconflatethepurposesofHTML(structure)andCSS(styling),andmakeasiteconsiderablymoredifficulttomaintain.
Thevalueoflogicseparationisfurtherpronouncedwhenworkinginateamenvironment,inwhichit’scommonfordevelopersanddesignerstobumpheadswhiletryingtoeditthesamefileatthesametime.
OptimizedapproachWiththereviewofstandardmethodsoutoftheway,let’slookattheoptimizedapproach.It’sjustasbeneficial—andoftenthebestmethodologyforJavaScript-centricanimationworkflows—toshiftanimationstylinglogicintoadedicatedJavaScriptfile(forexample,astyle.js)ratherthanadedicatedCSSstylesheet.Soundsweird,right?Perhaps,butitworksbrilliantly.ThistechniqueleveragesplainoldJavaScriptobjectstohelpyouorganizeyouranimationcode.
Forexample,yourstyle.jsfilemightlooklikethis:Clickheretoviewcodeimage
//ThisobjectisaparalleltotheCSSclassdefinedinthepreviouscode
example
varfadeIn={
opacity:1,
top:“50px”
};
Inyourscript.js,whichistheprimaryJavaScriptfilethatcontrolsanimationlogic,youwouldthenhave:Clickheretoviewcodeimage
//PassournamedpropertiesobjectintoVelocity
$element.velocity(fadeIn,1000);
Torecap,inyourstyle.js,you’vedefinedaJavaScriptobjectthat’spopulatedwiththeCSSpropertiesyouwanttoanimate.Thisisthesameobjectthat’sthenpassedintoVelocityasafirstargument.You’renotdoinganythingfancyhere—justsavingobjectstonamedvariables,thenpassingthosevariablesintoVelocityinsteadoftherawobjectsthemselves.
Note
ThistechniqueworksequallywellwithjQuery’sanimate()function.
ThebenefitofswitchingfromCSStoJavaScripttosegregatelogicisthatyourstyle.jsfileisuniquelycapableofdefininganimationoptions—notjustanimationproperties.Therearemanywaystospecifyanoption:oneistoassigntwomemberpropertiestoaparentanimationobjecttowhichyouassignanexpressivename.Thefirstpropertyontheobjectdefinestheanimation’sproperties;theseconddefinesitsoptions.
Inthiscase,yourstyle.jsfilewouldlooklikethis:Clickheretoviewcodeimage
varfadeIn={
//pisfor“properties”
p:{
opacity:1,
top:“50px”
},
//oisfor“options”
o:{
duration:1000,
easing:“linear”
}
};
Inthescript.jsfile,you’dhave:Clickheretoviewcodeimage
//Passinourcleanandre-usableanimationobjects
$element.velocity(fadeIn.p,fadeIn.o);
Prettyandclean,right?Someoneskimmingitwouldunderstanditspurpose,andwould
knowwheretolooktomodifyitsproperties—thestyle.jsfile.Further,thepurposeofthisanimationisimmediatelyevident:becauseyou’venamedtheanimationobjectappropriately,youknowthatthecodeservestofadeanobjectintoview.Younolongerhavetomentallyparseanimationpropertiestoassessthepurposeoftheanimation.
Thisapproachdiscouragesyoufromarbitrarilysettingoptionsforeachindividualanimationonapagesincethere’snowabankofpremadeanimationobjectsyoucaneasilypullfrom.Thisresultsinleanercodeandmoreconsistentmotiondesign.Consistency,asyoulearnedinthepreviouschapter,isakeycomponentofgreatUX.
Butthebestpartisthatthisapproachlendsitselfperfectlytoorganizingyouranimationvariationstogether.Forexample,ifyoutypicallyfadebuttonelementsintoviewwithadurationof1000ms,butyoufademodalwindowsintoviewwithadurationof3000ms,youcansimplysplityouroptionsobjectintotwoappropriatelynamedvariations:Clickheretoviewcodeimage
varfadeIn={
p:{
opacity:1,
top:“50px”
},
//Optionsobjectvariation#1usesafastduration
oFast:{
duration:1000,
easing:“linear”
},
//Variation#2usesaslowerduration
oSlow:{
duration:3000,
easing:“linear”
}
};
//Animateusingthefastduration.
$button.velocity(fadeIn.p,fadeIn.oFast);
/*Animateusingtheslowduration.*/
$modal.velocity(fadeIn.p,fadeIn.oSlow);
Alternatively,youcouldnest“fast”and“slow”objectsaschildrenofasingularooptionsobject.Thechoiceofwhichimplementationtouseisbasedonyourpersonalpreference:Clickheretoviewcodeimage
varfadeIn={
p:{
opacity:1,
top:“50px”
},
o:{
fast:{
duration:1000,
easing:“linear”
},
slow:{
duration:3000,
easing:“linear”
}
}
};
//Animateusingthefastduration.
$button.velocity(fadeIn.p,fadeIn.o.fast);
/*Animateusingtheslowduration.*/
$modal.velocity(fadeIn.p,fadeIn.o.slow);
Ifthisseemsliketoomuchoverhead,andifyouhavefewenoughlinesofJavaScripttojustifysimplyinliningallyouranimationlogic,thendon’tfeellikeabaddeveloperforskippingthisapproachaltogether.Youshouldalwaysusewhicheverdegreeofabstractionbestsuitsthescopeofyourproject.Thetakeawayhereissimplythatanimationworkflowbestpracticesdoexistifyoufindyourselfneedingthem.
Codetechnique:OrganizesequencedanimationsVelocityhasasmalladd-onplugincalledtheUIpack(getitatVelocityJS.org/#uiPack).ItenhancesVelocitywithfeaturesthatgreatlyimprovetheUIanimationworkflow.Manyofthetechniquesinthischapter,includingtheonediscussedbelow,makeuseofit.
ToinstalltheUIpack,simplyincludea<script>tagforitafterVelocityandbeforetheending</body>tagofyourpage:Clickheretoviewcodeimage
<scriptsrc=“velocity.js”></script>
<scriptsrc=“velocity.ui.js”></script>
ThespecificUIpackfeaturediscussedinthissectioniscalledsequencerunning.Itwillforeverchangeyouranimationworkflow.Itisthesolutiontomessilynestedanimationcode.
StandardapproachWithouttheUIpack,thestandardapproachtoconsecutivelyanimatingseparateelementsisasfollows:Clickheretoviewcodeimage
//Animateelement1followedbyelement2followedbyelement3
$element1.velocity({translateX:100,opacity:1},1000,function(){
$element2.velocity({translateX:200,opacity:1},1000,function(){
$element3.velocity({translateX:300,opacity:1},1000);
});
});
Don’tletthissimpleexamplefoolyou:inreal-worldproductioncode,animationsequencesincludemanymoreproperties,manymoreoptions,andmanymorelevelsofnestingthanaredemonstratedhere.Codelikethismostcommonlyappearsinloadingsequences(whenapageorasubsectionfirstloadsin)thatconsistofmultipleelementsanimatingintoplace.
Notethatthecodeshownaboveisdifferentfromchainingmultipleanimationsontothesameelement,whichishassle-freeanddoesn’trequirenesting:Clickheretoviewcodeimage
//Chainmultipleanimationsontothesameelement
$element1
.velocity({translateX:100})
.velocity({translateY:100})
.velocity({translateZ:100});
Sowhat’swrongwithfirstcodesample(theonewithdifferentelements)?Herearethemainissues:
Thecodebloatshorizontallyveryquicklywitheachlevelofnesting,makingitincreasinglydifficulttomodifythecodewithinyourIDE.
Youcan’teasilyrearrangetheorderofcallsintheoverallsequence(doingsorequiresverydelicatecopyingandpasting).
Youcan’teasilyindicatethatcertaincallsshouldrunparalleltooneanother.Let’ssaythathalfwaythroughtheoverallsequenceyouwanttwoimagestoslideintoviewfromdifferentoriginpoints.Whencodingthisin,itwouldn’tbeobvioushowtonestanimationsthatoccurafterthisparallelmini-sequencesuchthattheoverallsequencedoesn’tbecomeevenmoredifficulttomaintainthanitalreadyis.
OptimizedapproachBeforeyoulearnaboutthebeautifulsolutiontothisuglyproblem,it’simportanttounderstandtwosimplefeaturesofVelocity.First,knowthatVelocityacceptsmultipleargumentsyntaxes:themostcommon,whenVelocityisinvokedonajQueryelementobject(likeallthecodeexamplesshownsofar),consistsofapropertiesobjectfollowedbyanoptionsobject:Clickheretoviewcodeimage
//Theargumentsyntaxusedthusfar
$element.velocity({opacity:1,top:“50px”},{duration:1000,easing:
“linear”});
AnalternativesyntaxpairswithVelocity’sutilityfunction,whichisthefancynamegiventoanimatingelementsusingthebaseVelocityobjectinsteadofchainingoffofajQueryelementobject.Here’swhatanimatingoffthebaseVelocityobjectlookslike:Clickheretoviewcodeimage
//VelocityregistersitselfonjQuery’s$object,whichyouleveragehere
$.Velocity({e:$element,p:{opacity:1,scale:1},o:{duration:1000,
easing:“linear”}});
Asshownabove,thisalternativesyntaxconsistsofpassingVelocityasingleobjectthatcontainsmemberobjectsthatmaptoeachofthestandardVelocityarguments(elements,properties,andoptions).Forthesakeofbrevity,thememberobjectnamesaretruncatedtothefirstletteroftheirassociatedobjects(eforelements,pforproperties,andoforoptions).
Further,notethatyou’renowpassingthetargetelementinasanargumenttoVelocitysinceyou’renolongerinvokingVelocitydirectlyontheelement.Theneteffectisexactlythesameasthesyntaxyouusedearlier.
Asyoucansee,thenewsyntaxisn’tmuchbulkier,butit’sequally—ifnotmore—expressive.Armedwiththisnewsyntax,you’rereadytolearnhowtheUIpack’ssequence-runningfeatureworks:yousimplycreateanarrayofVelocitycalls,witheach
calldefinedusingthesingle-objectsyntaxjustdemonstrated.YouthenpasstheentirearrayintoaspecialVelocityfunctionthatfiresthesequence’scallssuccessively.WhenoneVelocitycalliscompleted,thenextruns—eveniftheindividualcallsaretargetingdifferentelements:Clickheretoviewcodeimage
//CreatethearrayofVelocitycalls
varloadingSequence=[
{e:$element1,p:{translateX:100,opacity:1},o:{duration:1000
}},
{e:$element2,p:{translateX:200,opacity:1},o:{duration:1000
}},
{e:$element3,p:{translateX:300,opacity:1},o:{duration:1000
}}
];
//Passthearrayinto$.Velocity.RunSequencetokickoffthesequence
$.Velocity.RunSequence(loadingSequence);
Thebenefitshereareclear:
Youcaneasilyreorderanimationsintheoverallsequencewithoutfearofbreakingnestedcode.
Youcanquicklyeyeballthedifferencebetweenpropertiesandoptionsobjectsacrossthecalls.
Yourcodeishighlylegibleandexpressivetoothers.
Ifyoucombinethistechniquewiththeprevioustechnique(turningCSSclassesintoJavaScriptobjects),youranimationcodestartstolookremarkablyelegant:Clickheretoviewcodeimage
$.Velocity.RunSequence([
{e:$element1,p:{translateX:100,opacity:1},o:slideIn.o},
{e:$element2,p:{translateX:200,opacity:1},o:slideIn.o},
{e:$element3,p:{translateX:300,opacity:1},o:slideIn.o}
]);
Expressivenessandmaintainabilityaren’ttheonlybenefitstosequencerunning:youalsogaintheabilitytorunindividualcallsinparallelusingaspecialsequenceQueueoptionwhich,whensettofalse,forcestheassociatedcalltorunparalleltothecallthatcamebeforeit.Thisletsyouhavemultipleelementsanimateintoviewsimultaneously,givingasingleVelocitysequencethepowertointricatelycontroltimingthatwouldnormallyhavetobeorchestratedthroughmessycallbacknesting.Refertotheinlinedcommentsbelowfordetails:Clickheretoviewcodeimage
$.Velocity.RunSequence([
{elements:$element1,properties:{translateX:100},options:{
duration:1000}},
//Thefollowingcallwillstartatthesametimeasthefirstcallsince
itusesthe`sequenceQueue:false`option
{elements:$element2,properties:{translateX:200},options:{
duration:1000,sequenceQueue:false},
//Asnormal,thecallbelowwillrunoncethesecondcallhascompleted
{elements:$element3,properties:{translateX:300},options:{
duration:1000}
];
Codetechnique:PackageyoureffectsOneofthemostcommonusesofmotiondesignisfadingcontentinandoutofview.Thistypeofanimationoftenconsistsofaseriesofindividualanimationcallsthatarechainedtogethertodeliveranuanced,multistageeffect.
StandardapproachInsteadofsimplyanimatingtheopacityofanelementtoward1,youmightsimultaneouslyanimateitsscalepropertysothattheelementappearstobothfadeinandgrowintoplace.Oncetheelementisfullyinview,youmightchoosetoanimateitsborderthicknessto1remasafinishingtouch.Ifthisanimationweretohappenmultipletimesacrossapage,andonmanydifferentelements,itwouldmakesensetoavoidcoderepetitionbyturningitintoastandalonefunction.Otherwise,you’dhavetorepeatthisnon-expressivecodethroughoutyourscript.js:Clickheretoviewcodeimage
$element
.velocity({opacity:1,scale:1},{duration:500,easing:“ease-in-out”
})
.velocity({borderWidth:“1rem”},{delay:200,easing:“spring”,
duration:400});
Unlikethesequencingtechniquediscussedintheprevioussection,thecodeaboveconsistsofmultipleanimationsthatalloccuronthesameelement.Chainedanimationsonasingularelementconstituteaneffect.Ifyouweretoimprovethiseffectbyimplementingthefirsttechniqueinthischapter(turningCSSclassesintoJavaScriptobjects),you’dhavetogooutofyourwaytouniquelynameeachargumentobjectforeachstageintheoverallanimation.Notonlyisitpossiblethattheseobjectswouldn’tbeusedbyotherportionsoftheanimationcodeduetotheuniquenessofthisparticularsequence,butyou’dhavetodealwithappendingintegerstoeachanimationcall’srespectiveobjectstodelineatethemfromoneanother.Thiscouldgetmessy,andcouldneutralizetheorganizationalbenefitandbrevityofturningCSSclassesintoJavaScriptobjects.
Anotherproblemwitheffectssuchastheoneaboveisthatthecodeisn’tveryself-descriptive—itspurposeisn’timmediatelyclear.Whyaretheretwoanimationcallsinsteadofone?Whatisthereasoningbehindthechoiceofpropertiesandoptionsforeachoftheseindividualcalls?Theanswerstothesequestionsareirrelevanttothecodethattriggerstheanimation,andshouldconsequentlybetuckedaway.
OptimizedapproachVelocity’sUIpackletsyouregistereffectsthatyoucansubsequentlyreuseacrossasite.Onceaneffectisregistered,youcancallitbypassingitsnameintoVelocityasitsfirstparameter:Clickheretoviewcodeimage
//Assumeweregisteredoureffectunderthename“growIn”
$element.velocity(“growIn”);
That’salotmoreexpressive,isn’tit?Youquicklyunderstandthecode’spurpose:Anelementwillgrowintoview.Thecoderemainsterseandmaintainable.
What’smore,aregisteredeffectbehavesidenticallytoastandardVelocitycall;youcanpassinanoptionsobjectasnormalandchainotherVelocitycallsontoit:Clickheretoviewcodeimage
$element
//Scrolltheelementintoview
.velocity(“scroll”)
//Thentriggerthe“growIn”effectonit,withthefollowingsettings
.velocity(“growIn”,{duration:1000,delay:200})
IftheUIpackisloadedontoyourpage,aneffectsuchasthisisregisteredusingthefollowingsyntax:Clickheretoviewcodeimage
$.Velocity.RegisterEffect(name,{
//Defaultdurationvalueifoneisn’tpassedintothecall
defaultDuration:duration,
//ThefollowingVelocitycallsoccuroneafteranother,witheachtaking
up
apredefinedpercentageoftheeffect’stotalduration
calls:[
[propertiesObject,durationPercentage,optionsObject],
[propertiesObject,durationPercentage,optionsObject]
],
reset:resetPropertiesObject
});
Let’sbreakdownthistemplatestepbystep:
1.Thefirstargumentisthenameoftheeffect.Iftheeffectisresponsibleforbringinganelementintoview(asin,itfadesanelement’sopacityfrom0to1),it’simportanttosuffixtheeffectwith“In”.
2.Thesecondargumentisanobjectthatdefinestheeffect’sbehavior.ThefirstpropertyinthisobjectisdefaultDuration,whichletsyouspecifythedurationthefulleffectshouldtakeifoneisnotpassedintotheVelocitycallthattriggerstheeffect.
3.Thenextpropertyintheobjectisthecallsarray,whichconsistsoftheVelocitycallsthatconstitutetheeffect(intheorderthattheyshouldoccur).Eachofthesearrayitemsisanarrayitself,whichconsistsofthecall’spropertiesobject,followedbytheoptionalpercentageofthetotaldurationwhichthatcallshouldconsume(adecimalvaluethatdefaultsto1.00),followedbyanoptionaloptionsobjectforthatspecificcall.NotethatVelocitycallsspecifiedwithinthecallsarrayacceptonlytheeasinganddelayoptions.
4.Finally,youhavetheoptionofpassinginaresetobject.TheresetobjectisspecifiedusingthesamesyntaxasastandardVelocitypropertiesmapobject,butitisusedtoenactanimmediatevaluechangeuponcompletionofthefulleffect.Thisisusefulwhenyou’reanimatingtheopacityandscalepropertiesofanelementdownto0(outofview),butwanttoreturntheelement’sscalepropertyto1after
theelementishiddensothatsubsequenteffectsneedn’tworryaboutthepropertiesbeyondopacitytheymustresetontheelementfortheircallstoproperlytakeeffect.Inotherwords,youcanleveragetheresetpropertiesmaptomakeeffectsself-contained,suchthattheyleavenocleanupdutiesonthetargetelements.
Inadditiontotheresetobject,anotherpowerfulworkflowbonusoftheUIpack’seffectregistrationisautomaticdisplaypropertytoggling.Whenanelementbeginsanimatingintoview,youwanttoensureitsdisplayvalueissettoavalueotherthan“none”sotheelementisvisiblethroughoutthecourseofitsanimation.(Remember,display:noneremovesanelementfromthepage’sflow.)Conversely,whenfadinganelementout,youoftenwanttoensureitsdisplayvalueisswitchedto"none"onceitsopacityhits0.Thisway,youremovealltracesoftheelementwhenyou’redoneusingit.
UsingjQuery,displaytogglingisaccomplishedbychainingtheshow()andhide()helperfunctionsontoanimations(oftentimesmessilyburiedwithinnestedcallbacks).WithVelocity’sUIpack,however,thislogicistakencareofautomaticallywhenyousuffixyoureffectnameswith“In”and“Out”asappropriate.
Let’sregistertwoUIpackeffects—oneforthe“In”directionandoneforthe“Out”direction—andcalltheelement“shadowIn”sinceitconsistsoffadingandscalinganelementintoview,thenexpandingitsboxShadowpropertyoutward:Clickheretoviewcodeimage
$.Velocity
.RegisterEffect(“shadowIn”,{
defaultDuration:1000,
calls:[
[{opacity:1,scale:1},0.4],
[{boxShadowBlur:50},0.6]
]
})
.RegisterEffect(“shadowOut”,{
defaultDuration:800,
calls:[
//Wereversetheordertomirrorthe“In”direction
[{boxShadowBlur:50},0.2],
[{opacity:0,scale:0},0.8]
]
});
Ifyoureffect’snameendswith“Out”,Velocitywillautomaticallysettheelement’sdisplaypropertyto“none”oncetheanimationiscomplete.Conversely,ifyoureffect’snameendswith“In”,Velocitywillautomaticallysettheelement’sdisplaypropertytothedefaultvalueassociatedwiththeelement’stagtype(forexample,"inline"foranchors,"block"fordivandp).Ifyoureffect’snamedoesnotcontainoneofthesespecialsuffixes,theUIpackwillnotperformautomaticdisplaysetting.
Registeringeffectsnotonlyimprovesyourcode,butalsomakesithighlyportablebetweenprojectsandamongfellowdevelopers.Whenyou’vedesignedaneffectyoulove,nowit’spainlesstosharetheeffect’sregistrationcodewithotherssotheycanuseittoo.Prettyneat!
DesigntechniquesThetechniquesdiscussedsofarinthischapterwillimproveyourworkflowduringthecodingphaseofmotiondesign.Thetechniquescoveredinthissectionfocusonthedesignphase,whereyou’restillexperimentingtofindtheperfectanimationthatfitsyourUI.Thisphaserequiresalotofcreativityandalotofrepetition,andisaccordinglyripeforworkflowimprovements.
TimingmultipliersThefirstdesigntechniqueistouseaglobaltimingmultiplier.Thisconsistsofsprinklinginamultiplierconstantagainstallofyouranimations’delayanddurationvalues.
Startbydefiningyourglobaltimingmultiplier(arbitrarilydesignatedasMformultiplier):
varM=1;
Then,bakethemultiplierintothedurationanddelayoptionvalueswithineachanimationcall:Clickheretoviewcodeimage
$element1.animate({opacity:1},{duration:1000*M});
$element2.velocity({opacity:1},{delay:250*M});
Note
ifyouuseSASSorLESS,whichprovidesupportforvariableusagewithinstylesheets,thistechniqueappliesequallytoCSSanimations!
EmbeddingamultiplierconstantwillhelpyouquicklymodifytheMconstantinonelocation(presumablyatthetopofyourstyle.js)inordertoquicklyspeeduporslowdownalloftheanimationsacrossyourpage.Benefitsofsuchtimingcontrolinclude:
Slowingdownanimationstoperfectthetimingofindividualanimationcallswithinacomplexanimationsequence.Whenyou’reconstantlyrefreshingyourpageinordertotweakamulti-elementanimationsequencetoperfection,seeingthesequenceinslowmotionmakesitsignificantlyeasiertoassesshowindividualelementsinteractwithoneanother.
Speedingupanimationswhenyou’reperformingrepetitiveUItesting.Whenyou’retestingasiteforpurposesotherthananimation,evaluatingtheendstateofUIanimations(howelementswindup)ismoreimportantthantestingtheanimations’motion.Inthesesituations,itsavestimeandreducesheadachestospeedupalltheanimationsacrossyourpagesoyou’renotrepeatedlywaitingforyouranimationstoplayoutoneachpagerefresh.
Velocityhasahandyimplementationofthisfunctionalitycalledmock,whichfunctionsasabehind-the-scenesglobalmultipliersoyoudon’thavetosprinkleintheMconstantbyhand.Liketheexampleshownabove,mockmultipliesboththedurationandthedelayvalues.Toturnmockon,temporarilyset$.Velocity.mocktothemultiplier
valueyouwanttouse:Clickheretoviewcodeimage
//Multiplyallanimationtimingby5
$.Velocity.mock=5;
//Allanimationsarenowtime-adjusted
//Thedurationbeloweffectivelybecomes5000ms
$element.velocity({opacity:1},{duration:1000});
Velocity’smockfeaturealsoacceptsaBooleanvalue:settingmocktotruesetsalldurationsanddelaysto0ms,whichforcesallanimationstocompletewithinasinglebrowsertimingtick,whichoccurseveryfewmilliseconds.Thisisapowerfulshortcutforquicklyturningoffallanimationswhenthey’regettinginthewayofyourUIdevelopmentandtesting.
UseVelocityMotionDesignerVelocityMotionDesigner(VMD)wascraftedwiththesolepurposeofhelpingdevelopersstreamlinethecreationphaseofmotiondesign.VMDisabookmarkletthatyouloadontoapageinordertodesignanimationsinrealtime.Itallowsyoutodouble-clickelementstoopenamodalthatletsyouspecifyanimationpropertiesandoptionsforthatelement.YouthenhitEnteronyourkeyboardtowatchtheanimationplayoutimmediately—withoutapagerefresh.
Note
GetVelocityMotionDesignerathttp://velocityjs.org/#vmd.
Onceyou’vedesignedallyourelementanimationsexactlythewayyouwantthem,youcanexportyourworkintoone-for-oneVelocitycode,whichyoucanplaceimmediatelyintoanIDEforuseinproduction.(TheresultingcodeisalsofullycompatiblewithjQuery.)
Ultimately,VMDsavescountlesshoursofdevelopmenttimebypreventingconstantIDEandbrowsertabswitchingandrepeatedUIstateretriggering.Further,itstreamlinesthedesigner-to-developerworkflowbyallowingthetwoteamstoworkalongsideoneanotherinrealtime:withVMD,designerscanimplementmotiondesignwithouthavingtofamiliarizethemselveswithasite’sJavaScriptorCSS.TheycansimplyhandofftheexportedVelocitycodetothedeveloperstointegrateintothecodebaseattheirdiscretion.
VMDisahighlyvisualtool—visitVelocityJS.org/#vmdtoseethewalkthroughvideo.
WrappingupAsyouimplementanimationworkflowtechniques,you’llnoticetheintimidatingblackboxofmotiondesignbeginningtounfold.Thebeautifullyintricateloadingsequencesfoundoncutting-edgesiteslikeStripe.comandWebflow.comwillstarttomakesensetoyou.You’llgainconfidenceinyourabilitytocodeanimationsequences,andthisnewfoundskillwillreducefrictioninyourdevelopmentroutine,makingitnotonlyeasierbutalsosignificantlymorefuntoaccomplishyourmotiondesigngoals.
Chapter5.AnimatingText
Sincetextualanimationisrarelyemployedinwebpages,usingitisaneasywaytoimpressusers.That’spreciselywhatmakesthistopicsomuchfuntolearn:theunderlyingtechniquesaresimpletoprogram,buttheresultsfeelincrediblyrichandcomplextotheuser.
Thischapterintroducesyoutotoolsthatremovethetediousaspectsoftextualanimationandequipyouwithanefficientworkflow.Readontolearnthenuancesofthisdarkart.
ThestandardapproachtotextanimationThestandardHTMLelementswecodesiteswith—divs,tables,anchortags,andthelike—arethelowest-levelcomponentsofawebpagethatcanbestyled.Soitmakessensethatthesearethelowest-levelcomponentsthatcanbeanimated.
Textdoesnotconstituteanelementuntoitself;ablockoftextisdesignatedbythebrowserasatextnode,whichisanunstylable,lower-levelcomponentthatmustbecontainedbyanelement.Furthercomplicatingmattersisthefactthatthebrowserdoesnotsubdividetextnodesintogrammaticalcomponents;thereisnowaytoaccessindividualletters,words,orsentences.
Consequently,toanimatetextonaletter,word,orsentencebasis,youhavetobreakeachtextnodeintoseparatetextnodes,andthenwrapeachoftheseinanewelement.Youcanthenanimatethem.Butmanuallywrappingtextinspanelements,forexample,istediousworkthatresultsinbloatedHTML.
It’snosurprisethenthattextanimationonthewebisuncommon;it’stypicallytoomuchofahassletodealwith.Thisputsthewebatanaestheticdisadvantagetodedicatedmotiondesignsoftware,suchasAdobeAfterEffects,whichallowsforthefine-grainedanimationoftext—theresultsofwhicharecommonlyseeninTVcommercialsandmovietitlesequences.Theseeffectscanlookabsolutelybeautiful.Unfortunately,inadditiontobeingdifficulttointegrateontheweb,they’realsowidelyconsideredbadpractice.Afterall,thewebisamediumthatprioritizesfunctionoverform,andtextanimationislargelyaboutform.
However,thereisonetextualanimationusecasethatcancarryoverwelltothewebwhenusedsparingly:ifyoupaycloseattentiontothedepictionsoffuturistichardwareinterfacesinmovies,you’llnoticethecommonthreadoftextbeinganimatedintooroutofviewonagrammaticallevel.Thefutureofcomputing,accordingtopopculture,consistsofwordsandsentencesanimatingwithflickers,glitches,pops,andblurs.Theseeffectslookcool,andthereisn’tmuchdownsidetoembracingthemforthepurposesoftransitioningcontentintooroutofviewsincethetexthadtoundergoavisibilityanimationbyonemeansoranother.Thisconceptoftransitioningtextvisibilityispreciselywhatyou’lllearnaboutinthischapter.
PreparingtextelementsforanimationwithBlast.jsThetoolofchoicefortypographicanimationisBlast.js,whichhandilybreaksblocksoftextintocharacters,words,andsentences.YoucanthenanimatetheresultingpartsusingVelocityanditsUIpackplugin.
Note
GetBlast.jsatJulian.com/research/blast.
Blast.jshasthreedelimitertypestodefinethegrammaticalcomponentstobeindividuallyextracted:character,word,andsentence.Supposeyouhaveadivthatlookslikethis:
<div>
HelloWorld
</div>
IfyoucallBlastonthisdivusingthefollowingsyntaxClickheretoviewcodeimage
$(“div”).blast({delimiter:“word”});
thedivwouldturnintothis:Clickheretoviewcodeimage
<divclass=“blast-root”>
<spanclass=“blast”>Hello</span>
<spanclass=“blast”>World</span>
</div>
Asyoucansee,Blastseparatedthetargetdiv’stextintotextpartsthatareindividuallywrappedinspanelements.Ifyouweretoinsteadusethecharacterdelimiter,theresultwouldhavebeen:Clickheretoviewcodeimage
<divclass=“blast-root”>
<spanclass=“blast”>H</span>
<spanclass=“blast”>e</span>
<spanclass=“blast”>l</span>
<spanclass=“blast”>l</span>
<spanclass=“blast”>o</span>
<spanclass=“blast”></span>
<spanclass=“blast”>W</span>
<spanclass=“blast”>o</span>
<spanclass=“blast”>r</span>
<spanclass=“blast”>l</span>
<spanclass=“blast”>d</span>
</div>
Youcannowanimatethesespanelementsindependently.Beforeyoudiveintotextualanimation,however,you’regoingtolearnmoreabouthowBlastworkssoyoucantakefulladvantageofitspowerfulfeatures.
HowBlast.jsworksThegoalofthissectionistomakeyoucomfortablewiththeprospectofusingBlasttobreakapartthetextonyourbelovedpage.Let’sdivein!
divs,tables,andtheotherHTMLelementsthatyou’refamiliarwitharecalledelementnodes.Anelementnodecommonlyconsistsoftwotypesofchildren:additionalelementnodesandtextnodes(rawtext).
Takethiselement,forexample:<div>
Hello<span>World</span>
</div>
Thisdivelementiscomposedoftwochildren:atextnode(“Hello”)andaspanelementnode.Thespanelementnodecontainsachildofitsown:anothertextnode(“World”).
WhenBlastiscalled,ittraversestheentiretyofthetargetelement’sdescendantelementchaintofindtextnodes.Witheachtextnode,BlastexecutestheRegExqueryassociatedwiththespecifieddelimitertype(character,word,orsentence)tosubdividethenodeintonewelements,eachwithitsowntextnodepart.SinceBlastdoesn’tactuallysubdivideelementnodes—onlytextnodes—youcansafelyapplyittotheentirepagewithoutworryingaboutbreakingelements’eventhandlersandotherexpectedbehaviors.ThisversatilityiscrucialwhenusingBlastonuser-generatedcontentthatisoftendirtiedwithHTML.(Say,forexample,youwanttoseparatethewordsinamessagepostedtoyoursite’scommentssectionsoyoucanhighlightimportantpassages.WithBlast,youcansafelydosowithoutconcernforbreakingtheuser’sembeddedlinks.)
Inadditiontoitsrobustness,Blastprovidesahighlevelofaccuracy.Itdoesn’tdumblysplitwordsatspaces,nordoesitsplitsentencesatperiodswithinwords.ItleveragesUTF-8charactersetsforLatinalphabetlanguages,meaningthatyoucanaccuratelyapplyittoFrench,German,Spanish,English,Italian,andPortuguesecontent.
SupposeyouusedBlast’ssentencedelimiteronthefollowingparagraph.(BoldanditalicareusedbelowtoindicatetheconsecutivetextmatchesthatBlastdetects.)Blastcorrectlyidentifiedsixsentencesintheparagraph:
¿WillthesentencedelimiterrecognizethisfullsentencecontainingSpanishpunctuation?¡Yes!«Mais,oui!»“Nested“quotes”don’tbreakthesentencedelimiter!”Further,periodsinsidewords(e.g.Blast.js),informaltitles(e.g.Mrs.Bluth,Dr.Fünke),andin“e.g.”and“i.e.”donotfalselymatchassentence-finalpunctuation.Darn.That’sprettyimpressive.
Noticehowpunctuationisassociatedwithitspropersentence,andhowerrantperiodsdon’tfalselydemarcatesentencematches.
Withthesefoundationscovered,it’stimetorunthroughhowtouseBlast.
InstallationBlastisinstalledonapagelikeanyotherJavaScriptplugin:embedtheappropriatescriptlinkbeforeyourpage’s</body>tag:Clickheretoviewcodeimage
<html>
<head>MyPage</head>
<body>
Mycontent.
<scriptsrc=“jquery.js”></script>
<scriptsrc=“velocity.js”></script>
<scriptsrc=“blast.js”></script>
</body>
</html>
Note
BlastrequiresjQuery(orZepto,ajQueryalternative),andthereforemustberequiredafterjQuery.Itdoesn’tmatterwhetherBlastisloadedbeforeorafterVelocity.
OnceBlastisloaded,useitbycalling.blast()onajQueryelementobject.Itacceptsanoptionsobjectasitssoleargument:Clickheretoviewcodeimage
$element.blast({option1:value1,option2:value2});
Let’srunthroughtheavailableoptions.
Option:DelimiterBlast’smostimportantoptionisdelimiter,whichaccepts"character","word",or"sentence".Toseparatethetextwithin$elementusingthe"sentence"delimiter,yourcodewouldlooklikethis:Clickheretoviewcodeimage
$element.blast({delimiter:“sentence”});
NotethatBlastreturnsthegeneratedtextwrapperelementstothejQueryselectorchainsoyoucanmanipulatethem,likethis:Clickheretoviewcodeimage
$element.blast({delimiter:“sentence”})
.css(“opacity”,0.5);
The.css()callisappliedtotheindividualtextelements,nottheparent$elementthatyoucalledBlaston.
Option:customClassBlastprovidestwooptionstomaketextmanipulationeasier:customClassandgenerateValueClass.customClassbehavesexactlyasyouwouldexpect:supplyacustomclass(asastringvalue)tobeassignedtothetextnodewrapperelements.
SupposeyouhadthefollowingdivandBlastcall:Clickheretoviewcodeimage
<div>
HiMom
</div>
$(“div”).blast({delimiter:“word”,customClass:“myClass”});
Thedivwouldturnintothefollowing(notehowBlastautomaticallyassignseverytextpartthe"blast"classbydefault):Clickheretoviewcodeimage
<div>
<spanclass=“blastmyClass”>Hi</span>
<spanclass=“blastmyClass”>Mom</span>
</div>
ThevalueinprovidingacustomclassisindifferentiatingtheelementsgeneratedbyeachBlastcall.If,forexample,youusedBlastintwolocationsonyourpage—onceintheheaderandonceinthefooter—itmightbehelpfultoassignthesetwocallsdifferentclassessoyoursubsequentJavaScriptcodeandCSSstylescanactonthetextelementsappropriately.
Option:generateValueClassgenerateValueClasstakesaBooleanvalue(trueorfalse)indicatingwhetherauniqueclass,intheformof.blast-[delimiter]-[textValue],shouldbeassignedtothegeneratedtextelements.
Note
Thisoptionisapplicableonlytothecharacterandworddelimiters.
The[delimiter]placeholderrepresentsthedelimitertypeusedinthecall,andthe[textValue]placeholderrepresentsthetextcontainedwithinanindividualelement.Considerthefollowingexample:Clickheretoviewcodeimage
<div>
HiMom
</div>
$(“div”).blast({delimiter:“word”,generateValueClass:true});
Theelementwouldturnintothis:Clickheretoviewcodeimage
<divclass=“blast-root”>
<spanclass=“blastblast-word-Hi”>Hi</span>
<spanclass=“blastblast-word-Mom”>Mom</span>
</div>
WhenBlastiscalledwiththeletterdelimiter,theelementwouldturnintothisinstead:Clickheretoviewcodeimage
<divclass=“blast-root”>
<spanclass=“blastblast-letter-H”>H</span>
<spanclass=“blastblast-letter-i”>i</span>
…andsoon…
</div>
ThegenerateValueClassoptionisusefulwhenyouneedtouseCSSorJavaScripttomanipulatetextmatchesbasedonthetextcontainedwiththem.If,forexample,youusedthisfeatureonabookexcerpt,youcouldcreateavisualizationofallinstancesoftheword“and”bygivingelementswiththe.blast.word-andclassayellowbackground:Clickheretoviewcodeimage
//jQueryimplementation
$(“.blast-word-and”).css(“background”,“yellow”);
//RawJavaScriptimplementation
document.querySelectorAll(“.blast-word-and”).forEach(function(item){
item.style.background=“yellow”;});
//CSSimplementation
.blast-word-and{
background:yellow;
}
Thankstothisfeature,youcanpainlesslytargettextmatchesviaeitherCSSorJavaScriptwithouthavingtousemessycustomcodetoindividuallycheckthetextcontentsofeachelement.
Option:TagThisoptionletsyouspecifythetypeofelementthatwrapstextparts.Thedefaultvalueisspan,butyoucanpassinanyelementtype(forexample,a,div,p).Considerthisexample:Clickheretoviewcodeimage
<div>
HiMom
</div>
//Usethe“div”elementasthewrappertag
$(“div”).blast({delimiter:“word”,tag:“div”});
Theelementwouldconsequentlyturnintothis:<divclass=“blast-root”>
<divclass=“blast”>Hi</div>
<divclass=“blast”>Mom</div>
</div>
ThisfeatureisusefultoensurethattheresultingtextelementsmimicthestructureofthesurroundingHTML.Perhapsnearbysiblingelementsareallofthedivtype,inwhichcasetheaboveexamplemaybeappropriate.
Youmightalsowanttotakeadvantageoftheuniquepropertiesofferedbydifferenttagtypes.strong,forexample,automaticallyboldstext,whereasdivforceseachtextmatchtobeginonanewlinethankstodiv’sdefaultdisplayvalueof"block".
Command:ReverseYoucanundoBlastonanelementbypassingfalseasthesoleparameterintoaBlastcall.Hence,ifyourBlastedelementlookedlikethis:
<divclass=“blast-root”>
<divclass=“blast”>Hi</div>
<divclass=“blast”>Mom</div>
</div>
andyoupassedinthefollowingBlastcall:$(“div”).blast(false);
theelementwouldreturntoitsoriginalstructure:<div>
HiMom
</div>
Youmightbewonderinghowthisworks:whenBlastisreversed,itsimplydestroysthegeneratedwrapperelements,theninsertsrawtextwherethewrapperelementswerepreviously.NotethatthiswillbreakeventhandlersassignedtothenewelementsgeneratedbyBlast,butitwon’tbreakeventhandlersassociatedwiththeHTMLthatexistedpriortoBlastbeinginitiallycalled.
ReversingBlastinthiswayisacrucialcomponentoftextualanimationsincethemodusoperandiwhenanimatingelementsonawebpageistoleavethingsastheywerebeforeyoutouchedthem.If,forexample,you’veBlastedapartasentenceinordertoanimateits
wordsintoviewoneatatime,youwouldsubsequentlyreverseBlastuponcompletionoftheanimation.Consequently,JavaScriptcodethatlaterinteractswiththetextwon’thaveunexpectedchildelementsthatithastoparseout.Inshort,it’sgoodpracticetoavoidleavingyourHTMLunnecessarilybloatedsothatfurtherprogrammaticinteractionwithyourelementsdoesn’tbecomeincreasinglyconvoluted.
Note
TolearnmoreaboutBlast,includingitsuniquesearchcapabilitiesanditscompatibilitywithscreen-readingsoftware,visititsdocumentationatJulian.com/research/blast.
Nowthatyou’veseparatedyourtextelements,it’stimetoanimatethem.
TransitioningtextintooroutofviewThemostcommonuseoftextualanimationisanimatingtextinandoutofview.Abasicimplementationofthisistoanimatethewordsinasentenceintoviewoneafteranother.
ReplacingexistingtextLet’sstartbycreatingacontainerdivwithplaceholdertextthatwillbereplacedbynewtextthatanimatesintoplace:Clickheretoviewcodeimage
<div>
Amessagewillloadhereshortly…
</div>
Becausethedivstartsoutasvisible,Blastingthediv’stextresultsinchildtextelementsthatarevisibleaswell.Sinceyourgoalistoanimatethegeneratedtextelementsintoviewstartingfromastateofinvisibility,youhavetomakethegeneratedtextelementsinvisibleimmediatelyafteryoucallBlast:Clickheretoviewcodeimage
$(“div”)
.html(“Thisisournewmessage.”)
.blast({delimiter:“word”})
.css(“opacity”,0);
.velocity({opacity:1});
Thisreplacesthediv’sexistingtextwithanewmessage.ThenitBlaststhedivusingtheworddelimiter.SinceacalltoBlastreturnsthegeneratedtextwrapperelementstothejQueryselectorchain,youcaneasilyextendthecodetosettheopacityofeachtextelementto0.ThisprimestheelementsforthesubsequentVelocitycall,whichconsistsofasimpleopacityanimation.
Youmayhavenoticedthattheabovecoderesultsinalltextpartsanimatingintoviewsimultaneously.This,ofcourse,defeatsthepurposeofusingBlastinthefirstplace:ifyouwantedallofthediv’scontenttoanimateintoviewsimultaneously,youcouldhavesimplyanimatedthedivitself.Thegoalhereisactuallytoachieveasuccessive
animationsequencethatconsistsofonetextelementanimatingafteranother.
StaggeringThisiswhereVelocity’sUIpackcomesintoplay.(ReviewChapter4,“AnimationWorkflow,”ifyouneedaprimerontheUIpack.)Toimposeasuccessivedelaybetweenanimationstarttimeswithinanelementset,useVelocityUIpack’sstaggeroption,whichexpectsadurationspecifiedinmilliseconds.Applyingittothepreviouscodeexample,youget:Clickheretoviewcodeimage
$(“div”)
.html(“Thisisournewmessage.”)
.blast({delimiter:“word”})
.css(“opacity”,0)
.velocity(“transition.fadeIn”,{stagger:50});
Thecodeaboveproducesasuccessivedelayof50msbetweentheelements’animationstarttimes.Importantly,notetheVelocitycall’sprevious{opacity:1}argumentfor"transition.fadeIn",whichisapremadefadeeffectincludedwithVelocity’sUIpack.(RefertoChapter4,“AnimationWorkflow,”ifyouneedarefresher.)SincethestaggeroptionworkswithUIpackeffects,thisexampleshowstheeffectthatmirrorsanimatingopacitytoavalueonlyof1.
AsdiscussedinChapter3,“MotionDesignTheory,”becarefultokeepstaggertimestoalowdurationsothatusersaren’twaitingneedlesslywhiletextfadesintoview.Keepinmindthatthelongeranelement’swordcount,thegreatertheoveralltimeananimationsequencewilltaketocomplete.Textelementstaggeringisoneoftheeasiestwaystoslipintothebadpracticeofslowingdownyourinterface.
TransitioningtextoutofviewThecodeexampleintheprevioussectiononlyanimatedtextinto—notoutof—view;thediv’spreexistingtextwasimmediatelyreplacedbythenewmessage.Thisdoesn’tnecessarilymakeforpoormotiondesign,butitisoftenbeneficialfromtheperspectiveofmotiondesigntheorytounifyanimationssuchthatanelementfadesoutofviewinawaythatreflectsthewayitfadedintoview.Chapter3,“MotionDesignTheory,”coveredtheconceptofmirroringanimationssothatwhatcomesinreflectswhatgoesout.Thatadviceapplieshere.
Ifyouwanttheoutwardtextualanimationtomirrortheinwardanimation,youcouldreworkthecodeexampleasfollows:Clickheretoviewcodeimage
//Selectthepreviouslyblastedtext
$(“div.blast”).velocity(
//AnimatetheexistingtextoutofviewwiththeappropriateUIpack
effect
“transition.fadeOut”,
{
//Staggertheoutwardanimationasyoudidtheinwardanimation
stagger:50,
backwards:true,
//Whenthisoutwardanimationiscomplete,begintheinwardanimation
complete:function(){
//Proceedwiththeinwardanimation
$(“div”)
.html(message)
.blast({delimiter:“word”})
.css(“opacity”,0)
.velocity({opacity:1},{stagger:50});
}
}
);
ThisbeginsbycallingtheVelocityUIpack"transition.fadeOut"effectonthetextpartsgeneratedbythedivhavingpreviouslybeenBlasted.Aswiththeinwarddirection,thestaggeroptionsuccessivelyoffsetstheindividualtextpartanimationsintheoutwarddirection.NewtothiscallistheuseofVelocityUIpack’sbackwardsoption,whichpairswithstaggertoreversethetargetelementset’sordersothatthelastelement(thelastwordinthesentence)animatesoutofviewbeforethesecond-to-lastelementdoes,andthatelementanimatesoutofviewbeforethethird-to-lastelementdoes,andsoon.Whenthisoutwardanimationsequenceiscomplete,theinwardanimationiscalledfromwithinthecompletecallback.
Usingthebackwardsoptionfortextanimationprovidestwobenefits.First,ithelpsmirror(createtheinverseof)theinwardanimation,whichconsistsofthefirstwordanimatingintoviewbeforethesecondworddoes,andsoon.Second,whenthebackwardanimationisimmediatelyfollowedbytheforwardanimation,thenetresultisanelegantchainingeffectinwhichthelastwordinthebackwarddirectionandthefirstwordintheforwarddirectionoccurback-to-back.Thisworkstotiethetwoanimationsequencestogetherintowhatlookslikeoneconjoinedanimationinsteadoftwoseparateanimationscrudelygluedtogether.
TransitioningindividualtextpartsMovietitlesequencesarewellknownfortheirinventivetypographicmotiondesign.Thetechniqueunderlyingmanyoftheseeffectsissinglingoutindividualtextelementsforanimation.That’swhatthissectioncovers.
Note
Fortypographicanimationinspiration,searchYouTubeformovietitlesequencesandtakedetailednotes!Aslongasyoukeeptheprinciplesofmotiondesigntheoryinmind,youshouldfeelencouragedtoexploretextualanimationdesigninyourinterface.
Toachievefine-grainedcontrolovertheelementsthatBlastgenerates,simplyuseCSS’snth-childselectororjQuery’seq()function.Thesefunctionsbehavesimilarlytooneanother,inthattheyallowfortheselectionofanelementwithinasetbasedonthatelement’sindex.Ifyoupassedanintegervalueof3intothesefunctions(or2inthecaseofjQueryasyouwillsee),theywouldtargetthethirdelement(thatis,thirdword)inthefullelementset(thatis,multiwordsentence):
Clickheretoviewcodeimage
//CSSimplementation
.blast:nth-child(3){
color:red;
}
//jQueryimplementation
$(“.blast”).eq(2).css(“color”,“red”);
Bothexamplesabovetargetthethirdelementonthepagethathasthe.blastclassapplied.(NotethatjQuery’seqfunctionis0-basedwhereasCSS’nth-childis1-based,hencethedifferentintegervaluesbeingpassedintotheexamples.)Let’scontinuewithajQueryimplementationtoworktowardacompleteexample:Clickheretoviewcodeimage
<div>
Currentstatus:paused
</div>
//Blastthedivusingtheworddelimiter
$(“div”).blast({delimiter:“word”})
//Selectthethirdwordinthesentence(thespancontainingthe
“paused”text)
.eq(2)
//Fadethethirdelementoutofviewthenreplaceitsinnertext
withanewmessage
.velocity({opacity:0},function(){$(this).text(“running”);})
//Fadethereplacedtextintoview
.velocity({opacity:1});
ThisBlastsasentence,selectsitsthirdword(“paused”),fadesthewordoutofview,replacesthefadedwordwithanewword(“running”),thenfadesthenewwordintoview.Theneteffectisthatthestatus-indicatingkeywordwithinasentencegracefullyfadesintoanewwordtoalerttheuserofachange.Thisisatremendouslyeleganteffectthatconsistsofonlyafewlinesofsimplecode.Ifyouweretoperformthiseffectmanytimesoveralargerblockoftext,youcouldachieveaneffectinwhichonemessageappearstosporadicallychangeintoanother.
TransitioningtextfancifullyYoucouldeasilyswapthetransition.fadeIneffectyou’veusedthusfarwithanothereffectfromVelocity’sUIpack.Someoftheothereffectsarequitefanciful,rangingfromtransition.shrinkIn,whichcausesanelementtoscaledownintoview,totransition.perspectiveDownIn,whichcausesanelementtorotatedownintoviewlikeahingedbarndoor.(Asalways,thesophisticationofyoureffectsshouldberootedintheprinciplesdiscussedinChapter3,“MotionDesignTheory.”)
Note
ForacompletelistofUIpackeffects,includinglivedemos,visitVelocityJS.org/#uiPack.)
Keepinmindthatsomeeffectsuse3Dtransforms(rotateX,rotateY,andtranslateZ),whichdon’tworkwithonelementswhoseCSSdisplayvalueissetto
"inline"—thedefaultdisplayvalueforspanandanchorelementsinparticular.TheworkaroundistosetBlast’sgeneratedtextelementstoadisplayvalueof"inline-block",whichkeeps"inline"elementsbehavingastheynormallydowhilegivingthemtheaddedfunctionalityof"block"elements(suchasdivandp),inwhichposition-relatedproperties,including3Dtransforms,canbestyled.Takingthisdisplaytweakintoaccount,theinwardtexttransitionexamplewouldnowlooklikethis:Clickheretoviewcodeimage
$(“div”)
.html(message)
.blast({delimiter:“word”})
.css({opacity:0,display:“inline-block”})
.velocity(“transition.perspectiveDownIn”,{stagger:50});
ThissetstheBlastedtextparts’displayvaluesto"inline-block"inthesamecalltojQuery’scss()functionthatsetstheelements’opacitytoastartingvalueof0.
TextualflourishesThefinaltopicinthisdiscussionoftextualanimationistheconceptofflourishes,ambientanimationsthatproduceongoingeffectsforaestheticpurposes.Oneexamplemightbeastringoftextthatflickerslikeadyinglightbulb.Anothermightbehavingallthewordsinasentencecontinuouslyanimatetodifferentshadesofblue.
Bothofthesearebadideas.
Theseeffectsdistractusersandultimatelyamuseonlyyou—thedeveloperwhoenjoystoyingwithmotiondesign.Neverincludeanimationjustforthesakeofanimation;ifapartofyourpageismeaninglesslydrawingtheuser’sattentionawayfromthepartsthathaveutility,gobacktothedrawingboard.
Therareexceptiontothisisstatusindicators—textsuchas“Loading…”—thatkeeptheuserabreastofwhattheinterfaceisdoing.Theseareappropriatetargetsfortextualflourishesbecausetheflourishestelltheuserthattheinterfaceisstillprocessingdata(asopposedtohavingfrozen).Inthisway,flourishesactasanengagingvisualheartbeat.
Soiftextualflourishesaregenerallyconsideredbadpractice,whyisthissectionevenincludedinthebook?Becauseflourishesthataren’tanimatedareoftenagreatidea!Considerthisanon-animationbonusprovidedbyBlast:youcanstylizethetextelementsgeneratedbyBlasttoproducecolorfulcollagesandotheruniquetypographicdesigns.Forexample,youcouldbreakapartawebsite’sslogantext(“Deliveringhappinessrighttoyourdoor!”)wordbywordtoreducetheopacityofeachsuccessiveword,therebycreatingasubtlegradienteffectthatspanstheentiresentence.Here’swhatthatcodewouldlooklike:Clickheretoviewcodeimage
<div>
HiMom
</div>
//Blastthedivtheniteratethroughthegeneratedtextelements
$(“div”).blast({delimiter:“character”}).each(function(i,element){
//Successivelyreducetheopacityofeachelementwithanarbitrary
formula
varadjustedOpacity=1-i/10;
element.style.opacity=adjustedOpacity;
});
Insteadofiteratingopacityvalues,youcouldalsoiterateRGBvaluestocreatecolor-basedgradients.Forexample,ifyouincreasedthebluecomponentoftextwhosecolorinitiallystartsasgray,you’dproduceelementsthatareincreasinglyrichinblueasyougofromfirsttolast:Clickheretoviewcodeimage
//Blastthedivtheniteratethroughthegeneratedtextelements
$(“div”).blast({delimiter:“character”}).each(function(i,element){
//Successivelyincreasethebluecolorcomponentofeachelementwithan
arbitraryformula
varadjustedBlue=i*20;
element.style.opacity=“rgb(0,0,”+adjustedBlue+“)”;
});
WrappingupThisisjustthebeginningofthepossibilitiescreatedbygranulartextcontrol.Othertechniquesincludefine-tuningthecoordinatesofeveryletterinawordtoproduceacollageeffect,orplacingwordsaroundthecircumferenceofacircletomimicthetypographicdesignyoumightfindonadrinkcoaster.
Whilethesetechniquesmaybewell-suitedforboldhomepagecenterpieces,theymaynotbeappropriateforcriticalpartsofyourUIthataresubjecttorepeateduserinteraction.
Why?Becausestylizedtextishardertoreadataglancethanunstylizedtext.Butifyouconsiderthebalancebetweenformandfunction,you’llbefine.
Chapter6.ScalableVectorGraphicsPrimer
Sinceanin-depthtutorialonScalableVectorGraphics(SVG)couldeasilycompriseabookofitsown,thischaptersimplyservesasanintroductiontothetopic.ThegoalistoequipyouwithenoughknowledgetobecomfortableanimatingSVGelementsandtoknowwheretogonexttocontinueyourlearning.
CreatingimagesthroughcodeAnSVGelementisatypeofDOMelementthatborrowsthesyntaxoftheHTMLelementsyou’realreadyfamiliarwithtodefinearbitraryshapes.SVGelementsdifferfromHTMLelementsinthattheyhaveuniquetags,attributes,andbehaviorsthatallowthemtodefinegraphicshapes.Putanotherway,SVGsletyoutocreateimagesthroughcode.ThisisatremendouslypowerfulconceptbecauseitmeansyoucanprogrammaticallystyleandanimatetheseshapesusingJavaScriptandCSS.InadditionSVGoffersmanyotherbenefits:
SVGcompressesincrediblywell.GraphicsdefinedinSVGhavesmallerfilesizesthantheirPNG/JPEGequivalents,whichcangreatlyimprovesiteloadtimes.
SVGgraphicsscaletoanyresolutionwithoutalossofclarity.Unlikestandardimageformats,theylookrazorsharpacrossalldevices—saygood-byetoblurryimagesonmobilescreens.
LikeHTMLelements,SVGelementscanbeassignedeventhandlersthatrespondtoauser’sinput,whichmeansthatthegraphicsonyourpagecanbemadeinteractive.Ifyousodesired,allthebuttonsonyoursitecouldbeturnedintoanimatedgraphics.
Manyphoto-editingapps(includingAdobePhotoshop,Sketch,andInkscape)letyouexportyourdesignworkintoSVGformatforquickcopyingandpastingintoHTML.So,evenifyoudon’tconsideryourselfanartist,youcanleveragethird-partyapplicationstodothedesigningforyou.
Inshort,SVGsareanamazinggraphicssolution.Let’sdivein!
SVGmarkupSVGelementsaredefinedwithinaparent<svg>container.SpecifyingthewidthandheightdimensionsofcontainerelementdefinesthecanvasthatyourSVGgraphicsrenderupon:Clickheretoviewcodeimage
<svgversion=“1.1”width=“500”height=“500”
xmlns=“http://www.w3.org/2000/svg”>
<circlecx=“100”cy=“100”r=“30”/>
<rectid=“rect”x=“100”y=“100”width=“200”height=“200”/>
</svg>
Within<svg>,youcaninsertSVGshapeelementsofvaryingsorts.Theaboveexamplehasacircleelementfollowedbyarect(rectangle)element.AswithnormalHTMLelements,SVGelementsacceptheightandwidthattributes,whichareused
herefordemonstrationpurposes,but(aswithHTML)it’sconsideredbestpracticetospecifySVGstylingpropertieswithinaCSSstylesheet.AlsoaswithHTML,stylesheetclassestargetSVGelementsviatheirid,class,ortagtypes.
WheretheSVGandHTMLspecificationsfundamentallydifferisintheirrangeofacceptedHTMLattributesandCSSproperties.SVGelementsacceptonlyafewofthestandardCSSproperties.Further,SVGsacceptaspecialsetofattributes,calledpresentationalattributes,whichincludefill,x,andy.(fillspecifieswhichcolortofillashapewith,whereasxandydefinethepositionoftheelement’stop-leftcorner.)Theseattributesdefinehowanelementisvisuallyrenderedonitscanvas.Let’srunthroughafewofthem,usingrectasasampleSVGelement:Clickheretoviewcodeimage
<rectid=“rect”x=“100”y=“100”width=“200”height=“200”/>
Here,thewidthandheightattributesworkasyou’dexpect.Theuniquexandyattributesdefinetherectangle’scoordinateswithinthecanvas.Thesevaluessimplypositiontherectanglerelativetoanx=0,y=0originpoint.UnlikeHTML,SVGpositioningisnotdefinedwithtop,right,bottom,left,float,ormarginCSSproperties;SVGpositioninglogicisfullydictatedbyexplicitlydefinedcoordinates.Inotherwords,anSVGelement’spositioningdoesn’taffectthepositionofitssiblingelements;insteadofpushingeachotheraroundthepage,SVGsiblingssimplyoverlaponeanother.
Nowlet’stakealookatthecircleelement.Itsrenderingisspecifiedviacoordinatesthatdesignateitscenterpoint(cxandcy)alongwitharadiusvalue(r)thatdesignatesitslength:Clickheretoviewcodeimage
<circlecx=“100”cy=“100”r=“30”/>
Prettysimple,right?SVGelementsusethesamemarkupstructureasHTMLelements,soallthecodesamplesinthischaptershouldfeelfamiliar.
NotethattherearemanyothertypesofSVGelements,includingellipse,line,andtext.Seetheendofthischapterforfurtherdetails.
SVGstylingSVGelementsacceptavarietyofspecialstylingpropertiesthatarenotavailabletoHTMLelements.SVG’sfillproperty,forexample,issimilartobackground-colorinCSS,strokeissimilartoborder-color,andstroke-widthissimilartoborder-width.Takealookatthisexample:Clickheretoviewcodeimage
<svgversion=“1.1”width=“500”height=“500”
xmlns=“http://www.w3.org/2000/svg”>
<circlecx=“100”cy=“100”r=“30”style=“fill:blue”/>
<rectid=“rect”x=“100”y=“100”width=“200”height=“200”style=“fill:
green;stroke:red;stroke-width:5px”/>
</svg>
Above,thecircleelementisfilledwithsolidblue,andtherectelementisfilled
withsolidgreen.Additionally,therectanglehasaredborderwithathicknessof5px.
TherearemanyotherSVG-specificstylingproperties.Fornow,it’ssimplyimportantforyoutoknowthattheyexistsoyou’llpayextraattentionwhentryingtoanimateCSSpropertiesonSVGelements.
Note
Refertothe“Wrappingup”sectionofthischapterforinformationonwheretofindafulllistingofSVGstylingproperties.
SupportforSVGOut-of-the-boxsupportforSVGelementanimationisn’tgreat:neitherjQuerynorCSSofferscompletesupportforanimatingSVG-specificstylingpropertiesandpresentationalattributes.Further,CSStransitionscan’tanimateSVGelementsatallonInternetExplorer9,andCSScan’tbeusedtoapplytransformanimationstoSVGelementsonanyversionofInternetExplorer.
TogaincomprehensiveSVGanimationsupport,useeitheradedicatedSVGlibraryorananimationlibrarythathasbuilt-insupportforSVGelements.OnenoteworthydedicatedSVGlibraryisSnap.svg.Itprobablywon’tsurpriseyoutolearnthatVelocity.js,theJavaScriptanimationlibraryyou’vebeenusingthroughoutthisbook,providesfullsupportforSVGelementanimation.
Note
GotoSnapSVG.iotodownloadtheSnap.svglibrary.
SVGanimationSVGelementsmightneverbethebackboneofyourUI,butthey’recertainlyappropriateforspicingupthepartsofyourpagethatyou’dnormallyfillwithstaticimages.UsesforSVGsinclude:
Buttonswithintricateanimationsequencesthataretriggeredwhenusershoverandclick.
Uniqueloadingstatusgraphicsthatreplacetheall-too-commonrotatingindicatorGIF.
Companylogoswhoseindividualpartsanimatetogetheruponpageload.
Thislastusecaseisexploredinmoredetaillaterinthischapter.
PassinginpropertiesWithVelocity,SVGpropertiesareanimatedinthesamewaythatstandardCSSpropertiesare.PasstheappropriatepropertiesandtheirdesiredendvaluesintoVelocity’spropertiesobject:
Clickheretoviewcodeimage
//AnimateanSVGelementtoaredfillandablackstroke
$svgElement.velocity({fill:“#ff0000”,stroke:“#000000”});
Incontrast,notethatthecodebelowwouldnotworksincethefollowingCSSpropertiesarenotsupportedbySVGelements:Clickheretoviewcodeimage
//Incorrect:Thesepropertiesdon’tapplytoSVGelements
$svgElement.velocity({borderSize:“5px”,borderColor:“#000000”});
PresentationalattributesThepresentationalattributesexploredearlierinthischapterarealsoanimatedasexpected:Clickheretoviewcodeimage
//Animatethexandycoordinatesofarectangle
$(“rect”).velocity({x:100,y:100});
//Animatethecxandcycoordinatesofacircle
$(“circle”).velocity({cx:100,cy:100});
//Animatethedimensionsofarectangle
$(“rect”).velocity({width:200,height:200});
//Animatetheradiusofacircle
$(“circ”).velocity({r:100});
AlltheVelocityfeaturesthatyou’recurrentlyusing—animationreversal,UIpackeffects,sequencetriggering,andsoon—alsoworkasexpectedwithSVGelements.
Positionalattributesvs.transformsYoumightbewonderingwhatthedifferenceisbetweenusingthex,cx,y,andcypositionalattributesinsteadofCSStransforms(e.g.translateX,translateY)whenspecifyingthepositionsofSVGelements.Theanswerisbrowsersupport.InternetExplorer(uptoandincludingInternetExplorer11)doesnotsupportCSStransformsonSVGelements.Considerthefollowing:Clickheretoviewcodeimage
//ThexandyattributesworkeverywherethatSVGelementsdo(IE8+,Android
3+)
$(“rect”).velocity({x:100,y:100});
//Alternatively,positionaltransforms(suchastranslateXandtranslateY)
workeverywhere*except*InternetExplorer
$(“rect”).velocity({translateX:100,translateY:100});
Note
Althoughtransformsareknowntobeparticularlyperformantduetohardwareacceleration(readmoreonthisinChapter7,“AnimationPerformance”),bothapproachestoSVGanimationareequallyfastsinceSVGgraphicsarehardware-acceleratedbydefault.
Implementationexample:AnimatedlogosHigh-resolutionsitelogosthatanimateintoplaceuponpageloadareidealtargetsforSVGimplementation.SupposeyouwanttocrudelyreplicatetheMasterCardlogo,whichconsistsoftwooverlappingcirclesofdifferentcolors.IfyouweretoanimatethislogointoplaceusingVelocity,you’dstartwithanSVGcanvasdefinedasfollows:Clickheretoviewcodeimage
<svgversion=“1.1”width=“500”height=“500”
xmlns=“http://www.w3.org/2000/svg”>
<circleid=“circleLeft”cx=“100”cy=“100”r=“30”style=“fill:red”/>
<circleid=“circleRight”cx=“100”cy=“100”r=“30”style=“fill:orange”/>
</svg>
Thiscreatestwooverlappingcircleswithidenticalradii.Next,you’danimatethecirclesoutwardfromtheiroriginssothattheyoverlaponlyslightlywhenthey’redoneanimating:Clickheretoviewcodeimage
//Moveonecircletowardtheleft
$(“#circleLeft”).velocity({cx:“-=15px”},{easing:“spring”});
//Moveonecircletowardtheright
$(“#circleRight”).velocity({cx:“+=15px”},{easing:“spring”});
Here,theleftcircleisanimated15pixelsleftward(usingthe"-="operatortoinstructVelocitytodecrementthecircle’scurrentvalue)andtherightcircleisanimated15pixelsrightward.Thespringeasingprovidesaddedflairbymakingthecirclesbounceawayfromoneanotherwithpropulsiveforce.
SinceSVGelementscanlistenformouse-basedevents(clicks,hovers,andsoon),youcouldimproveuponthisdemobyturningitintoanexampleofSVGelementinteraction.WiththeaidofjQueryandVelocity,onesuchimplementationcouldlooklikethis:Clickheretoviewcodeimage
$(“svg”).on(“mouseovermouseout”,function(){
$(“#circleLeft,#circleRight”).velocity(“reverse”);
});
Thistriggersareversalofthecircles’page-loadanimationwhentheuserhoversonorofftheSVGelement.ThesinglelineofcodeaccomplishesthisbyleveragingVelocity’sreverseanimationcommand.Formoreonworkingwithreverse,refertoChapter2,“AnimatingwithVelocity.js.”Ineffect,whentheuserfirsthovers,thepage-loadanimationisreversed.Whentheuserthenhoversoff,thereversalisitselfreversed,bringingthelogobacktoitsoriginalform.
Whilethiscodeexampleisundoubtedlyanticlimactic,thisisonceagainagoodthingbecauseitreflectsthesimilaritiesbetweenanimatingSVGandHTMLelements.WhereSVGsdostarttobecomeuniquelycomplexiswhenyoudefinearbitraryshapesthatgobeyondthebasicsofsquares,rectangles,circles,andsoon.Afterall,SVGelementscandefineanyshapeyoucandreamupinaphotoeditor,sotheyhavetobetremendouslyexpressive.Andtheyare.ButmasteringSVGdesignisbeyondthescopeofthisbook.Seethe“Wrappingup”sectionofthischaptertolearnwheretogonexttocontinuelearning.
WrappingupIfyou’reintriguedbywhatyou’vereadsofarandwanttolearnmoreaboutworkingwithSVGs,checkoutthesegreatresources:
ForafulloverviewofworkingwithSVGelements,refertoJoniTrythall’sfantasticandfreeSVGPocketGuide(https://github.com/jonitrythall/svgpocketguide).
ForadirectoryofSVGelementtypesandtheirproperties,consultMozillaDeveloperNetwork(https://developer.mozilla.org/en-US/docs/Web/SVG).
ForalistingofalltheSVGattributesandstylingpropertiesthatVelocitycananimate,refertoVelocityJS.org/#svg.
Chapter7.AnimationPerformance
Performanceaffectseverything.Increasedperformance—apparentorreal—drasticallyimprovesUX,whichinturnboostsyourcompany’sbottomline.Severalmajorstudieshavedemonstratedthatlatencyincreasesonsearchenginesresultinsignificantdecreasesinrevenueperuser.Toputitbluntly,peoplehatewaiting.
AsexplainedinChapter1,JavaScriptanimationperformanceiscomparabletothatofCSSanimation.So,ifyou’reusingamodernanimationlibrarysuchasVelocity.js,theperformanceofyouranimationengineisnotyourapp’sbottleneck—it’syourowncode.That’swhatthischapterexplores:techniquesforcodinghigh-performanceanimationsacrossallbrowsersanddevices.
TherealityofwebperformanceIfyou’veeverwonderedwhyrunningconcurrentanimationsslowsdownyourUI,orwhyyoursiteperformsslowlyonmobiledevices,thischapterisforyou.
Animationsareaveryresource-intensiveprocessforbrowserstoperform,buttherearemanytechniquesthatcanhelpthebrowserworkasefficientlyaspossible.We’reabouttolearnthem.
FromtheperspectiveofUIdesign,there’snoshortageofarticlesextollingthevirtuesofbuildingmobile-first,responsivewebsites.Conversely,fromtheperspectiveofUIperformance,mostofus,asdevelopers,areunawareofwhatbestpracticesareorhowtofollowthem.Stayingabreastofthewebperformancelandscapeisoverwhelmingandoftentimesfutile;we’reheldcaptivebybrowseranddevicequirks,byproductsofthevolumeofdevices(desktops,smartphones,andtablets)andbrowsers(Chrome,Android,Firefox,Safari,InternetExplorer)thatcrowdtheecosystem.Consideringthattheseplatformsarecontinuouslyupdated,it’snosurprisethatweoftenthrowinthetowelandsidelineperformanceconcernsasmuchaswecan.Sometimeswemayevenbetemptedtodoawaywithanimationsaltogetherifwe’reunsurehowtoimplementthemwithoutsacrificingperformance.
Wetellourselves:
Sincedevicesaregettingfaster,asuserscontinueupgradingtheirhardware,mysitewillbecomeprogressivelymoreperformant.
Unfortunately,theglobalrealityistheexactopposite:thesmartphonesthatthedevelopingworldisadoptingfallshortoftheperformanceofthelatestiPhonesinourpockets.Doyoureallywanttoforsakebuildingproductsforthenextfewbillionpeoplecomingonline?TheupcomingFirefoxOSinitiativeispoisedtobringcapablesmartphonestohundredsofmillionsofpeople,sowe’renotsimplywaxingpoeticabouthypotheticals.Themobilerevolutionisherenow.
Note
Ericssonhasreportedthattheglobalsmartphonesubscribercountwillrisefrom1.9billionto5.9billioninthenextfiveyears—fueledalmostexclusivelybythedevelopingworld.
Ifyourgutreactionis,“It’snotmyproblem—myappisjustforthetech-savvymiddle-classinthedevelopedworld,”restassuredthatyourevilwebdevelopertwinissittingtwothousandmilesawaycacklingatthethoughtofgettingtoanascentmarketbeforeyoudobyactuallyputtingintheeffortnecessarytodelivergreatexperiencesonlow-powereddevices.(There’sactuallyanenormousconglomeratededicatedtothis—searchGooglefor“RocketInternet.”)
There’sanothernastyrealitytosideliningperformanceconcerns:wesystematicallymakethemistakeoftestingoursitesondevicesoperatingunderidealloads.Inreality,ofcourse,usershavemultipleappsandbrowsertabsrunningconcurrently.Theirdevicesareworkingovertimetoprocessadozentasksatanygiventime.Accordingly,theperformancebaselineestablishedforyourappprobablydoesn’treflectitsperformanceintherealworld.Yikes!
But,fearnot,keendeveloper.It’stimetoexploretheperformancetechniquesatyourdisposalandlevelupyouranimationgame.
Technique:RemovelayoutthrashingLayoutthrashing—thelackofsynchronizationinDOMmanipulation—isthe800-poundgorillainanimationperformance.There’snopainlesssolution,buttherearebestpractices.Let’sexplore.
ProblemConsiderhowwebpagemanipulationconsistsofsettingandgetting:youcanset(update)orget(query)anelement’sCSSproperties.Likewise,youcaninsertnewelementsontoapage(aset)oryoucanqueryforasetofexistingelements(aget).Getsandsetsarethecorebrowserprocessesthatincurperformanceoverhead(anotherisgraphicalrendering).Thinkofitthisway:aftersettingnewpropertiesonanelement,thebrowserhastocalculatetheresultingimpactsofyourchanges.Forexample,changingthewidthofoneelementcantriggerachainreactioninwhichthewidthoftheelement’sparent,siblings,andchildrenelementsmustalsochangedependingontheirrespectiveCSSproperties.
TheUIperformancereductionthatoccursfromalternatingsetswithgetsiscalledlayoutthrashing.Whilebrowsersarehighlyoptimizedforpage-layoutrecalculations,theextentoftheiroptimizationsisgreatlydiminishedbylayoutthrashing.Performingaseriesofgetsatonce,forexample,caneasilybeoptimizedbythebrowserintoasingle,streamlinedoperationbecausethebrowsercancachethepage’sstateafterthefirstget,thenreferencethatstateforeachsubsequentget.However,repeatedlyperformingonegetfollowedbyonesetforcesthebrowsertodoalotofheavyliftingsinceitscacheiscontinuouslyinvalidatedbythechangesmadebyset.
Thisperformanceimpactisexacerbatedwhenlayoutthrashingoccurswithinananimationloop.Considerhowananimationloopaimstoachieve60framespersecond,thethresholdatwhichthehumaneyeperceivesbuttery-smoothmotion.Whatthismeansisthateverytickinananimationloopmustcompletewithin16.7ms(1second/60ticks~=16.67ms).Layoutthrashingisaveryeasywaytocauseeachticktoexceedthislimit.Theendresult,ofcourse,isthatyouranimationwillstutter(orjank,inwebanimationparlance).
Whilesomeanimationengines,suchasVelocity.js,containoptimizationstoreducetheoccurrenceoflayoutthrashinginsidetheirownanimationloops,becarefultoavoidlayoutthrashinginyourownloops,suchasthecodeinsideasetInterval()oraself-invokingsetTimeout().
SolutionAvoidinglayoutthrashingconsistsofsimplybatchingtogetherDOMsetsandDOMgets.Thefollowingcodecauseslayoutthrashing:Clickheretoviewcodeimage
//Badpractice
varcurrentTop=$(“element”).css(“top”);//Get
$(“element”).style.top=currentTop+1;//Set
varcurrentLeft=$(“element”).css(“left”);//Get
$(“element”)..style.left=currentLeft+1;//Set
Ifyourewritethecodesothatallqueriesandupdatesarealigned,thebrowsercanbatchtherespectiveactionsandreducetheextenttowhichthiscodecauseslayouttrashing:Clickheretoviewcodeimage
varcurrentTop=$(“element”).css(“top”);//Get
varcurrentLeft=$(“element”).css(“left”);//Get
$(“element”).css(“top”,currentTop+1);//Set
$(“element”).css(“left”,currentLeft+1);//Set
Theillustratedproblemiscommonlyfoundinproductioncode,particularlyinsituationswhereUIoperationsareperformeddependingonthecurrentvalueofanelement’sCSSproperty.
Sayyourgoalistotogglethevisibilityofasidemenuwhenabuttonisclicked.Toaccomplishthis,youmightfirstchecktoseeifthesidemenuhasitsdisplaypropertysettoeither"none"or"block",thenyou’dproceedtoalternatethevalueasappropriate.Theprocessofcheckingforthedisplaypropertyconstitutesaget,andwhicheveractionissubsequentlytakentoshoworhidethesidemenuwillconstituteaset.
Theoptimizedimplementationofthiscodewouldentailmaintainingavariableinmemorythat’supdatedwheneverthebuttonisclicked,andcheckingthatvariableforthesidemenu’scurrentstatusbeforetogglingitsvisibility.Inthisway,thegetcanbeskippedaltogether,whichhelpsreducethelikelihoodofthecodeproducingasetalternatedwithaget.Further,beyondreducingthelikelihoodoflayoutthrashing,theUInowalsobenefitsfromhavingonelesspagequery.Keepinmindthateachsetandgetisarelativelyexpensivebrowseroperation;thefewerthereare,thefasteryourUIwillperform.
Manytinyimprovementsultimatelyadduptoasubstantialbenefit,whichistheunderlyingthemeofthischapter:Followasmanyperformancebestpracticesasyoucan,andyou’llwindupwithaUIthatrarelysacrificesyourdesiredmotiondesigngoalsforthesakeofperformance.
jQueryElementObjectsInstantiatingjQueryelementobjects(JEO)isthemostcommonculpritofDOMgets.YoumaybewonderingwhataJEOis,butyou’vecertainlyseenthiscodesnippetbefore:Clickheretoviewcodeimage
$(“#element”).css(“opacity”,1);
…oritsrawJavaScriptequivalent:
document.getElementById(“element”).style.opacity=1;
InthecaseofthejQueryimplementation,thevaluereturnedby$("#element")isaJEO,whichisanobjectthatwrapstherawDOMelementthatwasqueried.JEO’sprovideyouwithaccesstoallofyourbelovedjQueryfunctions,including.css(),.animate(),andsoon.
InthecaseoftherawJavaScriptimplementation,thevaluereturnedbygetElementByid("element")istheraw(unwrapped)DOMelement.Inboth
implementations,thebrowserisinstructedtosearchthroughtheDOMtreetofindthedesiredelement.Thisisanoperationthat,whenrepeatedinbulk,impactspageperformance.
Thisperformanceconcernisexacerbatedwhenuncachedelementsareusedincodesnippetsthatarerepeated,suchasthecodecontainedbyaloop.Considerthefollowingexample:Clickheretoviewcodeimage
$elements.each(function(i,element){
$(“body”).append(element);
});
Youcanseehow$("body")isaJEOinstantiationthat’srepeatedforeveryiterationofthe$.each()loop:Inadditiontoappendingtheloop’scurrentelementtotheDOM(whichhasitsownperformanceimplications),you’renowalsorepeatedlyforcingaDOMquery.Seeminglyharmlessone-lineoperationsliketheseaddupveryquickly.
Thesolutionhereistocachetheresults—or,savethereturnedJEO’sintovariables—toavoidarepeatedDOMoperationeverytimeyouwanttocallajQueryfunctiononanelement.Hence,thecodegoesfromlookinglikethis:Clickheretoviewcodeimage
//Badpractice:Wehaven’tcachedourJEO
$(“#element”).css(“opacity”,1);
//…someintermediarycode…
//WeinstantiatetheJEOagain
$(“#element”).css(“opacity”,0);
tolookinglikethisafterit’sproperlyoptimized:Clickheretoviewcodeimage
//CachethejQueryelementobject,prefixingthevariablewith$toindicate
aJEO
var$element=$(“#element”);
$element.css(“opacity”,1);
//…someintermediarycode…
//Were-usethecachedJEOandavoidaDOMquery
$element.css(“opacity”,0);
Nowyoucanreuse$elementthroughoutyourcodewithouteverincurringarepeatedDOMlookuponitsbehalf.
Force-feedingTraditionally,animationenginesquerytheDOMatthestartofananimationtodeterminetheinitialvalueofeachCSSpropertybeinganimated.Velocityoffersaworkaroundtothispage-queryingeventthroughafeaturecalledforce-feeding.It’sanalternativetechniqueforavoidinglayoutthrashing.Withforce-feeding,youexplicitlydefineyouranimations’startvaluessothattheseupfrontgetsareeliminated.
Force-fedstartvaluesarepassedinastheseconditeminanarraythattakestheplaceofaproperty’svalueinananimationpropertiesmap.Thefirstiteminthearrayisthestandardendvaluethatyou’reanimatingtoward.
Considerthefollowingtwoanimationexamples,bothofwhicharetriggereduponpageload:Clickheretoviewcodeimage
//AnimatetranslateXto500pxfromastartvalueof0
$element.velocity({translateX:[500,0]});
//Animateopacityto0fromastartvalueof1
$element.velocity({opacity:[0,1]);
Inthefirstexample,you’repassingtranslateXaforce-fedstartvalueof0sinceyouknowthattheelementhasyettobetranslated(sincethepagehasjustloaded).You’reforce-feedinginwhatyouknow(orwant)theoriginalpropertyvaluetobe.Further,inthesecondexample,theelement’scurrentopacityis1becausethat’sthedefaultvalueforopacityandyouhaven’tyetmodifiedtheelementinanyway.Inshort,withforce-feeding,youcanreducethebrowser’sworkloadinsituationswhereyouhaveanunderstandingofhowelementsarealreadystyled.
Note
Force-feedanimationpropertiesonlywhenthey’refirstusedinananimationchain,notwhentheyoccursubsequentlyinthechain,sinceVelocityalreadydoesinternalcachingthere:
Clickheretoviewcodeimage$element
//Optionallyforcefeedhere
.velocity({translateX:[500,0]})
//Donotforcefeedhere;500isinternallycached
.velocity({translateX:1000});
Force-feedingisaninvaluablefeatureforhigh-stresssituationssuchasanimatingalargenumberofelementsatonceonadesktopbrowserorwhendealingwithlow-poweredmobiledevicesforwhicheverypageinteractionincursanoticeabledelay.
However,formostreal-worldUIanimationsituations,force-feedingisanunnecessaryoptimizationthatmakesyourcodelessmaintainableduetohavingtoupdatetheforce-fedstartvalueswheneveryouchangetheelements’valueswithinCSSstylesheets.
Note
RefertoChapter8,“AnimationDemo,”towalkthroughanapplicationofforce-feeding.
Technique:BatchDOMadditionsLikereducinglayoutthrashing,batchingDOMadditionsisanotherperformancetechniquetohelpavoidunoptimizedinteractionwiththebrowser.
ProblemYou’renotdonewithgetsandsetsjustyet!AcommonpagesetistheinsertionofnewDOMelementsatrun-time.Whiletherearemanyusesforaddingnewelementstoapage,perhapsthemostpopularisinfinitescrolling,whichconsistsofelementscontinuouslyanimatingintoviewatthebottomofapagewhiletheuserscrollsdownward.
Asyoulearnedintheprevioussection,browsershavetocomputethecompositionofallaffectedelementswheneveranewelementisadded.Thisisarelativelyslowprocess.Hence,whenDOMinsertionisperformedmanytimespersecond,thepageishitwithasignificantperformanceimpact.Fortunately,whenprocessingmultipleelements,browserscanoptimizepagesetperformanceifallelementsareinsertedatthesametime.Unfortunately,weasdevelopersoftenunintentionallyforgothisoptimizationbyseparatingourDOMinsertions.ConsiderthefollowingexampleofunoptimizedDOMinsertioncode:Clickheretoviewcodeimage
//Badpractice
var$body=$(“body”);
var$newElements=[“<div>Div1</div>”,“<div>Div2</div>”,“<div>Div
3</div>”];
$newElements.each(function(i,element){
$(element).appendTo($body);
//Otherarbitrarycode
});
ThisiteratesthroughasetofelementstringsthatareinstantiatedintojQueryelementobjects(withoutaperformancedrawbacksinceyou’renotqueryingtheDOMforeachJEO).EachelementistheninsertedintothepageusingjQuery’sappendTo().
Here’stheproblem:evenifadditionalcodeexistsaftertheappendTo()statement,thebrowserwon’tcompresstheseDOMsetsintoasingleinsertionoperationbecauseitcan’tbecertainthatasynchronouscodeoperatingoutsidetheloopwon’taltertheDOM’sstatebetweeninsertions.Forexample,imagineifyouqueriedtheDOMtofindouthowmanyelementsexistonthepageaftereachinsertion:Clickheretoviewcodeimage
//Badpractice
$newElements.each(function(i,element){
$(element).appendTo($body);
//Outputhowmanychildrenthebodyelementhas
console.log($body.children().size());
});
Thebrowsercouldn’tpossiblyoptimizetheDOMinsertionsintoasingleoperationbecausethecodeexplicitlyasksthebrowsertotellustheaccuratenumberofelementsthatexistbeforethenextloopbegins.Forthebrowsertoreturnthecorrectcounteachtime,itcan’thavebatchedallinsertionsupfront.
Inconclusion,whenyouperformDOMelementinsertioninsidealoop,eachinsertionhappensindependentlyofanyothers,resultinginanotableperformancesacrifice.
SolutionInsteadofindividuallyinsertingnewelementsintotheDOM,constructthefullDOMelementsetinmemory,theninsertitviaasinglecalltoappendTo().Theoptimizedversionofthecodeshowninthesectionabovenowlookslikethis:Clickheretoviewcodeimage
//Optimized
var$body=$(“body”);
var$newElements=[“<div>Div1</div>”,“<div>Div2</div>”,“<div>Div
3</div>”];
varhtml=””;
$newElements.each(function(i,element){
html+=element;
});
$(html).appendTo($body);
ThisconcatenatesthestringrepresentationofeachHTMLelementontoamasterstringthatisthenturnedintoaJEOandappendedintotheDOMinasingleshot.Inthisway,thebrowserisgivenexplicitinstructiontoinserteverythingatonce,anditoptimizesforperformanceaccordingly.
Simple,right?Asyou’llseeintheremainderofthischapter,performancebestpracticesareusuallyaseasyasthis.Yousimplyhavetotrainyoureyetoknowwhentousethem.
Technique:AvoidaffectingneighboringelementsIt’simportanttoconsidertheimpactofanelement’sanimationonneighboringelements.
ProblemWhenanelement’sdimensionsareanimated,thechangesoftenaffectthepositioningofnearbyelements.Forexample,ifanelementbetweentwosiblingelementsshrinksinwidth,thesiblings’absolutepositionswilldynamicallychangesotheyremainnexttotheanimatingelement.Anotherexamplemightbeanimatingachildelementnestedinsideaparentelementthatdoesn’thaveexplicitlydefinedwidthandheightproperties.Accordingly,whenthechildisbeinganimated,theparentwillalsoresizeitselfsothatitcontinuestofullywrapitselfaroundthechild.Ineffect,thechildelementisnolongertheonlyelementbeinganimated—theparent’sdimensionsarealsobeinganimated,andthat’sevenmoreworkforthebrowsertoperformuponeachtickinananimationloop!
TherearemanyCSSpropertieswhosemodificationcanresultindimensionalandpositionaladjustmentstoneighboringelements,includingtop,right,bottom,andleft;allmarginandpaddingproperties;borderthickness;andthewidthandheightdimensions.
Asaperformance-mindeddeveloper,youneedtoappreciatetheimpactthatanimatingthesepropertiescanhaveonyourpage.Alwaysaskyourselfhoweachpropertyyou’reattemptingtoanimateaffectsnearbyelements.Ifthere’sawaytorewriteyourcodesuchthatyoucanisolateelements’changesfromoneanother,thenconsiderdoingso.Infact,thereisaneasywaytodojustthis—ontothesolution!
SolutionThesimplesolutiontoavoidaffectingneighboringelementsistoanimatetheCSStransformproperties(translateX,translateY,scaleX,scaleY,rotateZ,rotateX,androtateY)wheneverpossible.Thetransformpropertiesareuniqueinthattheyelevatetargetedelementstoisolatedlayersthatarerenderedseparatelyfromtherestofthepage(withaperformanceboostcourtesyofyourGPU),sothatneighboringelementsaren’taffected.Forexample,whenanimatinganelement’stranslateXtoavalueof“500px",theelementwillmove500pxrightwardwhilesuperimposingitselfontopofwhateverelementsexistalongitsanimationpath.Iftherearenoelementsalongitspath(thatis,iftherearenonearbyelementsforittoaffect),thenusingtranslateXwillhavethesameneteffectonthelookofyourpageasifyouhadanimatedusingthemuchslowerleftproperty.
Hence,wheneverpossible,ananimationthatoncelookedlikethis:Clickheretoviewcodeimage
//Movetheelement500pxfromtheleft
$element.velocity({left:“500px”});
shouldberefactoredintothis:Clickheretoviewcodeimage
//Faster:UsetranslateX
$element.velocity({translateX:“500px”});
Similarly,ifyoucansubstitutetranslateYfortop,doso:Clickheretoviewcodeimage
$element.velocity({top:“100px”});
//Faster:UsetranslateY
$element.velocity({translateY:“100px”});
Note
Sometimesyouactuallyintendtouseleftortopsothatneighboringelements’positionsarechanged.Inallothercases,getintothehabitofusingthetransformproperties.Theperformanceimpactissignificant.
ConsiderOpacityOverColor
opacityisanotherCSSpropertythatreceivesaGPUrenderingboostsinceitdoesn’taffectthepositioningofelements.So,ifthereareelementsonyourpageforwhichyou’recurrentlyanimating,say,colorwhentheuserhoversoverthem,consideranimatingopacityinstead.Iftheneteffectlooksalmostasgoodasthecoloranimation,thenconsiderstickingwithit—you’vejustboostedtheUI’sperformancewithoutcompromisingitslook.
Asaperformance-mindeddeveloper,you’renolongerallowedtoarbitrarilyselectanimationproperties.Youmustnowconsidertheimpactofeachofyourpropertychoices.
Note
RefertoCSSTriggers.comforabreakdownofhowCSSpropertiesaffectbrowserperformance.
Technique:ReduceconcurrentloadBrowsershavebottlenecks.Findoutwhattheyareandstaybelowthem.
ProblemWhenapagefirstloads,thebrowserprocessesHTML,CSS,JavaScript,andimagesasquicklyaspossible.Itshouldcomeasnosurprisethatanimationsoccurringduringthistimetendtobelaggy—they’refightingforthebrowser’slimitedresources.So,despitethefactthatapage’sloadingsequenceisoftenagreattimetoflauntallyourmotiondesignskills,it’sbesttorestrainyourselfifyouwanttoavoidgivingusersthefirstimpressionthatyoursiteislaggy.
Asimilarconcurrencybottleneckariseswhenmanyanimationsoccuratonceonapage—regardlessofwheretheytakeplaceinthepage’slifecycle.Inthesesituations,browserscanchokeunderthestressofprocessingmanystylingchangesatonce,andstutteringcanoccur.
Fortunately,therearesomeclevertechniquesforreducingconcurrentanimationload.
SolutionTherearetwoapproachesforaddressingtheconcurrencyissue:staggeringandbreakingupanimationsintosequences.
Stagger
OnewaytoreduceconcurrentanimationloadistomakeuseofVelocity’sUIpack’sstaggerfeature,whichdelaysthestarttimesofsuccessiveanimationsinasetofelementsbyaspecifiedduration.Forexample,toanimateeveryelementinasettowardanopacityvalueof1withsuccessive300msdelaysbetweenstarttimes,yourcodemightlooklikethis:Clickheretoviewcodeimage
$elements.velocity({opacity:1},{stagger:300});
Theelementsarenolongeranimatinginperfectsynchronization;instead,attheverystartoftheentireanimationsequence,onlythefirstelementisanimating.Later,attheveryendoftheentiresequence,onlythelastelementisanimating.You’reeffectivelyspreadingouttheanimationsequence’stotalworkloadsothatthebrowserisalwaysperforminglessworkatonetimethanitwouldhavehaditbeenanimatingeveryelementsimultaneously.What’smore,implementingstaggeringintoyourmotiondesignisoftenagoodaestheticchoice.(Chapter3,“MotionDesignTheory,”furtherexploresthemeritsofstaggering.)
Multi-animationsequences
There’sonemorecleverwaytoreduceconcurrentload:breakuppropertyanimationsintomulti-animationsequences.Take,forexample,thecaseofanimatinganelement’sopacityvalue.Thisistypicallyarelativelylow-stressoperation.But,ifyouweretosimultaneouslyanimatetheelement’swidthandbox-shadowproperties,you’dbegivingthebrowserappreciablymoreworktoperform:morepixelswillbeaffected,andmorecomputationwouldberequired.
Hence,ananimationthatlookslikethis:Clickheretoviewcodeimage
$images.velocity({opacity:1,boxShadowBlur:“50px”});
mightberefactoredintothis:Clickheretoviewcodeimage
$images
.velocity({opacity:1})
.velocity({boxShadowBlur:“50px”});
Thebrowserhaslessconcurrentworktodosincetheseindividualpropertyanimationsoccuroneafteranother.Notethatthecreativetradeoffbeingmadehereisthatwe’veoptedtoprolongthetotalanimationsequenceduration,whichmayormaynotbedesirableforyourparticularusecase.
Sinceanoptimizationsuchasthisentailschangingtheintentionofyourmotiondesign,thisisnotatechniquethatshouldalwaysbeemployed.Consideritalastresort.Ifyouneedtosqueezeadditionalperformanceoutoflow-powereddevices,thenthistechniquemaybesuitable.Otherwise,don’tpre-optimizethecodeonyoursiteusingtechniqueslikethis,oryou’llendupwithunnecessarilybloatedandinexpressivecode.
Technique:Don’tcontinuouslyreacttoscrollandresizeeventsBemindfulofhowoftenyourcodeisbeingrun.Afastsnippetofcodebeingrun1,000timespersecondmay—inaggregate—nolongerbeveryfast.
ProblemBrowsers’scrollandresizeeventsaretwoeventtypesthataretriggeredatveryhighrates:whenauserresizesorscrollsthebrowserwindow,thebrowserfiresthecallbackfunctionsassociatedwiththeseeventsmanytimespersecond.Hence,ifyou’veregisteredcallbacksthatinteractwiththeDOM—orworse,containlayoutthrashing—theycancausetremendouslyhighbrowserloadduringtimesofscrollingandresizing.Considerthefollowingcode:Clickheretoviewcodeimage
//Performanactionwhenthebrowserwindowisscrolled
$(window).scroll(function(){
//Anythinginhereisfiredmultipletimespersecondwhiletheuser
scrolls
});
//Performanactionwhenthebrowserwindowisresized
$(window).resize(function(){
//Anythinginhereisfiredmultipletimespersecondwhiletheuser
resizes
});
Recognizethatthefunctionsabovearen’tsimplycalledoncewhentheirrespectiveeventsstart;instead,theyarecalledthroughoutthedurationoftheuser’srespectiveinteractionwiththepage.
SolutionThesolutiontothisproblemistodebounceeventhandlers.Debouncingistheprocessofdefininganintervalduringwhichaneventhandlercallbackwillbecalledonlyonce.Forexample,sayyoudefinedadebounceintervalof250msandtheuserscrolledthepageforatotaldurationof1000ms.Thedebouncedeventhandlercodewouldaccordinglyfireonlyfourtimes(1000ms/250ms).
Thecodeforadebounceimplementationisbeyondthescopeofthisbook.Fortunately,manylibrariesexistexclusivelytosolvethisproblem.Visitdavidwalsh.name/javascript-debounce-functionforoneexample.Further,thetremendouslypopularUnderscore.js(UnderscoreJS.org),aJavaScriptlibraryakintojQuerythatprovideshelperfunctionsformakingcodingeasier,includesadebouncefunctionthatyoucaneasilyreuseacrossyoureventhandlers.
Note
Asofthisbook’swriting,thelatestversionofChromeautomaticallydebouncesscrollevents.
Technique:ReduceimagerenderingNotallelementsarerenderedequally.Browsershavetoworkovertimewhendisplayingcertainelements.Let’slookatwhichthoseare.
ProblemVideosandimagesaremultimediaelementtypesthatbrowsershavetoworkextrahardtorender.Whereasthedimensionalpropertiesofnon-multimediaHTMLelementscanbecomputedwithease,multimediaelementscontainthousandsofpixel-by-pixeldatapointsthatarecomputationallyexpensiveforbrowserstoresize,reposition,andrecomposite.AnimatingtheseelementswillalwaysbelesslessthanoptimalversusanimatingstandardHTMLelementssuchasdiv,p,andtable.
Further,giventhatscrollingapageisnearlyequivalenttoanimatingapage(thinkofscrollingasanimatingthepage’stopproperty),multimediaelementscanalsodrasticallyreducescrollingperformanceonCPU-constrainedmobiledevices.
SolutionUnfortunately,there’snowayto“refactor”multimediacontentintofasterelementtypes,otherthanturningsimple,shape-basedimagesintoSVGelementswhereverpossible.Accordingly,theonlyavailableperformanceoptimizationisreducingthetotalnumberofmultimediaelementsthataredisplayedonthepageatonceandanimatedatonce.Notethatthewordsatoncestressarealityofbrowserrendering:browsersonlyrenderwhat’svisible.Theportionsofyourpage(includingtheportionsthatcontainadditionalimages)thataren’tvisibledonotgetrendered,anddonotimposeadditionalstressonbrowserprocesses.
So,therearetwobestpracticestofollow.First,ifyou’reeveronthefenceaboutaddinganadditionalimagetoyourpage,opttonotincludeit.Thefewerimagestherearetorender,thebetterUIperformancewillbe.(Nottomentionthepositiveimpactfewerimageswillhaveonyourpage’snetworkloadtime.)
Second,ifyourUIisloadingmanyimagesintoviewatonce(say,eightormore,dependingonyourdevice’shardwarecapabilities),considernotanimatingtheimagesatall,andinsteadcrudelytogglingthevisibilityofeachimagefrominvisibletovisible.Tohelpcounteracthowinelegantthiscanlook,considerstaggeringvisibilitytogglingsothattheimagesloadintoviewoneafteranotherinsteadofsimultaneously.Thiswillhelpguidetheuser’seyeacrosstheloadingsequence,andwillgenerallydelivermorerefinedmotiondesign.
Note
RefertoChapter3,“MotionDesignTheory,”tolearnmoreaboutanimationdesignbestpractices.
SneakyimagesYou’renotdoneyet.There’smoretothissectionthanmeetstheeye,aswehaven’tfullyexploredthewaysinwhichimagescanmaterializeonapage.Theobviousculpritistheimgelement,buttherearetwootherwaysthatimagescansneakontoyourpages.
CSSgradients
Theseareactuallyatypeofimage.Insteadofbeingpre-producedbyaphotoeditor,theyareproducedatrun-timeaccordingtoCSSstylingdefinitions,forexample,usingalinear-gradient()asthebackground-imagevalueonanelement.Thesolutionhereistooptforsolid-colorbackgroundsinsteadofgradientswheneverpossible.Browserscaneasilyoptimizetherenderingofsolidchunksofcolor,but,aswithimages,theyhavetoworkovertimetorendergradients,whichdifferincolorfrompixeltopixel.
Shadowproperties
Theeviltwinsiblingsofgradientsarethebox-shadowandtext-shadowCSSproperties.Thesearerenderedsimilarlytogradients,butinsteadofstylizingbackground-color,theyeffectivelystylizeborder-color.What’sworse,theyhaveopacityfalloffsthatrequirebrowserstoperformextracompositingworkbecausethesemitransparentportionsofthegradientsmustberenderedagainsttheelementsunderneaththeanimatingelement.Thesolutionhereissimilartothepreviousone:ifyourUIlooksalmostasgoodwhenyouremovetheseCSSpropertiesfromyourstylesheet,patyourselfonthebackandneverlookback.Yourwebsite’sperformancewillthankyou.
Theserecommendationsaresimplythat:recommendations.Theyarenotperformancebestpracticessincetheysacrificeyourdesignintentionsforincreasedperformance.Consideredthemonlyaslastresortswhenyoursite’sperformanceispoorandyou’veexhaustedallotheroptions.
Technique:DegradeanimationsonolderbrowsersYoudon’thavetoneglectsupportingunderperformingbrowsersanddevices.Ifyouembraceaperformance-mindedworkflowfromdayone,youcansimplyprovidethemwithadegraded—butcompletelyfunctional—experience.
ProblemInternetExplorer8—aslow,outdatedbrowser—isdyinginpopularity.ButInternetExplorer9,itssuccessor,isstillwidelyusedoutsideoftheAmericas.Further,olderAndroidsmartphonesrunningAndroid2.3.xandbelow,whichareslowrelativetothelatest-generationAndroidandiOSdevices,alsoremaintremendouslypopular.Outofeverytenuserstoyoursite,expectuptothreeofthemtofallintooneofthesetwogroups(dependingonthetypeofusersyourappattracts).Accordingly,ifyoursiteisrichinanimationandotherUIinteractions,assumeitwillperformespeciallypoorlyforuptoathirdofyourusers.
SolutionTherearetwoapproachestoaddressingtheperformanceissueraisedbyweakerdevices:eitherbroadlyreducetheoccurrenceofanimationsacrossyourentiresite,orreducethemexclusivelyfortheweakerdevices.Theformerisaultimatelyaproductdecision,butthelatterisasimpletechnicaldecisionthatiseasilyimplementedifyou’reusingtheglobalanimationmultipliertechnique(orVelocity’sequivalentmockfeature)explainedintheChapter4,“AnimationWorkflow.”Theglobalmultipliertechniqueletsyoudynamicallyalterthetimingofanimationsacrossyourentiresitebysettingasinglevariable.Thetrickthen—wheneveraweakbrowserisdetected—istosetthemultiplierto0(orset$.Velocity.mocktotrue)sothatallofapage’sanimationscompletewithinasingleanimationtick(lessthan16ms):Clickheretoviewcodeimage
//Causeallanimationstocompleteimmediately
$.Velocity.mock=true;
TheresultofthistechniqueisthatweakerdevicesexperienceUIanimationsthatdegradesothatinstantstylechangesreplaceyouranimatedtransition.Thebenefitsaresignificant:yourUIwillperformnoticeablymoresmoothlywithoutresource-intensiveanimationsoccurringonyourpage.Whilethistechniqueisundoubtedlydestructive(itcompromisesyourmotiondesignintentions),animprovementinusabilityisalwaysworthareductioninelegance.Afterall,usersvisityourapptoaccomplishspecificgoals,nottoadmirehowcleveryourUIworkis.Neverletanimationsgetinthewayofuserintentions.
Ifyou’restillirkedbythenotionofstrippinganimationsfromyourUI,keepinmindthatusersonweakerdevicesareaccustomedtowebsitesbehavingslowlyforthem.So,ifyoursitebucksthetrendinaconstructiveway,they’llbeespeciallydelightedbyitandwillbemorelikelytocontinueusingit.
FindyourperformancethresholdearlyonContinuingfromtheprevioustechnique’stheme,it’sworthstressingthattheadviceinthischapterisespeciallyrelevantformobiledevices,manyofwhichareslowrelativetodesktopcomputers.Unfortunately,we,asdevelopers,oftenfailtoconsiderthisinourworkflows:weroutinelycreatewebsiteswithinthepristineoperatingenvironmentsofourhigh-enddesktops,whicharelikelyrunningthelatest-generationhardwareandsoftwareavailable.Thistypeofenvironmentisdivorcedfromthereal-worldenvironmentsofusers,whoareoftennotonlyusingoutdatedhardwareandsoftware,buttendtohavemanyappsandbrowsertabsrunningsimultaneously.Inotherwords,mostofusworkindevelopmentenvironmentsthatarenon-representationallyhigh-performance!Thesideeffectofthisoversightisthatyourappmayactuallybenoticeablylaggyforasignificantportionofyourusers.Bythetimeyouaskingwhatfrustratesthem,theymayhavealreadylostinterestinusingit.
Thecorrectapproachforaperformance-mindeddeveloperistodeterminetheperformancethresholdearlyoninthedevelopmentcycle.Whiledevelopingyourapp,checkitsperformancefrequentlyonreferencedevices,whichmightincludealast-generationmobiledeviceplusavirtualmachinerunningInternetExplorer9.Ifyousetaperformancegoalearlyonofbeingperformantonyourreferencedevices,thenyoucansleepsoundlyknowingthatallnewerdeviceswilldeliverevenbetterperformanceforyourusers.
Tip
Ifyou’reaMacuser,visitMicrosoft’sModern.iewebsiteforinformationonhowtorunfreevirtualcopiesofoldInternetExplorerversions.
Ifyoufindthatareferencedeviceistooweaktopowerthemotiondesignthatyouinsistyourapphas,followtheadvicefromtheprevioustechnique:gracefullydegradeanimationsonthatreferencedevice,andchooseafasterdeviceasyournew(non-degraded)reference.
Foreachtestingdevice,remembertoopenseveralappsandtabsatoncesoyousimulateusers’operatingenvironments.Nevertestinavacuuminwhichtheonlyapprunningisyourown.
Keepinmindthatremotebrowsertesting(throughservicessuchasBrowserStack.comandSauceLabs.com)isnotthesameaslivereferencedevicetesting.RemotetestingservicesareappropriatefortestingforbugsandUIresponsiveness—notforanimationperformance.Afterall,thetestdevicesrunninginthecloudaren’tusingrealhardware—they’reemulatedversionsofdevices.Consequently,theirperformanceistypicallydifferentthanthatoftheirreal-worldcounterparts.Further,thelagtimebetweenwhatoccursonthevirtualmachineandwhat’sdisplayedonyourbrowserwindowistoosignificanttogetameaningfulgaugeofUIanimationperformance.
Inshort,you’llneedtogooutandbuyrealdevicesforperformancetesting.Evenifyou’reacash-strappeddeveloper,don’tskimponthis.Thefewhundreddollarsyouspend
ontestdeviceswillbeoffsetbytheincreasedrecurringrevenueyou’llgeneratefromhappierusersengagingmorefrequentlywithyourbuttery-smoothapp.
Ifyouwindupwithahandfulofreferencedevices,alsoconsiderpurchasingDeviceLab,aversatilestandthatpropsupallofyourmobiledevicesonasinglesurfacesoyoucaneasilyeyeballthescreensduringtesting.Asabonus,thedeviceincludesaniftyappthatletsyoucontrolallthebrowsersacrossyourdevicesatoncesoyoudon’thavetomanuallyrefresheachbrowsertab.
Note
VisitVanamco.comtopurchaseanddownloadDeviceLab.
VisitEbaytoBuyOldDevicesforCheap
PurchasingthemostpopularAndroidandiOSdevicesfromeachoftheseproducts’majorreleasecycleswillgiveyouabroadcross-sectionofthehardwareandsoftwareenvironmentsthatyourusershave.Here’smyrecommendedsetup(asofearly2015):
iPhone4oriPad2runningiOS7
iPhone5s(ornewer)runningthelatestversionofiOS
MotorolaDroidXrunningAndroid2.3.x
SamsungGalaxySIIrunningAndroid4.1.x
SamsungGalaxyS5(ornewer)runningthelatestversionofAndroid
You’rewelcometosubstituteanyoftheAndroiddevicesfordevicesofsimilarperformance.What’simportanthereisthatyou’reusingonedevicefromeachmajorAndroidreleasecycle(2.3.x,4.1.x,andsoon)sothatyouhavearepresentativesampleofthewebbrowserperformancefromeachone.Refertohttp://developer.android.com/about/dashboardsforadistributionofthemostpopularAndroidversions.
WrappingupPerformanceaffectseverything.Fromhowmanydevicescanrunyourapp,tothequalityoftheuserexperience,totheperceptionofyourapp’stechnicalcompetency,performanceisamajortenetofprofessionalwebdesign.It’snota“nice-to-have,”it’safundamentalbuildingblock.Don’trelegateperformanceasasimpleoptimizationtobemadeinhindsight.
Chapter8.AnimationDemo
It’stimetogetyourhandsdirty!ThisfinalchapterwalksyouthroughafullanimationdemopoweredbyVelocity.Ingoingthroughthedemo’ssource,you’lllearnhowVelocity’scorefeaturescomplementoneanothertogreatlyimproveUIanimationworkflow.ThisdemowillalsointroduceyoutoadvancedtechniquesforworkingwithCSS’stransformproperties,whicharevitaltoweb-basedanimationtoday.
Inshort,you’regoingtoputtogethertheskillsyou’veaccumulatedthroughoutthisbooktomakesomethingreallydarncool.Yourgoalsincodingthedemoaretwofold:useterseandexpressiveanimationcode,andensuremaximumperformance.
BehaviorThedemoconsistsof250circlesfloatingin,out,andaroundthescreen.Periodically,you’llzoomin,thenbackouttothepositionwherethevirtualcamerastarted.Thefirstimagepresentedmomentarilyshowsazoomed-inview.
Note
Beforeyoucontinuereading,headonovertoVelocityJS.org/demo.book.htmltoseealivepreviewofthedemo.(Youcanright-clickanywhereonthepagethenchoose“ViewSource”toseethedemo’scode.)
Thecircleelementsaresimplynormaldivswithbox-shadowandborder-radiussetinCSS.There’snoWebGLorCanvasanimationgoingonhere—justpureHTMLelementmanipulation.(Giventhevolumeofelementsthatarebeinganimatedatonce,it’squiteimpressivethatthisdemoiscapableofrunningsosmoothlyintheDOM!)
Let’sbreakdowntheanimation:ItconsistsofdivelementstranslatingalongtheX,Y,andZaxes.TheZ-axisdictatesthedepthofeachelement’sanimation,whereasXandYprovidethegeneralflowing,2Dmovementseenacrossthescreen.Concurrenttotheelements’individualmovementsisalargerperspectiveshiftthatoccursontheelementcontainingallthesedivs.Thisperspectiveshiftoccursevery3seconds,anditcreatesaperiodiczoomingeffectthatmakestheviewerfeelasifhe’sbrieflytravelingthroughthecircles’3Dspace.
Thesecondgraphicdepictsthe3Dsceneinitszoomed-outview.Contrastthiswiththezoomed-inviewshowninthefirstimage.
HowtoDownloadtheCodeSample
Thecodebehindthisanimationdemoisavailablefordownloadfrompeachpit.com.Here’showtogetit:
1.Gotowww.peachpit.com/registerandcreateorlogintoyouraccount.
2.Enterthebook’sISBN(978-0-13-409670-4)andclickSubmit.
3.Your“MyRegisteredProducts”pageopens.Findthelistingforthisbook,andclick“AccessBonusContent.”
4.Thepagecontainingthedownloadlinkopens—clicktoaccesstheAnimationDemofileentitledWebAnimationJS_DemoCodeSample.zip
CodestructureLet’stakealookatthecodethatpowersthisdemo.Itisstructuredasfollows:
5.Animationsetup:Thespecificationofparametersusedforconstraininganimationmovement.
6.Circlecreation:Thegenerationofthedivelementstobeanimated.
7.Containeranimation:Thecoderesponsibleforanimatingthecircles’parentelement.
8.Circleanimation:Thecoderesponsibleforanimatingthecircleelementsthemselves.
Trytofamiliarizeyourselfwiththebroaderstrokesofthedemo’simplementationsoyoucankeepitsfullcontextinmindasyouexploreeachindividualcodeblockintheupcomingsections:Clickheretoviewcodeimage
/************************
Animationsetup
************************/
/*Randomlygenerateanintegerbetweentwonumbers.*/
functionr(min,max){
returnMath.floor(Math.random()*(max-min+1))+min;
}
/*Querythewindow’sdimensions.*/
varscreenWidth=window.screen.availWidth,
screenHeight=window.screen.availHeight;
/*Definethez-axisanimationrange.*/
vartranslateZMin=-725,
translateZMax=600;
/**********************
Circlecreation
**********************/
varcircleCount=250,
circlesHtml=””,
$circles=””;
for(vari=0;i<circleCount;i++){
circlesHtml+=“<divclass=‘circle’></div>”;
}
$circle=$(circlesHtml);
/******************************
Containeranimation
******************************/
$container
.css(“perspective-origin”,screenWidth/2+“px”+screenHeight/2+“px”)
.velocity(
{
perspective:[215,50],
opacity:[0.90,0.55]
},{
duration:800,
loop:1,
delay:3000
});
/***************************
Circleanimation
***************************/
$circles
.appendTo($container)
.velocity({
opacity:[
function(){returnMath.random()},
function(){returnMath.random()+0.1}
],
translateX:[
function(){return“+=”+r(-screenWidth/2.5,screenWidth/2.5)},
function(){returnr(0,screenWidth)}
],
translateY:[
function(){return“+=”+r(-screenHeight/2.75,screenHeight/2.75)
},
function(){returnr(0,screenHeight)}
],
translateZ:[
function(){return“+=”+r(translateZMin,translateZMax)},
function(){returnr(translateZMin,translateZMax)}
]
},{duration:6000})
.velocity(“reverse”,{easing:“easeOutQuad”})
.velocity({opacity:0},2000);
Codesection:AnimationsetupThissection’scodeiscopiedbelowforeasyreference:Clickheretoviewcodeimage
/************************
Animationsetup
************************/
/*Randomlygenerateanintegerbetweentwonumbers.*/
functionr(min,max){
returnMath.floor(Math.random()*(max-min+1))+min;
}
/*Querythewindow’sdimensions.*/
varscreenWidth=window.screen.availWidth,
screenHeight=window.screen.availHeight;
/*Definethez-axisanimationrange.*/
vartranslateZMin=-725,
translateZMax=600;
Thefirstsection,Animationsetup,beginsbydefiningafunctionr(abbreviatedfrom"random")thatletsyouartificiallyconstrainrandomlygeneratedintegervalues.Thisfunctiontakesminandmaxparameters,thenoutputsarandomnumberbetweenthemintomaxrange(usingsomebasicalgebra).You’llusethislaterwhenrandomizingtheanimatingelements’CSStransformvalueswithinrangesthatarepredefinedinthenexttwocodeblocks.
Thenextsectionqueriesthewindowobjecttoretrievethemonitor’sdimensions.Bylaterreferencingthesevalues,youcanensurethatthecirclesdon’tanimatetoofaroff-screen(andconsequentlyoutofview).
Animationsetupconcludesbydefiningtheminandmaxvaluesfortheelements’Z-axismovement.Thesevaluescontrolhowsmall(faraway)orlarge(nearby)youwantthecirclestoanimatefromtheirinitialsize.Specifically,itdictatesthatthecirclescangoasfaras725pixelsalongtheZ-axisawayfromthevirtualcamera(awayfromthescreen),andascloseas600pixelstowardthecamera.Inthiscase,there’snoconstraintofgoingoff-screen,butthecirclecouldbecometoodistanttoseeorsoclosethatittakesuptheentiremonitor.Basically,it’sacreativedecision.
Codesection:CirclecreationClickheretoviewcodeimage
/**********************
Circlecreation
**********************/
varcircleCount=250,
circlesHtml=””,
$circles=””;
for(vari=0;i<circleCount;i++){
circlesHtml+=“<divclass=‘circle’></div>”;
}
$circle=$(circlesHtml);
Thedemo’ssecondsection,Circlecreation,generatestheprimarydivelementstobeanimated.Here,itfirstdefinesthedesirednumberofcirclesascircleCount.Then,itdefinesacirclesHtmlstringtocontainthecircles’collatedHTML.
Next,ititeratesuptothecircleCountnumbertogeneratethecircles’HTML.NoticethatitusestheperformancebestpracticeofbatchingDOMadditions,asdetailedinChapter7,“AnimationPerformance.”ItcollatesthemarkupforeachdivelementontoamastercirclesHtmlstringthat’slaterinsertedintotheDOMinasingleaction.(IfyouweretoinsertthedivelementsintotheDOMoneatatime,thenegativeperformanceimpactwouldbesignificant:UIinteractioninthebrowserwouldbefrozenuntiltherelativelyslowelementinsertionprocesscompleted.)
Finally,itwrapsthecircleelementsinajQueryelementobjectsotheycanbeeasilymanipulatedasagroupintheupcomingCircleanimationsection.
Codesection:ContaineranimationClickheretoviewcodeimage
/******************************
Containeranimation
******************************/
$container
.css(“perspective-origin”,screenWidth/2+“px”+screenHeight/2+“px”)
.velocity(
{
perspective:[215,50],
opacity:[0.90,0.55]
},{
duration:800,
loop:1,
delay:3000
});
3DCSSprimerLet’sbeginthefirstofthetwoanimationsectionsofthecodebasebyfocusingontheelementthatcontainsthecircleelements.Beforedivingintothecode,however,here’saprimeronhow3Danimationworksinthebrowser:
Inorderfor3Dtransformstowork(forexample,translateZ,rotateX,rotateY),theCSSspecificationrequiresthattheperspectiveCSSpropertybeset
ontheelement’sparent.Inthiscase,that’swhatthe$containerelementisfor.
Thegreaterthevaluethatperspectiveissetto,thelessdistanceZ-axistranslations(viaCSS’stranslateZ)appeartomoverelativetotheirorigin.Inotherwords,ifyouwantmoreexaggerateddepthinyour3Danimations,settheparentelement’sperspectivepropertytosomethinglow,suchas50px,whichisinfactthevaluethatthecontainerelementissettointhedemo’sCSS.Incontrast,ahigherperspectivevalue,suchas250px,wouldresultinlessvisiblemovementfromtheoriginpointforeverypixelthattheelement’stranslateZpropertyisincrementedby.
AseparateandcomplementaryCSSpropertyisprospective-origin,whichdefinestheangleatwhichthevirtualcameraispositioned.Thevirtualcameraisthepeepholethroughwhichtheviewersees3Danimationunfoldinthebrowser.Thissection’scodeblockusesjQuery’s$.css()functiontosetaperspective-originvalueonthecontainerelementthatresultsinthecamerabeingpositionedatthecenterofthepage,creatingaperpendicularviewofthe3Danimation.Thisperpendicularviewresultsintheappearanceofcirclesflyingdirectlytowardandawayfromtheviewer.
Specifically,thiscodesectionsetsperspective-origintothepointonthepagethat’sathalfthebrowser’sheightandhalfitswidth—thecenterpointofthepage.ThisleveragesthewindowdimensionsqueriedintheAnimationsetupsection.
Withthatcontextoutoftheway,let’sexplorethissection’scode.
PropertiesThissection’scode,reproducedbelowforeasyreference,createsthedemo’szoominginandouteffect:Clickheretoviewcodeimage
$container
.css(“perspective-origin”,screenWidth/2+“px”+screenHeight/2+“px”)
.velocity(
{
perspective:[215,50],
opacity:[0.90,0.55]
},{
duration:800,
loop:1,
delay:3250
});
Whiletheprospective-originpropertyissetonceonthecontainerelementandthereafterleftalone,theprospectivepropertyisbeinganimatedbyVelocity.Thisisnecessarybecausetheintendedeffectofthedemoistokeepthevantagepointintothescenestationary(perpendicular),buttoexaggeratethende-exaggeratethedistanceoftheelementsfromthevirtualcamera,whichiswheretheperspectiveproperty’sanimationcomesin.
Specifically,thissectionusesVelocitytoanimatetheperspectiveCSSpropertytoafinalvalueof215pxfromastartingvalueof50px.
Bypassinginanarrayasananimationproperty’svalue,you’reforcefullyspecifying
thefinalvaluetoanimatethepropertytoward(215px,inthecaseabove)aswellastheinitialvaluetoanimatefrom(50px,inthecaseabove).WhileyoucertainlycouldhavepassedthepropertyasingleintegervalueasistypicallyexpectedbyVelocity,theforce-feedingsyntaxprovidesincreasedcontrolovertheproperty’scompleteanimationpath.Youmightbewondering,isn’tforce-feedingunnecessarysinceVelocityknowshowto
retrieveaCSSproperty’sstartingvalueonitsown?WhilethatisVelocity’sstandardbehaviorwhenanintegerispassedinasavalueinsteadofanarray,thisisn’talwaysadesirablebehaviorduetotheperformancedrawbacksinherenttoqueryingtheDOMforaproperty’sstartingvalue.Whattheforce-feedingsyntaxallowsyoutodoisexplicitlypassinastartingvaluesothatVelocitycanavoidqueryingtheDOMforapropertywhosestartingvalueyoualreadyknow.Inotherwords,the50pxstartingvalueusedintheperspectivecodeaboveisthesamevalueyouinitiallysetthecontainerelement’sperspectivepropertytointheCSSstylesheet.You’resimplyrepeatingthevaluehere.Noticethatthissameforce-feedingtechniqueisusedontheelement’sopacitypropertyaswell:it’sanimatedtoafinalvalueof0.90fromastartingvalueof0.55sincethat’swhatthepropertywassettointheCSS.
AsdiscussedthoroughlyinChapter7,“AnimationPerformance,”DOMqueriesareindeedtheAchilles’heelofperformantanimation:thebrowserperformsresource-intensivecalculationstodeterminethevisualstateofanelement.Whileit’snotimportanttothedemo’sperformancethatyouincludethisperformanceoptimization,sincetheassociatedVelocityanimationisn’tbeingtriggeredrepeatedlyinsidealoop,it’sincludednonethelesstocontrastforce-feeding’ssecondaryuse,whichyou’lllearnaboutlaterinthischapter.
Theneteffectofanimatingtheperspectiveandopacityisthatallofthecontainer’scircleelementsappeartozoominclosertothevirtualcamerawhileanimatingtoanincreasedbrightness(opacitygoesfrom0.55to0.90).Theopacityboostmimicsthewaythatlightbehavesintherealworld:thecloserthevieweristotheobjects,thebrightertheyappear!
OptionsThefinalsectionofContaineranimationcodeincludestheoptionsbeingpassedintoVelocity:duration,whichisselfexplanatory;delay,whichinsertsatime-outatthestartoftheanimation,andloop,whichloopsananimationbackandforthbetweenthevaluesdefinedinthepropertiesmapandtheelement’svaluespriortotheanimationoccurring.Specifically,bysettingloopto2,you’retellingVelocitytoanimatetothevaluesinpropertiesmap,backtowheretheywerebefore,thentorepeatthisfullloopiterationoncemoreaftera3000msdelay.
Note
Whendelayissetalongsideloop,thedelayoccursbetweeneachoftheloop’salternations.Usingdelaycreatesapleasantpausesothatthezoom-inandzoom-outeffectdoesn’tzigzagbackandforthabruptly.
Codesection:CircleanimationThisiswherethingsstartgettinginteresting.Let’stakealookthecircleanimation,inwhichyou’resimultaneouslyanimatingtheirX-,Y-,Z-axistranslationsindividually.You’realsoanimatingtheiropacity.Clickheretoviewcodeimage
/***************************
Circleanimation
***************************/
$circles
.appendTo($container)
.velocity({
opacity:[
function(){returnMath.random()},
function(){returnMath.random()+0.1}
],
translateX:[
function(){return“+=”+r(-screenWidth/2.5,screenWidth/2.5)},
function(){returnr(0,screenWidth)}
],
translateY:[
function(){return“+=”+r(-screenHeight/2.75,screenHeight/2.75)
},
function(){returnr(0,screenHeight)}
],
translateZ:[
function(){return“+=”+r(translateZMin,translateZMax)},
function(){returnr(translateZMin,translateZMax)}
]
},{duration:6000})
.velocity(“reverse”,{easing:“easeOutQuad”})
.velocity({opacity:0},2000);
ValuefunctionsUnlikethestaticanimationpropertyvaluesusedintheprevioussection(forexample,[215,50]),thissectionusesfunctionsforpropertyvalues:eachpropertyisforce-fedanarrayofstartandendvaluesthataredynamicallyproducedbyfunctions.Let’sbrieflyexplorethesevaluefunctions,whichareauniquefeatureofVelocity.
Note
ReadmoreaboutvaluefunctionsatVelocityJS.org/#valueFunctions.
Valuefunctionsletyoupassinfunctionsasanimationpropertyvalues.Thesefunctionstriggeratrun-time,andarecalledindividuallyforeachelementanimatedinaset.Inthedemo,thesetinquestionisthecircledivscontainedwithinthe$circlesjQueryelementobject.Consequently,eachcircleelementpropertywillbeassigneditsownrandomizedvalueoncetheanimationbegins.Theonlyotherwaytoachievedifferentiationbetweenanimationpropertiesinasetofelementsistoanimatetheelementsseparatelybyloopingthroughthem,whichgetsmessyandperformsbadly.Thisisthebenefitofvaluefunctions—youkeepdynamicanimationcodeterseand
maintainable.
Noticethat,toproducetherandomizedvalues,thissectionofcodeleveragesourrhelperfunctionthatwasdefinedinAnimationsetup.(Asareminder,therfunctionreturnsarandomizedintegervalueconstrainedbyitsminandmaxarguments.)You’lllearnmoreaboutthisfunctionmomentarily.
OpacityanimationTheopacitypropertyanimatesfromandtowardrandomizedvalues.Inthecaseofthestartingvalue,you’regivingtherandomizedvalueaslightboosttoensurethattheelementsarenevertooclosetobeinginvisible—afterall,youwanttheviewertoseewhatyou’reanimating!Theanimationofopacityresultsinasmatteringofcirclesalloverthepagethathavevaryingopacitiesfromtheveryfirstframe.Differentiatedopacitiescreateanicegradienteffectthataddsvisualrichnesstothedemo.
Thiscodetakesadvantageofforce-feedingforapurposeotherthanperformanceoptimization:valuefunctionsarebeingforce-fedtodynamicallygeneratestartvaluesfortheelementsthathaveyettobeinsertedintotheDOM,whichmeansthatyou’resuccessfullyavoidingwritinganentirelynewcodeblockjusttosettheinitialCSSstatesofthecircleelements.You’redynamicallyprovidinguniquestartingpositionsinthesamelineofcoderesponsibleforanimatingthosepositions.AsdiscussedthoroughlyinChapter4,“AnimationWorkflow,”youshouldstriveforthislevelofexpressivenessinallofyouranimationcode.
TranslationanimationForeasyreference,here’sthissection’scodeonceagain:Clickheretoviewcodeimage
/***************************
Circleanimation
***************************/
$circles
.appendTo($container)
.velocity({
opacity:[
function(){returnMath.random()},
function(){returnMath.random()+0.1}
],
translateX:[
function(){return“+=”+r(-screenWidth/2.5,screenWidth/2.5)},
function(){returnr(0,screenWidth)}
],
translateY:[
function(){return“+=”+r(-screenHeight/2.75,screenHeight/2.75)
},
function(){returnr(0,screenHeight)}
],
translateZ:[
function(){return“+=”+r(translateZMin,translateZMax)},
function(){returnr(translateZMin,translateZMax)}
]
},{duration:6000})
.velocity(“reverse”,{easing:“easeOutQuad”})
.velocity({opacity:0},2000);
It’stimetoexaminethetranslateanimations,whichindividuallytranslatethecircleelements’positionswithinthedemo’s3Dspace.Allthreeaxesareanimatingfromarandomizedstartvaluetowardarandomizedendvalue.Thevalueoperator,whichconsistsoftheplussignfollowedbytheequalssign(+=),tellstheanimationenginetoanimatepropertiesincrementallyfromtheirstartingvalues.Inotherwords,the+=valueoperatorinstructstheanimationenginetotreattheendingvalueasarelativevalue.Incontrast,thedefaultbehaviorofananimationengineistointerpretanendvalueinabsoluteterms.
Aswithopacity,thiscodesectionleveragesforce-feedingandvaluefunctionsfortheirexpressivityandperformancebenefits.Inparticular,thecircles’movementisconstrainedwithinrangesrelativetothescreendimensionsfortheXandYaxes,andrelativetothepredefinedminandmaxdepthvaluesfortheZ-axis.(Asareminder,thesevaluesweresetintheAnimationsetupsection.)InthecaseoftheXandYaxes,there’sanarbitraryfudgefactor(noticethedivisionby2.75)toreducehowspreadouttheelementsanimate.Thisvalueissimplyacreativedecision;tweakittosuityouraestheticpreference.
Finally,theoptionsobjectspecifiesthatthisentireanimationshouldoccuroveradurationof6000ms.
ReversecommandAftertheprimaryVelocityanimationcall,thechaincontinueswithacalltoVelocity’sreversecommand.Reversedoesexactlywhatitsoundslikeit:itanimatesthetargetelementsbacktotheirinitialvaluespriortothepreviousVelocitycalltakingplace.Inthisuniquecase,sincestartvalueshavebeenforce-fedintothepreviousVelocitycall,thosearethestartvaluesthatreversewillanimatebacktoward.
Oneofmyreasonsforincludingthereversecommandinthisdemoistoextendthedemo’soverallanimationdurationwithasinglelineofmaintainableandexpressivecode.(Whileyoucoulddoublethedurationoftheanimationfrom6000msto12000ms,thiswouldresultinslowingdownthemovementofthecircles.)Theconvenienceofthereversecommandisavoidinghavingtorespecify—byhand—alloftheanimationstartvalues.Itwouldhavebeenahugemesstoaccomplishthismanuallysinceyouwouldhavehadtofirststorealloftherandomlygeneratedstartvaluesintomemorysoyoucouldanimatebacktothem.Hence,reverseisyetanothergreatVelocityfeaturethatallowsthedemotoaccomplishalotwithjustafewlinesofcode.
Velocity’sreversecommanddefaultstotheoptionsobjectusedinthepreviousVelocitycall—includingitsduration,easing,andsoon.Inthiscase,sincethepreviouscallusedadurationof6000ms,sowillthereversecall.Thereversecommandalsoletsyouspecifyanewoptionsobjecttoextendontothepreviousone.ThisdemousesaneweasingtypeofeaseOutQuadforaddedmotiondesignflairintheanimation’sreversedirection.
Tip
Topreviewthebehaviorofthepopulareasingtypes,visithttp://easings.net.
Whenthereverseanimationcompletes,afinalVelocitycallfadestheelementsoutofviewbytransitioningtheiropacityvaluesto0overadurationof2000ms.Thiscompletesthedemobyleavingthebrowser’scanvasinthesamevisualstateitbeganin:cleanandempty!Yourworkhereisdone.
WrappingupFromforce-feeding,tovaluefunctions,toreverse,thiswalkthroughhasillustratedthepoweroftheVelocityanimationengine.Hopefully,thischapterhasconvincedyouthatthisbook’sfocusonVelocitywasworthwhile.Infewerthan75linesofterse,legible,andperformantcode,you’vecreatedarich3Dsceneunlikeanythingyou’veseenbeforeinpureHTML.
Letthisdemoserveasaconcreteexampleofjusthowsimpleintricate-lookinganimationscanactuallybe—especiallywhenyouusetherighttoolsandemploybestpractices.Myhopeisthatthisbookhasdistilledthebeautifulanimationworkyou’veseenacrossthewebintoasetoftenetsthatareeasytograspandfollowinpursuitofyourownmotiondesign.
Now,goanddesignsomebeautifulwebsitesandapps!Onceyou’veputtogethersomethingcool,showmeonTwitter:twitter.com/shapiro.
Index
SymbolsandNumbers$.animate()13
3D
CSSprimeron156
transforms96
AAdobeAfterEffect,animatingtextand80
AdobePhotoshop,SVGand104
Alerts,leveraginguserresponse42–43
Android
purchasingolderdevicesfromeBay144
realitiesofwebperformance118
Animationdemo
behaviors148–149
codesectionforanimationsetup153–154
codesectionforcircleanimation160–164
codesectionforcirclecreation154–155
codesectionforcontaineranimation156–159
codestructure150–152
overviewof147
review165
Animationlibraries
bypassingjQuery6
pagescrollingfunctions7
SVGsupport108
typesof14
Animationreversal,performancefeaturesofJavaScript7–8
Animations.SeealsoMotiondesign
breakingintosteps48–49
effectsonneighboringelements130
limitinginmotiondesign45
mirroring44
olderbrowsersproblem139
olderbrowserssolutions139–140
optimizedcodingapproachtoorganizingsequencedanimations66–68
performance.SeePerformance
reducingconcurrency43
reducingvariety44
staggering49
standardcodingapproachtoorganizingsequencedanimations65–66
oftext.SeeTextanimation
workflows.SeeWorkflows
Animations,withSVG
animatedlogoexample112–113
overviewof109
passingproperties109
positionalattributesvs.transforms110–111
presentationalattributes110
Arguments,Velocity16–18
Attributes,SVGmarkup105–106
BbackgroundColorproperty,VelocitysupportforCSScolorproperties31–32
backwardsoption,benefitsintextanimation92–93
Baselines,loadtestingand120
BatchingDOMadditions
codesectionforcirclecreation155
problem126–127
solutions127–128
beginoption,Velocity24
Béziercurves,easingvaluesinVelocity22
Blast.js
customClassoption85–86
delimiteroption85
generateValueClassoption86–87
howitworks83–84
installingonpages84–85
preparingtextelementsusing82–83
reverseoption88–89
tagoption87–88
Blue,VelocitysupportforCSScolorproperties31–32
bodytag,installingBlastand84
Boldtext,tagoptioninBlastand88
Booleanvalues,generateValueClassoptioninBlast86–87
borderColorproperty,VelocitysupportforCSScolorproperties31–32
border-radiussetproperty,inbehaviorofanimationdemo148
Bottlenecks
problem133
solutions133–134
Bottomline,performanceaffecting117
box-shadowproperty,CSS
inbehaviorofanimationdemo148
overviewof138
Browsers
animationsonolderbrowsersproblem139
animationsonolderbrowserssolution139–140
bottlenecksand133
findingperformancethresholdearlyon141–143
positionalattributesvs.transformsand110
realitiesofwebperformance118
supportforolderversions4
BrowserStack.com,testingbrowserson142
Buttons,usesofSVG109
CCallbackfunctions,beginandcompleteoptionsinVelocity24
Chaining
effectsand69
usingVelocitywithjQueryand16
inVelocity20
characterdelimiter,Blast.js82,85
Chrome,realitiesofwebperformance118
circleelement
inbehaviorofanimationdemo148
codesectionforcircleanimation160–164
codesectionforcirclecreation154–155
codestructureforanimationdemo153–154
SVGpresentationalattributes106
SVGstyling106
Classes
customClassoptioninBlast85–86
generateValueClassoptioninBlast86–87
Code/codingtechniques
codesectionforanimationsetup153–154
codesectionforcircleanimation160–164
codesectionforcirclecreation154–155
codesectionforcontaineranimation156–159
codestructureforanimationdemo150–152
creatingimagesthroughcodeinSVG104
optimizedapproachtoorganizingsequencedanimations66–68
optimizedapproachtopackagingeffects70–72
optimizedapproachtoseparatingstylingfromlogic60–65
standardapproachtoorganizingsequencedanimations65–66
standardapproachtopackagingeffects69
standardapproachtoseparatingstylingfromlogic59–60
whatgoodcodelookslike57
colorproperty,VelocitysupportforCSScolorproperties31–32
Colors
performancebenefitsofusingopacityinsteadof132
Velocityoptions31–32
completeoption,Velocity24
Compression,SVGand104
Concurrency
problem133
reducinginmotiondesign43
solutions133–134
Consistency,patternrecognitionandunderstandingand44
Containers
codesectionforcontaineranimation156–159
codestructureforanimationdemo153–154
SVG(<svg>)105
textelements80
Conventions,inmakingdesignchoices41
CSS
3Dprimer156
animationeffectsonneighboringelements130–131
appropriateusesofCSSworkflow57–58
benefitofswitchingtoJavaScriptforsegregationoflogic62
comparingSVGpositionalattributeswithCSStransforms110
comparingVelocitydisplayandvisibilityoptionswith27–29
comparingVelocitypropertieswithCSSproperties18–19
comparingVelocityvalueswithCSSvalues20
easingvaluesinVelocity22
fine-grainedcontrolofBlastelements94
issueswithCSSworkflow56–57
JavaScriptcomparedwith4–9
perspectiveproperties156–157
separatingstylingfromlogic59–60
sneakyimagesand138
SVGstylingcomparedwith107
Velocityargumentscorrespondingto16
VelocitysupportforCSStransformproperty32
customClassoption,Blast.js85–86
DDatatransferindicators,previewoptionsinmotiondesign41
Debouncing,eventhandlers135–136
delayoption,Velocity26
Delayvalues
staggeringdurationsand91
timingmultipliersand73
Delimiters,Blast.js82,85
Designtechniques.SeealsoMotiondesign
pagescrollinginWebdesign7
timingmultipliers73–74
VMD(VelocityMotionDesigner)74–76
DeviceLab142
displayoption,Velocity27–28
div
inbehaviorofanimationdemo148
Blast.js82
HTMLelements83
tagoptioninBlast88
DOM(DocumentObjectModel)
batchingDOMadditionsforimprovedperformance126–128,155
layoutthrashingproblem121–122
layoutthrashingsolution122–123
retrievingrawDOMelements33–34
SVGelementsasDOMelements104
durationoption,Velocity21
Durations
limitinginmotiondesign45
staggering91
timingmultipliersand73
EEasingoptions,Velocity21–23
eBay,purchasingolderdevicesfrom144
Effects
fadeeffectinUIpack91
fancifuleffectsintext96
flourishesintext97–98
optimizedcodingapproachtopackaging70–72
standardcodingapproachtopackaging69
transition.fadeOuteffectinUIpack92
Eleganceaspects,ofmotiondesign
breakinganimationintosteps48–49
flowingfromtriggeringelements49
graphicsuse50
notbeingfrivolous47
opacityuse48
overviewof39–40
staggeringanimations49
usingappropriatepersonalityfeatures47–48
Elementnodes,HTML83
Elements
animationeffectsonneighboringelements130–132
circleelement.Seecircleelement
fine-grainedcontrolofBlastelements94
flowingfromtriggeringelements49
HTMLelementmanipulation148
imagerenderingproblems137
imagerenderingsolutions137–138
JEOs(jQueryelementobjects)123–124,126–128
preparingtextelementsforanimationusingBlast.js82–83
retrievingrawDOMelements33–34
spanelements87–88
SVGelementscomparedwithHTMLelements104
textelements80
eq()function,jQuery94
Eventhandlers,debouncing135–136
Experimentation,benefitsofrepeatedlyexperimenting51–52
FFadeeffect,inUIpack91
Familiarity,useofconventionsinmakingdesignchoices41
fill,SVG
presentationalattributes105
styling107
Flags,leveraginguserresponse42–43
Flourishes,intext97–98
Flow,creatingfromtriggeringelements49
Force-feedingfeature(Velocity),foravoidinglayoutthrashingproblem124–125
Frivolousdesign,usesandabusesof47
GgenerateValueClassoption,Blast.js86–87
gets
JEOsasculpritinlayoutthrashing123–124
layoutthrashingand121–122
Globaltimingmultipliers73–74
Gradients,CSS138
Graphics
inelegantmotiondesign50
SVGand104,109
Green,VelocitysupportforCSScolorproperties31–32
GSAPanimationlibrary14
HHeight,SVGpresentationalattributes105
Hiddensetting,displayandvisibilityoptions28
Hoverstateanimations,usesofCSS6,57–58
HTML
codingwebpages80
elementmanipulation148
elementnodes83
SVGelementscomparedwithHTMLelements104
IImages
creatingthroughcodeinSVG104
renderingproblems137
renderingsolutions137–138
sneakyimageproblems139
sneakyimagesolutions139–140
imgelement138
Incentives,visceralnatureofinteractionsand43
Infinitelooping,inVelocity25–26
SeealsoLoops
Inkscape104
Inlinestatusindication,engagingusersintasks42
In-progressindicators,previewoptionsinmotiondesign41–42
InternetExplorer
animationsonolderbrowsersproblem139
findingperformancethresholdearlyon141–143
positionalattributesvs.transformsand110
realitiesofwebperformance118
iOS,purchasingolderdevicesfromeBay144
Irreversibleactions,indicatorsfor43
JJanks(stutters),layoutthrashingand121
JavaScriptvs.CSS
animationreversalfeatureinJavaScript7–8
overviewof4
pagescrollingfeatureinJavaScript7
performancebenefits6
physics-basedmotioninJavaScript8
review10
workflowmaintenance9
JEOs(jQueryelementobjects)
batchingDOMadditionsforimprovedperformance126–128
asculpritinlayoutthrashing123–124
jQuery
easingoptions22–23
fine-grainedcontrolofBlastelements94
installing15
JavaScriptanimationlibrariesthatbypass6
requiredbyBlast84–85
slownessofanimationfeaturesin4
standardcodingapproachtoseparatingstylingfromlogic59
usingVelocitywith16
usingVelocitywithout33–34
Velocitycomparedwith13
jQueryelementobjects.SeeJEOs(jQueryelementobjects)
LLatency,searchengineperformanceand117
Layoutthrashing
force-feedingfeatureinVelocityforavoiding124–125
JEOs(jQueryelementobjects)asculpritin123–124
problem121–122
solutions122–123
Loadtesting,realitiesofwebperformanceand120
Logic
optimizedcodingapproachtoseparatingfromstyling59–60
standardcodingapproachtoseparatingfromstyling59
Logos
animatedlogoexampleinSVG112–113
usesofSVG109
loopoption,Velocity25–26
Loops
codesectionforcontaineranimation159
layoutthrashingand121–122
MMaintenance,ofworkflows9
Markup,SVG105–106
Maxvalues,codesectionforanimationsetup154
Minvalues,codesectionforanimationsetup154
Mockfeature,Velocity74
Motiondesign
alertsandflagsforleveraginguserresponse42–43
appropriatepersonalityfeatures47–48
breakinganimationintosteps48–49
conventionsinmakingdesignchoices41
engagingusersintasks42
experimentingrepeatedly51–52
flowingfromtriggeringelements49
graphicsuse50
indicatorsofseverityofirreversibleactions43
limitinganimations45
limitingdurations45
mirroringanimations44
notbeingfrivolous47
opacityuse48
overviewof37
previewingoutcomes41
reducingconcurrency43
reducingvariety44
review53
staggeringanimations49
utilityandeleganceof39–40
UX(userexperience)improvedby38
visceralnatureofinteractions43
MozillaDeveloperNetwork,directoryofSVGelements114
Multi-animationsequences,solutionstoconcurrencyissues134
Multipliers,timingmultipliersasdesigntechnique73–74
OOpacity
animationof161
flourishesintext97–98
goingbeyondoveruseof48
performancebenefitsofusinginsteadofcolor132
opacityproperty161
outlineColorproperty,VelocitysupportforCSScolorproperties31–32
PPagescrolling,performancefeaturesofJavaScript7
Seealsoscrollcommand
Performance
animationeffectsonneighboringelementsproblem130
animationeffectsonneighboringelementssolution131–132
animationsonolderbrowsersproblem139
animationsonolderbrowserssolution139–140
batchDOMadditionsproblem126–127
batchDOMadditionssolutions127–128
bottleneckconcurrencyproblems133
bottleneckconcurrencysolutions133–134
featuresofJavaScript6
findingperformancethresholdearlyon141–143
force-feedingfeatureinVelocityforavoidinglayoutthrashing124–125
imagerenderingproblems137
imagerenderingsolutions137–138
JEOs(jQueryelementobjects)and123–124
layoutthrashingproblem121–122
layoutthrashingsolution122–123
overviewof117
realitiesofwebperformance118–120
review145
scrollandresizeeventproblems135
scrollandresizeeventsolutions135–136
sneakyimageproblems139
sneakyimagesolutions139–140
Personality,usingappropriatepersonalityfeaturesinmotiondesign47–48
Perspectiveproperties,CSS156–157
Physics-basedmotion,performancefeaturesofJavaScript8
Pixels,imagerenderingproblems137
Positionalattributes,SVG110–111
Presentationalattributes,SVG105,110
Previews,previewingoutcomesinmotiondesign41
Properties
inbehaviorofanimationdemo148
CSSperspectiveproperties156–157
CSSshadowproperties138
passingpropertiesinSVGanimations109
Velocity18–19
VelocitysupportforCSScolorproperties31–32
px,asdefaultunitinVelocity19–20
RRandomnumbers,codesectionforanimationsetup153
Red,VelocitysupportforCSScolorproperties31–32
resizeevents
performanceproblems135
performancesolutions135–136
reversecommand
animationreversalfeatureinJavaScript7–8
codesectionforcircleanimation163–164
inVelocity30
reverseoption,Blast.js88–89
RGB(red,green,blue),VelocitysupportforCSScolorproperties31–32
Rotation,CSStransformproperty32
SSafari,realitiesofwebperformance118
Scalablevectorgraphics.SeeSVG(scalablevectorgraphics)
Scale,CSStransformproperty32
scrollcommand
overviewof30–31
Velocitypagescrolling7
scrollevents
performanceproblems135
performancesolutions135–136
Scrolling,pageanimationand137
Searchengines,latencyand117
sentencedelimiter,Blastoptions84–85
Sequencerunning,inUIpack65
Sequencedanimations
optimizedcodingapproachtoorganizing66–68
standardcodingapproachtoorganizing65–66
sets,layoutthrashingand121–122
setup
codesectionforanimationsetup153–154
codestructureforanimationdemo150
Shadowproperties,CSS138
Shorthandfeatures,inVelocity20
Sketchprogram104
Smartphones
animationsonolderbrowsersand139
purchasingfromeBay144
realitiesofwebperformance118
Sneakyimages,performanceissues139–140
Spanelements
animatingtextand80
tagoptioninBlast87–88
Springphysics,easingvaluesinVelocity23
staggerfeature,inUIpack133–134
Staggering
animations49
solutionstoconcurrencyissues133–134
solutionstoimagerenderingissues138
textanimationand91
Statusindicators
datatransferindicators41
loadingtextand97
usesofSVG109
Stutters(janks),layoutthrashingand121
Stylesheets,JavaScriptvs.CSS4
SeealsoCSS
Styling
optimizedcodingapproachtoseparatingfromlogic60–65
standardcodingapproachtoseparatingfromlogic59–60
SVG107
SVG(scalablevectorgraphics)
animatedlogoexample112–113
animatinggraphiccomponents50
animations109
creatingimagesthroughcode104
goingbeyondrectangles111
markup105–106
overviewof103
passingproperties109
positionalattributesvs.transforms110–111
presentationalattributes110
review112–113
styling107
supportfor108
SVGPocketGuide(Trythall)114
Syntax
argumentsinVelocity17–18
SVGmarkup105–106
TTables,HTMLelements83
tagoption,Blast.js87–88
Textanimation
customClassoptioninBlast85–86
delimiteroptioninBlast85
flourishesintext97–98
generateValueClassoptioninBlast86–87
howBlast.jsworks83–84
installingBlastonpage84–85
overviewof79
preparingtextelementsusingBlast.js82–83
replacingexistingtext90
reverseoptioninBlast88–89
review100
staggeringoption91
standardapproachto80
tagoptioninBlast87–88
transitioningindividualtextparts94–95
transitioningtextoutofview91–93
transitioningtextusingfancifuleffects96
Textnodes80
text-shadowproperty,CSS138
Thresholds,findingperformancethresholdearly141–143
Timingcontrol
delayoption26
JavaScriptvs.CSS4
Timingmultipliers,asdesigntechnique73–74
transformproperty,Velocity31–32
Transforms
3DCSSprimer156
3Dtransforms96
animationeffectsonneighboringelementsand131
comparingSVGpositionalattributeswithCSStransforms110–111
transition.fadeOuteffect,inUIpack92
transition.perspectiveDowneffect,inUIpack96
Transitions
individualtextparts94–95
limitingdurations45
replacingexistingtext90
staggeringdurations91
textoutofview91–93
textusingfancifuleffects96
textvisibility80
Translations
3DCSSprimer156
animationeffectsonneighboringelementsand131
animationof162–163
codesectionforcircleanimation160
CSStransformproperty32
mirroringand44
Triggers,flowingfromtriggeringelements49
Trigonometriceasings,easingvaluesinVelocity22
UUI(userinterface)
conventionsinmakingdesignchoices41
motiondesignimprovinguserexperience38
UIanimationlibraries14
UIanimationworkflow65
UIpack
fadeeffectin91
gettingandinstalling65
optimizedcodingapproachtopackagingeffects70–72
staggerfeaturein133–134
transition.fadeOuteffect92
transitioningtextfancifully96
Unittypes,valuesinVelocity19–20
Userexperience.SeeUX(userexperience)
Userinterface.SeeUI(userinterface)
Utilityaspects,ofmotiondesign
alertsandflagsforleveraginguserresponse42–43
conventionsinmakingdesignchoices41
engagingusersintasks42
indicatorsofseverityofirreversibleactions43
limitinganimations45
limitingdurations45
mirroringanimations44
overviewof39–40
previewingoutcomes41
reducingconcurrency43
reducingvariety44
visceralnatureofinteractions43
Utilityfunction,Velocity66
UX(userexperience)
motiondesignimproving38
performanceaffecting117
physics-basedmotioninJavaScriptenhancing8
VValues
codesectionforanimationsetup154
valuefunctions161
Velocity19–20
Variety,reducinginmotiondesign44
Velocity
animationdemo.SeeAnimationdemo
arguments16–18
beginandcompleteoptions24
chaining20
coloroptions31–32
comparedwithjQuery13
containinganimationlogicwithin29
delayoption26
displayandvisibilityoptions27–28
downloadingandinstalling15
durationoption21
easingoptions21–23
force-feedingfeatureforavoidinglayoutthrashing124–125
loopoption25–26
mockfeature74
optimizedcodingapproachtoorganizingsequencedanimations66–68
pagescrollingfunctions7
passingpropertiesinSVGanimations109
physics-basedmotion8
properties18–19
resourceforSVGattributesandstylingproperties114
reversecommand30
review33–34
scrollcommand30–31
transformproperty31–32
typesofanimationlibraries14
UIpack65
usingwithjQuery16
usingwithoutjQuery33–34
values19–20
VelocityMotionDesigner(VMD)74–76
Video.SeealsoImages
imagerenderingproblems137
imagerenderingsolutions137–138
Visibility
replacingexistingtext90
transitioningtextoutofview91–93
transitioningtextvisibility80
visibilityoption,Velocity27–28
Visualprocessing,leveragingprimalinstinctsinmotiondesign42–43
VMD(VelocityMotionDesigner)74–76
WWebdesign,useofpagescrollingin7
Webperformance,realitiesof118–120
Width,SVGpresentationalattributes105
worddelimiter,Blastoptions85
Workflows
CSSappropriateuses57–58
CSSissues56–57
maintainabilityof9
optimizedcodingapproachtoorganizingsequencedanimations66–68
optimizedcodingapproachtopackagingeffects70–72
optimizedcodingapproachtoseparatingstylingfromlogic60–65
overviewof55
review77
standardcodingapproachtoorganizingsequencedanimations65–66
standardcodingapproachtopackagingeffects69
standardcodingapproachtoseparatingstylingfromlogic59–60
timingmultipliersasdesigntechnique73–74
VMD(VelocityMotionDesigner)74–76
Xxvalue,SVGpresentationalattributes105
Yyvalue,SVGpresentationalattributes105
CodeSnippets