web animation using javascript - programmer books€¦ · chapter 2 animating with velocity.js...

Post on 25-Jun-2020

14 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

WebAnimationusingJavaScriptDEVELOPANDDESIGN

JulianShapiro

WWW.PEACHPIT.COM

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,contactpermissions@peachpit.com.

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

top related