Front End Web Development: The Big Nerd Ranch Guide (opal Opal Parris' Library) (Big Guides) Chris Aquino, Todd Gandee Development Gu

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 576 [warning: Documents this large are best viewed by clicking the View PDF Link!]

Front-EndWebDevelopment:TheBig
NerdRanchGuide
byChrisAquinoandToddGandee
Copyright©2016BigNerdRanch,LLC
Allrightsreserved.PrintedintheUnitedStatesofAmerica.Thispublicationisprotected
bycopyright,andpermissionmustbeobtainedfromthepublisherpriortoanyprohibited
reproduction,storageinaretrievalsystem,ortransmissioninanyformorbyanymeans,
electronic,mechanical,photocopying,recording,orlikewise.Forinformationregarding
permissions,contact
BigNerdRanch,LLC
200ArizonaAveNE
Atlanta,GA30307
(770)817-6373
http://www.bignerdranch.com/
book-comments@bignerdranch.com
The10-gallonhatwithpropellerlogoisatrademarkofBigNerdRanch,LLC.
ExclusiveworldwidedistributionoftheEnglisheditionofthisbookby
PearsonTechnologyGroup
800East96thStreet
Indianapolis,IN46240USA
http://www.informit.com
Theauthorsandpublisherhavetakencareinwritingandprintingthisbookbutmakeno
expressedorimpliedwarrantyofanykindandassumenoresponsibilityforerrorsor
omissions.Noliabilityisassumedforincidentalorconsequentialdamagesinconnection
withorarisingoutoftheuseoftheinformationorprogramscontainedherein.
Manyofthedesignationsusedbymanufacturersandsellerstodistinguishtheirproducts
areclaimedastrademarks.Wherethosedesignationsappearinthisbook,andthe
publisherwasawareofatrademarkclaim,thedesignationshavebeenprintedwithinitial
capitallettersorinallcapitals.
ISBN-100134432533
ISBN-13978-0134432533
Firstedition,firstprinting,July2016
ReleaseE.1.1.1
Dedication
ToMomandDad,forbuyingusthatcomputer.ToDaveandGlenn,forlettingyour
littlebrothercompletelyhogit.AndtoAngela,forgivingmealifeawayfromthe
screen.
 —C.A.
Tomymomanddad,thankyouforgivingmeroomtofindmyownway.Tomywife,
thankyouforlovinganerd.
 —T.G.
Acknowledgments
Asauthors,wecantakefullcreditfortypingthewordsandcreatingthediagrams.(Yay,
us!)Butthewholetruthisthatwewouldstillbestaringatablankpageifnotforthe
effortsofanarmyofcontributors,collaborators,andmentors.
AaronHillegass,forbelievingthatthetwoofuscouldproduceaworkworthyof
theBigNerdRanchname.Thankyouforyourimmeasurablefaithandsupport.
MattMathias,forguidingusthroughthedevelopmentofthisbook,especially
duringthecruciallastmile.Youmadesurethattimethatwouldhavebeenspent
watchingcatvideosorDowntonAbbeyrerunswasinsteaddedicatedtowriting.
BrandyPorter,forthecareand(literal)feedingoftheauthorsonnumerous
occasions.Youworkedyourmagicbehindthecurtain,orchestratingasequence
ofeventsthatmadefinishingthisworkpossible.Thankyou.
JonathanMartin,ourcoinstructorandlanguagemaven.Thankyoufor
enthusiasticallyteachingthein-progresscoursematerialsonwhichthisbookis
basedandofferingthoughtfulcriticismthroughoutthemanyrevisions.
Ourproofreaders,technicalreviewers,andguineapigs:MikeZornek,Jeremy
Sherman,JoshJustice,JasonReece,GarrySmith,AndrewJones,Stephen
Christopher,andBillPhillips.Thankyouforvolunteeringastribute.
ElizabethHoladay,ourinfinitelypatientandreassuringeditor.Thankyoufor
breakingusoutoftheechochamber,beingthevoiceofreason,andremindingus
alwaysofourreaders.
EllieVolckhausen,whodesignedourcover.
SimonePayment,ourproofreader,whokeptthingsconsistent.
ChrisLoperatIntelligentEnglish.com,whodesignedandproducedtheprintand
ebookversionsofthebook.HisDocBooktoolchainmadelifemucheasier,too.
Lastly,thankyoutothecountlessstudentswhohavetakentheweek-longtraining.
Withoutyourcuriosityandyourquestions,noneofthismatters.Thisworkisareflection
oftheinsightandinspirationyouhavegivenusoverthespanofthosemanyweeks.We
hopetheottersmadethetrainingalittlelighter.
TableofContents
Introduction
LearningFront-EndWebDevelopment
Prerequisites
HowThisBookIsOrganized
HowtoUseThisBook
Challenges
FortheMoreCurious
UsinganeBook
I.CoreBrowserProgramming
1.SettingUpYourDevelopmentEnvironment
InstallingGoogleChrome
InstallingandConfiguringAtom
Atomplug-ins
DocumentationandReferenceSources
CrashCourseintheCommandLine
Findingoutwhatdirectoryyouarein
Creatingadirectory
Changingdirectories
Listingfilesinadirectory
Gettingadministratorprivileges
Quittingaprogram
InstallingNode.jsandbrowser-sync
FortheMoreCurious:AlternativestoAtom
2.SettingUpYourFirstProject
SettingUpOttergram
InitialHTML
Linkingastylesheet
Addingcontent
Addingimages
ViewingtheWebPageintheBrowser
TheChromeDeveloperTools
FortheMoreCurious:CSSVersions
FortheMoreCurious:Thefavicon.ico
SilverChallenge:Addingafavicon.ico
3.Styles
CreatingaStylingBaseline
PreparingtheHTMLforStyling
AnatomyofaStyle
YourFirstStylingRule
Theboxmodel
StyleInheritance
MakingImagesFittheWindow
Color
AdjustingtheSpaceBetweenItems
Relationshipselectors
AddingaFont
BronzeChallenge:ColorChange
FortheMoreCurious:Specificity!WhenSelectorsCollide…
4.ResponsiveLayoutswithFlexbox
ExpandingtheInterface
Addingthedetailimage
Horizontallayoutforthumbnails
Flexbox
Creatingaflexcontainer
Changingtheflex-direction
Groupingelementswithinaflexitem
Theflexshorthandproperty
Ordering,justifying,andaligningflexitems
Centeringthedetailimage
AbsoluteandRelativePositioning
5.AdaptiveLayoutswithMediaQueries
ResettingtheViewport
AddingaMediaQuery
BronzeChallenge:Portrait
FortheMoreCurious:CommonSolutions(andBugs)withFlexbox
Layouts
GoldChallenge:HolyGrailLayout
6.HandlingEventswithJavaScript
PreparingtheAnchorTagsforDuty
YourFirstScript
OverviewoftheJavaScriptforOttergram
DeclaringStringVariables
WorkingintheConsole
AccessingDOMElements
WritingthesetDetailsFunction
Acceptingargumentsbydeclaringparameters
ReturningValuesfromFunctions
AddinganEventListener
AccessingAlltheThumbnails
IteratingThroughtheArrayofThumbnails
SilverChallenge:LinkHijack
GoldChallenge:RandomOtters
FortheMoreCurious:StrictMode
FortheMoreCurious:Closures
FortheMoreCurious:NodeListsandHTMLCollections
FortheMoreCurious:JavaScriptTypes
7.VisualEffectswithCSS
HidingandShowingtheDetailImage
Creatingstylestohidethedetailimage
WritingtheJavaScripttohidethedetailimage
Listeningforthekeypressevent
Showingthedetailimageagain
StateChangeswithCSSTransitions
Workingwiththetransformproperty
AddingaCSStransition
Usingatimingfunction
Transitiononclasschange
TriggeringtransitionswithJavaScript
CustomTimingFunctions
FortheMoreCurious:RulesforTypeCoercion
II.Modules,Objects,andForms
8.Modules,Objects,andMethods
Modules
Themodulepattern
ModifyinganobjectwithanIIFE
SettingUpCoffeeRun
CreatingtheDataStoreModule
AddingModulestoaNamespace
Constructors
Aconstructorsprototype
Addingmethodstotheconstructor
CreatingtheTruckModule
Addingorders
Removingorders
Debugging
LocatingbugswiththeDevTools
Settingthevalueofthiswithbind
InitializingCoffeeRunonPageLoad
CreatingtheTruckinstance
BronzeChallenge:TruckIDforNon-Trekkies
FortheMoreCurious:PrivateModuleData
SilverChallenge:MakingdataPrivate
FortheMoreCurious:SettingthisinforEach’sCallback
9.IntroductiontoBootstrap
AddingBootstrap
HowBootstrapworks
CreatingtheOrderForm
Addingtextinputfields
Offeringchoiceswithradiobuttons
Addingadropdownmenu
Addingarangeslider
AddingSubmitandResetbuttons
10.ProcessingFormswithJavaScript
CreatingtheFormHandlerModule
IntroductiontojQuery
ImportingjQuery
ConfiguringinstancesofFormHandlerwithaselector
AddingthesubmitHandler
Extractingthedata
Acceptingandcallingacallback
UsingFormHandler
RegisteringcreateOrderasasubmithandler
UIEnhancements
BronzeChallenge:SupersizeIt
SilverChallenge:ShowingtheValueastheSliderChanges
GoldChallenge:AddingAchievements
11.FromDatatoDOM
SettingUptheChecklist
CreatingtheCheckListModule
CreatingtheRowConstructor
CreatingDOMelementswithjQuery
CreatingCheckListRowsonSubmit
Manipulatingthiswithcall
DeliveringanOrderbyClickingaRow
CreatingtheCheckList.prototype.removeRowmethod
Removingoverwrittenentries
WritingtheaddClickHandlermethod
CallingaddClickHandler
BronzeChallenge:AddingtheStrengthtotheDescription
SilverChallenge:ColorCodingbyFlavorShot
GoldChallenge:AllowingOrderEditing
12.ValidatingForms
TherequiredAttribute
ValidatingwithRegularExpressions
ConstraintValidationAPI
Listeningfortheinputevent
Associatingthevalidationcheckwiththeinputevent
Triggeringthevaliditycheck
StylingValidandInvalidElements
SilverChallenge:CustomValidationforDecaf
FortheMoreCurious:TheWebshimsLibrary
13.Ajax
XMLHttpRequestObjects
RESTfulWebServices
TheRemoteDataStoreModule
SendingDatatotheServer
UsingjQuery’s$.postmethod
Addingacallback
InspectingtheAjaxrequestandresponse
RetrievingDatafromtheServer
Inspectingtheresponsedata
Addingacallbackargument
DeletingDatafromtheServer
UsingjQuery’s$.ajaxmethod
ReplacingDataStorewithRemoteDataStore
SilverChallenge:ValidatingAgainsttheRemoteServer
FortheMoreCurious:Postman
14.DeferredsandPromises
PromisesandDeferreds
ReturningDeferred
RegisteringCallbackswiththen
HandlingFailureswiththen
UsingDeferredswithCallback-OnlyAPIs
GivingDataStoreaPromise
CreatingandreturningPromises
ResolvingaPromise
Promise-ifyingtheotherDataStoremethods
SilverChallenge:FallbacktoDataStore
III.Real-TimeData
15.IntroductiontoNode.js
Nodeandnpm
npminit
npmscripts
Hello,World
AddingannpmScript
ServingfromFiles
Readingafilewiththefsmodule
WorkingwiththerequestURL
Usingthepathmodule
Creatingacustommodule
Usingyourcustommodule
ErrorHandling
FortheMoreCurious:npmModuleRegistry
BronzeChallenge:CreatingaCustomErrorPage
FortheMoreCurious:MIMETypes
SilverChallenge:ProvidingaMIMETypeDynamically
GoldChallenge:MovingErrorHandlingtoItsOwnModule
16.Real-TimeCommunicationwithWebSockets
SettingUpWebSockets
TestingYourWebSocketsServer
CreatingtheChatServerFunctionality
FirstChat!
FortheMoreCurious:socket.ioWebSocketsLibrary
FortheMoreCurious:WebSocketsasaService
BronzeChallenge:AmIRepeatingMyself?
SilverChallenge:Speakeasy
GoldChallenge:ChatBot
17.UsingES6withBabel
ToolsforCompilingJavaScript
TheChattrboxClientApplication
FirstStepswithBabel
Classsyntax
UsingBrowserifyforPackagingModules
Runningthebuildprocess
AddingtheChatMessageClass
Creatingthews-clientModule
Connectionhandling
Handlingeventsandsendingmessages
Sendingandechoingamessage
FortheMoreCurious:CompilingtoJavaScriptfromOtherLanguages
BronzeChallenge:DefaultImportName
SilverChallenge:ClosedConnectionAlert
FortheMoreCurious:Hoisting
FortheMoreCurious:ArrowFunctions
18.ES6,theAdventureContinues
InstallingjQueryasaNodeModule
CreatingtheChatFormClass
ConnectingChatFormtothesocket
CreatingtheChatListClass
UsingGravatars
PromptingforUsername
UserSessionStorage
FormattingandUpdatingMessageTimestamps
BronzeChallenge:AddingVisualEffectstoMessages
SilverChallenge:CachingMessages
GoldChallenge:SeparateChatRooms
IV.ApplicationArchitecture
19.IntroductiontoMVCandEmber
Tracker
Ember:AnMVCFramework
InstallingEmber
CreatinganEmberapplication
Startinguptheserver
ExternalLibrariesandAddons
Configuration
FortheMoreCurious:npmandBowerInstall
BronzeChallenge:LimitingImports
SilverChallenge:AddingFontAwesome
GoldChallenge:CustomizingtheNavBar
20.Routing,Routes,andModels
embergenerate
NestingRoutes
EmberInspector
AssigningModels
beforeModel
FortheMoreCurious:setupControllerandafterModel
21.ModelsandDataBinding
ModelDefinitions
createRecord
getandset
ComputedProperties
FortheMoreCurious:RetrievingData
FortheMoreCurious:SavingandDestroyingData
BronzeChallenge:ChangingtheComputedProperty
SilverChallenge:FlaggingNewSightings
GoldChallenge:AddingTitles
22.Data–Adapters,Serializers,andTransforms
Adapters
ContentSecurityPolicy
Serializers
Transforms
FortheMoreCurious:EmberCLIMirage
SilverChallenge:ContentSecurity
GoldChallenge:Mirage
23.ViewsandTemplates
Handlebars
Models
Helpers
Conditionals
Loopswith{{#each}}
Bindingelementattributes
Links
CustomHelpers
BronzeChallenge:AddingLinkRollovers
SilverChallenge:ChangingtheDateFormat
GoldChallenge:CreatingaCustomThumbnailHelper
24.Controllers
NewSightings
EditingaSighting
DeletingaSighting
RouteActions
BronzeChallenge:SightingDetailPage
SilverChallenge:SightingDate
GoldChallenge:AddingandRemovingWitnesses
25.Components
IteratorItemsasComponents
ComponentsforDRYCode
DataDown,ActionsUp
ClassNameBindings
DataDown
ActionsUp
BronzeChallenge:CustomizingtheAlertMessage
SilverChallenge:MakingtheNavBaraComponent
GoldChallenge:ArrayofAlerts
26.Afterword
TheFinalChallenge
ShamelessPlugs
ThankYou
Index
Introduction
LearningFront-EndWebDevelopment
Doingfront-endwebdevelopmentmayrequireashiftinperspective,asitisavery
differentanimalfromdevelopmentforotherplatforms.Hereareafewthingstokeepin
mindasyouarelearning.
Thebrowserisaplatform.
PerhapsyouhavedonenativedevelopmentforiOSorAndroid;writtenserver-sidecode
inRubyorPHP;orbuiltdesktopapplicationsforOSXorWindows.Asafront-end
developer,yourcodewilltargetthebrowser–aplatformavailableonnearlyeveryphone,
tablet,andpersonalcomputerintheworld.
Front-enddevelopmentrunsalongaspectrum.
Atoneendofthespectrumisthelookandfeelofawebpage:roundedcorners,shadows,
colors,fonts,whitespace,andsoon.Attheotherendofthespectrumisthelogicthat
governstheintricatebehaviorsofthatwebpage:swappingimagesinaninteractivephoto
gallery,validatingdataenteredintoaform,sendingmessagesacrossachatnetwork,etc.
Youwillneedtobecomeproficientwiththecoretechnologiesallalongthisspectrum,and
youwilloftenneedtousemultipletechnologiesinsynergytocreateagoodweb
application.
Webtechnologiesareopen.
Thereisnoonecompanythatcontrolshowbrowsersshouldwork.Thatmeansthatfront-
enddevelopersdonotgetayearlySDKreleasethatcontainsallthechangestheywill
needtodealwithforthenexttwelvemonths.Nativeplatformsareafrozenpondonwhich
youcancomfortablyskate.Thewebisariver;itcurves,movesquickly,andisrockyin
someplaces–butthatispartofitsappeal.Thewebisthemostrapidlyevolvingplatform
available.Adaptingtochangeisawayoflifeforafront-enddeveloper.
Thisbook’spurposeistoteachyouhowtodevelopforthebrowser.Asyoufollowthis
guide,youwillbetakenthroughtheprocessofbuildingaseriesofprojects.Eachproject
willcallforadifferentmixtureoftechnologiesalongthefront-endspectrum.Becauseof
thesheernumberoffront-endtools,libraries,andframeworksavailable,thisbookwill
focusonthemostessentialandportablepatternsandtechniques.
Prerequisites
Thisbookisnotanintroductiontoprogramming.Itassumesyouhaveexperiencewiththe
fundamentalsofwritingcode.Youareexpectedtobefamiliarwithbasictypes,functions,
andobjects.
Thatsaid,italsodoesnotassumeyoualreadyknowJavaScript.Itintroducesyouto
JavaScriptconceptsincontext,asyouneedthem.
HowThisBookIsOrganized
Thisbookwalksyouthroughwritingfourdifferentwebapplications.Eachapplicationhas
itsownsectionofthebook.Eachchapterinasectionaddsnewfeaturestotheapplication
youarebuilding.
Doingtheworkofbuildingthesefourapplicationstakesyoufromoneextremeofthe
front-endspectrumtotheother.
Ottergram Inyourfirstproject,youwillcreateaweb-basedphotogallery.Building
Ottergramwillteachyouthefundamentalsofprogrammingforthe
browserusingHTML,CSS,andJavaScript.Youwillbuildtheuser
interfacemanually,learninghowthebrowserloadsandrenderscontent.
CoffeeRun Partcoffeeorderform,partchecklist,CoffeeRuntakesyouthrougha
numberofJavaScripttechniquesincludingwritingmodularcode,taking
advantageofclosures,andcommunicatingwitharemoteserverusing
Ajax.YourfocuswillshiftfrommanuallycreatingtheUItocreatingand
manipulatingitprogrammatically.
Chattrbox Chattrboxhastheshortestsectionandisthemostdistinctoftheapps.You
willuseJavaScripttobuildachatsystem,writingachatserverwith
Node.jsaswellasabrowser-basedchatclient.
Tracker YourfinalprojectusesEmber.js,oneofthemostpowerfulframeworksfor
front-enddevelopment.Youwillcreateanapplicationthatcatalogs
sightingsofrare,exotic,andmythicalcreatures.Alongtheway,youwill
learnyourwayaroundtherichecosystemthatpowerstheEmber.js
framework.
Asyouworkthroughtheseapplications,youwillbeintroducedtoanumberoftools,
including:
theAtomtexteditorandsomeusefulplug-insforworkingwithcode
documentationresourcesliketheMozillaDeveloperNetwork
thecommandline,usingtheOSXTerminalapportheWindowscommandprompt
browser-sync
GoogleChrome’sDeveloperTools
normalize.css
Bootstrap
jQueryandlibrarieslikecrypto-jsandmoment
Node.js,theNodepackagemanager(npm),andnodemon
WebSocketsandthewscatmodule
Babel,Babelify,Browserify,andWatchify
Ember.jsandaddonslikeEmberCLI,EmberInspector,EmberCLIMirage,and
Handlebars
Bower
Homebrew
Watchman
HowtoUseThisBook
Thisbookisnotareferencebook.Itsgoalistogetyouovertheinitialhumptowhereyou
cangetthemostoutofthereferenceandrecipebooksavailable.Itisbasedonourfive-
dayclassatBigNerdRanch,and,assuch,itismeanttobeworkedthroughfromthe
beginning.Chaptersbuildoneachother,andskippingaroundwouldbeunproductive.
Inourclasses,studentsworkthroughthesematerials,buttheyalsobenefitfromtheright
environment–adedicatedclassroom,goodfoodandcomfortableboard,agroupof
motivatedpeers,andaninstructortoanswerquestions.
Asareader,youwantyourenvironmenttobesimilar.Thatmeansgettingagoodnight’s
restandfindingaquietplacetowork.Thesethingscanhelp,too:
Startareadinggroupwithyourfriendsorcoworkers.
Arrangetohaveblocksoffocusedtimetoworkonchapters.
Participateintheforumforthisbookatforums.bignerdranch.com,
whereyoucandiscussthebookandfinderrataandsolutions.
Findsomeonewhoknowsfront-endwebdevelopmenttohelpyouout.
Challenges
Mostchaptersinthisbookendwithatleastonechallenge.Challengesareopportunitiesto
reviewwhatyouhavelearnedandtakeyourworkinthechapteronestepfurther.We
recommendthatyoutackleasmanyofthemasyoucantocementyourknowledgeand
movefromlearningJavaScriptdevelopmentfromustodoingJavaScriptdevelopmenton
yourown.
Challengescomeinthreelevelsofdifficulty:
Bronzechallengestypicallyaskyoutodosomethingverysimilartowhatyoudid
inthechapter.Thesechallengesreinforcewhatyoulearnedinthechapterand
forceyoutotypeinsimilarcodewithouthavingitlaidoutinfrontofyou.
Practicemakesperfect.
Silverchallengesrequireyoutodomorediggingandmorethinking.Sometimes
youwillneedtousefunctions,events,markup,andstylesthatyouhavenotseen
before,butthetasksarestillsimilartowhatyoudidinthechapter.
Goldchallengesaredifficultandcantakehourstocomplete.Theyrequireyouto
understandtheconceptsfromthechapterandthendosomequalitythinkingand
problemsolvingonyourown.Tacklingthesechallengeswillprepareyouforthe
real-worldworkofJavaScriptdevelopment.
Youshouldmakeacopyofyourcodebeforeyouworkonthechallengesforanychapter.
Otherwise,thechangesthatyoumakemaynotbecompatiblewithsubsequentexercises.
Ifyougetlost,youcanalwaysvisitforums.bignerdranch.comforsome
assistance.
FortheMoreCurious
Manychaptersalsohave“FortheMoreCurious”sections.Thesesectionsofferdeeper
explanationsoradditionalinformationabouttopicspresentedinthechapter.The
informationinthesesectionsisnotabsolutelyessential,butwehopeyouwillfindit
interestinganduseful.
UsinganeBook
IfyouarereadingthisbookonaeReader,readingthecodemaybetrickyattimes.Longer
linesofcodemaywraptoasecondline,dependingonyourselectedfontsize.
Thelongestlinesofcodeinthisbookare86monospacecharacters,likethisone.
<linkhref="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">
YoucanplaywithyoureReaderssettingstofindthebestforviewinglongcodelines.
IfyouarereadingonaniPadwithiBooks,werecommendyougototheSettingsapp,
selectiBooks,andsetFullJustificationOFFandAuto-hyphenationOFF.
Whenyougettothepointwhereyouareactuallytypingincode,wesuggestopeningthe
bookonyourMac(orPC)inAdobeDigitalEditions.(AdobeDigitalEditionsisafree
eReaderapplicationyoucandownloadfromwww.adobe.com/products/
digitaleditions.)Maketheapplicationwindowlargeenoughsothatyoucansee
thecodewithnowrappinglines.Youwillalsobeabletoseethefiguresinfulldetail.
PartI
CoreBrowserProgramming
1
SettingUpYourDevelopment
Environment
Therearecountlesstoolsandresourcesforfront-enddevelopment,withmorebeingbuilt
allthetime.Choosingthebestonesischallengingfordevelopersofallskilllevels.
Throughouttheprojectsinthisbook,wewillguideyouintheuseofsomeofour
favorites.
Togetstarted,youwillneedthreebasictools:abrowser,atexteditor,andgoodreference
documentationforthemanytechnologiesusedinfront-enddevelopment.Also,thereare
severalextrasthat–whilenotessential–willmakeyourdevelopmentexperience
smootherandmoreenjoyable.
Forthepurposesofthisbookwerecommendthatyouusethesamesoftwareweusetoget
themostbenefitfromourdirectionsandscreenshots.Thischapterwalksyouthrough
installingandconfiguringtheGoogleChromebrowser,theAtomtexteditor,Node.js,anda
numberofplug-insandextras.Youwillalsofindoutaboutgooddocumentationoptions
andgetacrashcourseinusingthecommandlineonMacandWindows.Inthenext
chapter,youwillputalltheseresourcestouseasyoubeginyourfirstproject.
InstallingGoogleChrome
Yourcomputershouldalreadyhaveabrowserinstalledbydefault,butthebestonetouse
forfront-enddevelopmentisGoogleChrome.Ifyoudonotalreadyhavethelatestversionof
Chrome,youcangetitfromwww.google.com/chrome/browser/desktop
(Figure1.1).
Figure1.1DownloadingGoogleChrome
InstallingandConfiguringAtom
Ofthemanytexteditorprogramsoutthere,oneofthebestforfront-enddevelopmentis
theAtomeditorbyGitHub.Itisagoodchoicebecauseitishighlyconfigurable,hasmany
plug-instohelpwithwritingcode,andisfreetodownloadanduse.
YoucandownloadAtomforMacorWindowsfromatom.io(Figure1.2).
Figure1.2DownloadingAtom
Followtheinstallationinstructionsforyourplatform.AfterAtomisinstalled,thereare
severalplug-insyouwillwanttoinstallaswell.
Atomplug-ins
Theprimarythingsyouwantoutofyourtexteditoraredocumentationlookup,
autocompletion,codeformatting,andcodelinting(moreonthatinabit).Atomgivesyou
someofthesefeaturesbydefault,butinstallingafewplug-inswillmakeitevenbetter.
OpenAtomandrevealitsSettingsscreen.OnaMac,thisisdonebychoosingAtom→
Preferences…orusingthekeyboardshortcutCommand-,(thatis,theCommandkeyplus
thecomma).OnWindows,youcanaccessitviaFile→Settingsorusingthekeyboard
shortcutCtrl-,.
OnthelefthandsideoftheSettingsscreen,click+Install(Figure1.3).
Figure1.3Atom’sInstallPackagesscreen
Here,youcansearchforplug-inpackagesbyname.Beginbysearchingfor“emmet.”
WritingalotofHTMLcanbeverytediousandiserror-prone.Theemmetplug-in
(Figure1.4)letsyouwritewell-formattedHTMLusingaconvenientshorthand.Clickthe
Installbuttontogetemmet.
Figure1.4Installingemmet
Next,searchfor“atom-beautify.”Theatom-beautifyplug-in(Figure1.5)helpswiththe
indentationofyourcode,whichhelpswithreadability.Again,clickInstalltogetthisplug-
in.
Figure1.5Installingatom-beautify
Searchforandinstalltheautocomplete-pathsplug-in(Figure1.6).Veryoften,yourcodewill
needtorefertootherfilesandfoldersinyourproject.Thisplug-inhelpsbyoffering
filenamesinanautocompletemenuasyoutype.
Figure1.6Installingautocomplete-paths
Yournextplug-intoinstallistheapi-docspackage(Figure1.7),whichletsyoulookup
documentationbasedonkeyword.Itdisplaysthedocumentationinaseparatetabinthe
editor.
Figure1.7Installingapi-docs
Next,searchforandinstallthelinterpackage(Figure1.8).Alinterisaprogramthatchecks
thesyntaxandstyleofyourcode.Makesureyoufindandinstallthepackagethatisjust
named“linter.”Thisisabaselinterthatworkswithlanguage-specificplug-ins.Youwill
needitinordertousetheotherlinterplug-insbelow.
Figure1.8Installinglinter
TherearethreecompanionstolinterthatyouwillwanttoinstalltocheckyourCSS,
HTML,andJavaScriptcode.Startwithlinter-csslint(Figure1.9),whichensuresthatyour
CSSissyntacticallycorrectandalsoofferssuggestionsaboutwritingperformantCSS.
Figure1.9Installinglinter-csslint
Thenextlintercompanionplug-intoinstallislinter-htmlhint(Figure1.10),whichconfirms
thatyourHTMLiswellformed.ItwillwarnyouaboutmismatchedHTMLtags.
Figure1.10Installinglinter-htmlhint
Thelastlintercompanionplug-intoinstallislinter-eslint(Figure1.11).Thisplug-inchecks
thesyntaxofyourJavaScriptandcanbeconfiguredtocheckthestyleandformattingof
yourcode(forexample,howmanyspaceslinesareindentedorhowmanyblanklines
comebeforeandaftercomments).
Figure1.11Installinglinter-eslint
ChromeandAtomarenowreadyforfront-enddevelopment.Therearejustafewmoresteps
tocompletingyourcodingenvironment:accessingdocumentation,learningcommand-line
basics,anddownloadingtwofinaltools.
DocumentationandReferenceSources
Front-enddevelopmentisdifferentfromprogrammingforplatformslikeiOSand
Android.Asidefromtheobviousdifferences,front-endtechnologieshavenoofficial
developerdocumentationotherthanthetechnicalspecifications.Thismeansthatyouwill
needtolookelsewhereforguidance.Werecommendthatyoufamiliarizeyourselfwiththe
resourcesbelowandconsultthemregularlyasyouworkthroughthebookandcontinueon
withfront-enddevelopment.
TheMozillaDeveloperNetwork(MDN)isthebestreferenceforanythingtodowith
HTML,CSS,andJavaScript.Onewaytoaccessitisdevdocs.io,anexcellent
documentationinterface(Figure1.12).ItpullsdocumentationfromMDNforcorefront-
endtechnologies–anditcanworkoffline,soyoucancheckitevenwhenyoudonothave
aninternetconnection.
Figure1.12Accessingdocumentationviadevdocs.io
NotethatSafaricurrentlydoesnotsupporttheofflinecachingmechanismusedby
devdocs.io.Youwillneedtouseadifferentbrowser,suchasChrome,toaccessit.
YoucanalsouseMDN’swebsite,developer.mozilla.org/en-US(Figure1.13),
orsimplyadd“MDN”asasearchenginekeywordtofindtheinformationyouneed.
Figure1.13TheMozillaDeveloperNetworkwebsite
Anothersitetoknowaboutisstackoverflow.com(Figure1.14).Officially,thisis
notasourceofdocumentation.Itisaplacewheredeveloperscanaskeachotherabout
code.Theanswersvaryinquality,butareoftenverythoroughandquitehelpful.Soitisa
usefulresource–aslongasyoubearinmindthattheanswersarenotdefinitive,duetoits
crowdsourcednature.
Figure1.14TheStackOverflowwebsite
Webtechnologiesarealwayschanging.SupportforfeaturesandAPIswillvaryfrom
browsertobrowserandovertime.Twowebsitesthatcanhelpyoudeterminewhich
browsers(andwhichversionsofindividualbrowsers)supportwhatfeaturesare
html5please.comandcaniuse.com.Whenyouneedinformationaboutfeature
support,wesuggeststartingwithhtml5please.comtoknowwhetherafeatureis
recommendedforuse.Formoredetailedinformationaboutwhichbrowserversions
supportaspecificfeature,gotocaniuse.com.
CrashCourseintheCommandLine
Throughoutthisbook,youwillbeinstructedtousethecommandlineorterminal.Many
ofthetoolsyouwillbeusingrunexclusivelyascommand-lineprograms.
ToaccessthecommandlineonaMac,openFinderandgototheApplicationsfolder,thenthe
Utilitiesfolder.FindandopentheprogramnamedTerminal(Figure1.15).
Figure1.15FindingtheTerminalapponaMac
YoushouldseeawindowthatlookslikeFigure1.16.
Figure1.16Maccommandline
ToaccessthecommandlineonWindows,gototheStartmenuandsearchfor“cmd.”Find
andopentheprogramnamedCommandPrompt(Figure1.17).
Figure1.17FindingtheCommandPromptprogramonWindows
ClickittorunthestandardWindowscommand-lineinterface,whichlookslike
Figure1.18.
Figure1.18Windowscommandline
Fromnowon,wewillreferto“theterminal”or“thecommandline”tomeanboththeMac
TerminalandtheWindowsCommandPrompt.Ifyouareunfamiliarwithusingthecommand
line,hereisashortwalkthroughofsomecommontasks.Allcommandsareenteredby
typingatthepromptandpressingtheReturnkey.
Findingoutwhatdirectoryyouarein
Thecommandlineislocationbased.Thatmeansthatatanygiventimeitis“in”a
particulardirectorywithinthefilestructure,andanycommandsyouenterwillbeapplied
withinthatdirectory.Thecommand-linepromptshowsanabbreviatedversionofthe
directoryitisin.ToseethewholepathonaMac,enterthecommandpwd(whichstands
for“printworkingdirectory”),asinFigure1.19.
Figure1.19ShowingthecurrentpathusingpwdonaMac
OnWindows,usethecommandecho%cd%toseethepath,asinFigure1.20.
Figure1.20Showingthecurrentpathusingecho%cd%onWindows
Creatingadirectory
Thedirectorystructureoffront-endprojectsisimportant.Yourprojectscangrowquickly,
anditisbesttokeepthemorganizedfromthebeginning.Youwillcreatenewdirectories
regularlyduringyourdevelopment.Thisisdoneusingthemkdiror“makedirectory”
commandfollowedbythenameofthenewdirectory.
Toseethiscommandinaction,setupadirectoryfortheprojectsyouwillbuildasyou
workthroughthisbook.Enterthiscommand:
mkdirfront-end-dev-book
Next,createanewdirectoryforyourfirstproject,Ottergram,whichyouwillbegininthe
nextchapter.Youwantthisnewdirectorytobeasubdirectoryofthefront-end-dev-
bookdirectoryyoujustcreated.Youcandothisfromyourhomedirectorybyprefacing
thenewdirectorynamewiththenameoftheprojectsdirectoryand,onaMac,aslash:
mkdirfront-end-dev-book/ottergram
OnWindows,youusethebackslashinstead:
mkdirfront-end-dev-book\ottergram
Changingdirectories
Tomovearoundthefilestructure,youusethecommandcd,or“changedirectory,”
followedbythepathofthedirectoryyouwanttomoveinto.
Youdonotalwaysneedtousethecompletedirectorypathinyourcdcommand.For
example,tomovedownintoanysubdirectoryofthedirectoryyouarein,yousimplyuse
thenameofthesubdirectory.Sowhenyouareinthefront-end-dev-bookdirectory,
thepathoftheottergramfolderisjustottergram.
Moveintoyournewprojectdirectory:
cdfront-end-dev-book
Now,youcanmoveintotheottergramdirectory:
cdottergram
Tomoveuptotheparentdirectory,usethecommandcd..(thatis,cdfollowedbya
spaceandtwoperiods).Thepairofperiodsrepresentsthepathoftheparentdirectory.
cd..
Rememberthatyoucancheckyourcurrentdirectorybyusingthepwdcommand(orecho
%cd%onWindows).Figure1.21showstheauthorcreatingdirectories,movingbetween
them,andcheckingthecurrentdirectory.
Figure1.21Changingandcheckingdirectories
Youarenotlimitedtomovingupordownonedirectoryatatime.Let’ssaythatyouhada
morecomplexdirectorystructure,liketheoneshowninFigure1.22.
Figure1.22Anexamplefilestructure
Supposeyouareintheottergramdirectoryandyouwanttogodirectlytothe
stylesheetsdirectoryinsideofcoffeerun.Youwoulddothiswithcdfollowedby
apaththatmeans“thestylesheetsdirectoryinsidethecoffeerundirectoryinside
theparentdirectoryofwhereIamnow”:
cd../coffeerun/stylesheets
OnWindows,youwouldusethesamecommandbutwithbackslashes:
cd..\coffeerun\stylesheets
Listingfilesinadirectory
Youmayneedtoseealistoffilesinyourcurrentdirectory.OnaMac,youusethels
commandforthat(Figure1.23).Ifyouwanttolistthefilesinanotherdirectory,youcan
supplyapath:
ls
lsottergram
Figure1.23Usinglstolistfilesinadirectory
Bydefault,lswillnotprintanythingifadirectoryisempty.
OnWindows,thecommandisdir(Figure1.24),whichyoucanoptionallygiveapath:
dir
dirottergram
Figure1.24Usingdirtolistfilesinadirectory
Bydefault,thedircommandwillprintinformationaboutdates,times,andfilesizes.
Gettingadministratorprivileges
OnsomeversionsofOSXandWindows,youwillneedsuperuseroradministrator
privilegesinordertorunsomecommands,suchascommandsthatinstallsoftwareor
makechangestoprotectedfiles.
OnaMac,youcangiveyourselfprivilegesbyprefixingacommandwithsudo.Thefirst
timeyouusesudoonaMac,itwillgiveyouasternwarning,showninFigure1.25.
Figure1.25sudowarning
sudowillpromptyouforyourpasswordbeforeitrunsthecommandasthesuperuser.As
youtype,yourkeystrokeswillnotbeechoedback,sotypecarefully.
OnWindows,ifyouneedtogiveyourselfprivilegesyoudosointheprocessofopening
thecommand-lineinterface.FindthecommandpromptintheWindowsStartMenu,right-
clickit,andchooseRunasAdministrator(Figure1.26).Anycommandsyouruninthis
commandpromptwillberunasthesuperuser,sobecareful.
Figure1.26Openingthecommandpromptasanadministrator
Quittingaprogram
Asyouproceedthroughthebook,youwillrunmanyappsfromthecommandline.Some
ofthemwilldotheirjobandquitautomatically,butotherswillrununtilyoustopthem.To
quitacommand-lineprogram,pressControl-C.
InstallingNode.jsandbrowser-sync
Thereisonefinalset-upstepbeforeyoubeginyourfirstproject.
Node.js(orsimply“Node”)letsyouuseprogramswritteninJavaScriptfromthecommand
line.Mostfront-enddevelopmenttoolsarewrittenforusewithNode.js.Youwilllearnlots
moreaboutNode.jsinChapter15,butyouwillbeginusingonetoolthatdependsonit,
browser-sync,rightaway.
InstallNodebydownloadingtheinstallerfromnodejs.org(Figure1.27).Theversion
ofNode.jsusedinthisbookis5.11.1,andyouwilllikelyseeadifferentversionavailable
fordownload.
Figure1.27DownloadingNode.js
Double-clicktheinstallerandfollowtheprompts.
WhenyouinstallNode,itprovidestwocommand-lineprograms:nodeandnpm.Thenode
programdoestheworkofrunningprogramswritteninJavaScript.Youwillnotneedto
useituntilChapter15.TheotherprogramistheNodepackagemanager,npm,whichis
neededforinstallingopen-sourcedevelopmenttoolsfromtheinternet.
browser-syncisonesuchtool,anditwillbeinvaluabletoyouthroughoutthebook.It
makesyourexamplecodeeasiertoruninthebrowserandautomaticallyreloadsthe
browserwhenyousavechangestoyourcode.
Installbrowser-syncusingthiscommandatthecommandline:
npminstall-gbrowser-sync
(The-ginthecommandstandsfor“global.”Installingthepackagegloballymeansthat
youwillbeabletorunbrowser-syncfromanydirectory.)
Itdoesnotmatterwhatdirectoryyouareinwhenyourunthiscommand,butyouwill
probablyneedsuperuserprivileges.Ifthatisthecase,runthecommandusingsudoona
Mac:
sudonpminstall-gbrowser-sync
IfyouareonWindows,firstopenacommandpromptastheadministrator,asshown
above.
Whenyoustartbrowser-sync,asyouwillinthenextchapter,itwillrununtilyoupress
Control-C.Itisagoodideatoquitbrowser-syncwhenyouaredoneworkingonaproject
forawhile.Thatmeansthatyouwillneedtostartbrowser-synceachtimeyoubegin
workonthefirsttwoprojectsinthisbook(OttergramandCoffeeRun).
Withthat,youhavethetoolsyouneedtogetstartedonyourOttergramproject!
FortheMoreCurious:AlternativestoAtom
Therearemany,manytexteditorstochoosefrom.IfyouarenotthatkeenonAtom,when
youaredoneworkingthroughtheprojectsinthisbookyoumaywanttotryoutoneofthe
followingtwooptions.BothareavailableforfreeforMacandWindows,andbothhavea
largenumberofplug-instocustomizeyourdevelopmentexperience.Also,likeAtom,both
arebuiltusingHTML,CSS,andJavaScript,butrunasdesktopapplications.
VisualStudioCodeisMicrosoft’sopensourcetexteditor,madespecificallyfordeveloping
webapplications.Itcanbedownloadedfromcode.visualstudio.com
(Figure1.28).
Figure1.28TheVisualStudioCodewebsite
Adobe’sBracketstexteditorisparticularlygoodforbuildinguserinterfaceswithHTML
andCSS.Infact,itprovidesanextensionforhelpingyouworkwithAdobe’slayeredPSD
imagefiles.Bracketsisavailablefrombrackets.io(Figure1.29).
Figure1.29TheAdobeBracketswebsite
2
SettingUpYourFirstProject
Whenyouvisitawebsite,yourbrowserhasaconversationwithaserver,another
computerontheinternet.
Browser:“Heythere!CanIpleasehavethecontentsofthefilenamedcat-
videos.html?”
Server:“Certainly.Letmetakealookaround…hereitis!”
Browser:“Ah,it’stellingmethatIneedanotherfilenamedstyles.css.”
Server:“Surething.Letmetakealookaround…hereitis!”
Browser:“OK,thatfilesaysthatIneedanotherfilenamedanimated-
background.gif.”
Server:“Noproblem.Letmetakealookaround…hereitis!”
Thatconversationgoesonforsometime,sometimeslastingthousandsofmilliseconds
(Figure2.1).
Figure2.1Thebrowsersendsarequest,theserverresponds
Itisthebrowsersjobtosendrequeststotheserver;interprettheHTML,CSS,and
JavaScriptitreceivesintheresponsefromtheserver;andpresenttheresulttotheuser.
Eachofthesethreetechnologiesplaysapartintheusersexperienceofawebsite.Ifyour
appwerealivingcreature,theHTMLwouldbeitsskeletonandorgans(themechanics),
theCSSwouldbeitsskin(thevisiblelayer),andtheJavaScriptwouldbeitspersonality
(howitbehaves).
Inthischapter,youaregoingtosetupthebasicHTMLforyourfirstproject,Ottergram.
Inthenextchapter,youwillsetupyourCSS,whichyouwillrefineinChapter4.In
Chapter6,youwillbeginaddingJavaScript.
SettingUpOttergram
InChapter1,youcreatedafolderfortheprojectsinthisbookaswellasafolderfor
Ottergram.StartyourAtomtexteditorandopentheottergramfolderbyclickingFile→
Open(orFile→OpenFolder…onWindows).Inthedialogbox,navigatetothefront-
end-dev-bookfolderandchoosetheottergramfolder.ClickOpentotellAtomtouse
thisfolder(Figure2.2).
Figure2.2OpeningyourprojectfolderinAtom
YouwillseetheottergramfolderinthelefthandpanelofAtom.Thispanelisfor
navigatingamongthefilesandfoldersinyourproject.
Youaregoingtocreatesomefilesandfolderswithintheottergramprojectfolderusing
Atom.Control-click(right-click)ottergraminthelefthandpanelandclickNewFileinthe
pop-upmenu.Youwillbepromptedforanameforthenewfile.Enterindex.htmland
presstheReturnkey(Figure2.3).
Figure2.3CreatinganewfileinAtom
YoucanusethesameprocesstocreatefoldersusingAtom.Control-click(right-click)
ottergraminthelefthandpanelagain,butthistimeclickNewFolderinthepop-up.Enter
thenamestylesheetsinthepromptthatappears(Figure2.4).
Figure2.4CreatinganewfolderinAtom
Finally,createafilenamedstyles.cssinthestylesheetsfolder:Control-click
(right-click)stylesheetsinthelefthandpanelandchooseNewFile.Thepromptwill
pre-fillthetext“stylesheets/”.Afterthis,enterstyles.cssandpresstheReturnkey
(Figure2.5).
Figure2.5CreatinganewCSSfileinAtom
Whenyouarefinished,yourprojectfoldershouldlooklikeFigure2.6.
Figure2.6InitialfilesandfoldersforOttergram
Therearenorulesabouthowtostructureyourfilesandfoldersorwhattonamethem.
However,Ottergram(liketheotherprojectsinthisbook)followsconventionsusedby
manyfront-enddevelopers.Yourindex.htmlfilewillholdyourHTMLcode.Naming
themainHTMLfileindex.htmldatesbacktotheearlydaysoftheweb,andthe
conventioncontinuestoday.
Thestylesheetsfolder,asthenamesuggests,willholdoneormorefileswithstyling
informationforOttergram.ThesewillbeCSS,or“cascadingstylesheets,”files.
SometimesdevelopersgivetheirCSSfilesnamesthatdescribewhatpartofthepageor
sitetheypertainto,suchasheader.cssorblog.css.Ottergramisasimpleproject
andonlyneedsoneCSSfile,soyouhavenameditstyles.csstoreflectitsglobal
role.
InitialHTML
Timetogetcoding.Openindex.htmlinAtomandaddsomebasicHTMLtogetstarted.
Startbytypinghtml.Atomwillofferyouanautocompleteoption,asshowninFigure2.7.
(Ifitdoesnot,makesureyouinstalledtheemmetplug-inasdirectedinChapter1.)
Figure2.7Atom’sautocompletemenu
PresstheReturnkey,andAtomwillprovidebare-bonesHTMLelementstogetyoustarted
(Figure2.8).
Figure2.8HTMLcreatedusingautocomplete
Yourcursorisbetween<title>and</title>–theopeningandclosingtitletags.Type
“ottergram”togivetheprojectaname.Now,clicktoputyourcursorintheblankline
betweentheopeningandclosingbodytags.There,type“header”andpresstheReturnkey.
Atomwillconvertthetext“header”intoopeningandclosingheadertagswithablankline
betweenthem(Figure2.9).
Figure2.9Headertagcreatedwithautocomplete
Next,type“h1”andpressReturn.Again,yourtextisconvertedintotags,thistimewithout
ablankline.Enterthetext“ottergram”again.Thiswillbetheheadingthatwillappearon
yourwebpage.
Yourfileshouldlooklikethis:
<!doctypehtml>
<html>
<head>
<metacharset="utf-8">
<title>ottergram</title>
</head>
<body>
<header>
<h1>ottergram</h1>
</header>
</body>
</html>
Atomandemmethavetogethersavedyousometypingandhelpedyoubuildwell-formed
initialHTML.
Let’sexamineyourcode.Thefirstline,<!doctypehtml>,definesthedoctype–ittells
thebrowserwhichversionofHTMLthedocumentiswrittenin.Thebrowsermayrender,
ordraw,thepagealittledifferentlybasedthedoctype.Here,thedoctypespecifies
HTML5.
EarlierversionsofHTMLoftenhadlong,convoluted,andhardtorememberdoctypes,
suchas:
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Often,folkshadtolookupthedoctypeeachtimetheycreatedanewdocument.
WithHTML5,thedoctypeisshortandsweet.Itistheonethatwillbeusedthroughoutall
oftheprojectsinthisbook,andyoushoulduseitforyourapps.
AfterthedoctypeissomebasicHTMLmarkupconsistingofaheadandabody.
Theheadwillholdinformationaboutthedocumentandhowthebrowsershouldhandle
thedocument.Forexample,thetitleofthedocument,whatCSSorJavaScriptfilesthe
pageuses,andwhenthedocumentwaslastmodifiedareallincludedinthehead.
Here,theheadcontainsa<meta>tag.<meta>tagsprovidethebrowserwithinformation
aboutthedocumentitself,suchasthenameofthedocument’sauthororkeywordsfor
searchengines.The<meta>taginOttergram,<metacharset="utf-8">,specifiesthatthe
documentisencodedusingtheUTF-8characterset,whichencompassesallUnicode
characters.Usethistaginyourdocumentssothatthewidestrangeofbrowserscan
interpretthemcorrectly,especiallyifyouexpectinternationaltraffic.
ThebodywillholdalloftheHTMLcodethatrepresentsthecontentofyourpage:allthe
images,links,text,buttons,andvideosthatwillappearonthepage.
Mosttagsenclosesomeothercontent.Takealookattheh1headingyouincluded;its
anatomyisshowninFigure2.10.
Figure2.10AnatomyofasimpleHTMLtag
HTMLstandsfor“hypertextmarkuplanguage.”Tagsareusedto“markup”yourcontent,
designatingtheirpurpose–suchasheadings,listitems,andlinks.
ThecontentenclosedbyasetoftagscanalsoincludeotherHTML.Notice,forexample,
thatthe<header>tagsenclosethe<h1>tagshownabove(andthe<body>tagsenclosethe
<header>!).
Therearealotoftagstochoosefrom–morethan140.Toseealistofthem,visitMDN’s
HTMLelementreference,locatedatdeveloper.mozilla.org/en-US/docs/
Web/HTML/Element.Thisreferenceincludesabriefdescriptionofeachelementand
groupselementsbyusage(e.g.,textcontent,contentsectioning,ormultimedia).
Linkingastylesheet
InChapter3,youwillwritestylingrulesinyourstylesheet,styles.css.Butremember
theconversationbetweenthebrowserandtheserveratthebeginningofthischapter?The
browseronlyknowstoaskforafilefromtheserverifithasbeentoldthatthefileexists.
Youhavetolinktoyourstylesheetsothatthebrowserknowstoaskforit.Updatethe
headofindex.htmlwithalinktoyourstyles.cssfile.
<!doctypehtml>
<html>
<head>
<metacharset="utf-8">
<title>ottergram</title>
<linkrel="stylesheet"href="stylesheets/styles.css">
</head>
<body>
...
The<link>tagishowyouattachanexternalstylesheettoanHTMLdocument.Ithastwo
attributes,whichgivethebrowsermoreinformationaboutthetag’spurpose(Figure2.11).
(TheorderofHTMLattributesdoesnotmatter.)
Figure2.11Anatomyofatagwithattributes
Yousettherel(or“relationship”)attributeto"stylesheet",whichletsthebrowser
knowthatthelinkeddocumentprovidesstylinginformation.Thehrefattributetellsthe
browsertosendarequesttotheserverforthestyles.cssfilelocatedinthestylesheets
folder.Notethatthisfilepathisrelativetothecurrentdocument.
Saveindex.htmlbeforeyoumoveon.
Addingcontent
Awebpagewithoutcontentislikeadaywithoutcoffee.Addalistafteryourheaderto
giveyourprojectareasonforliving.
Youaregoingtoaddanunorderedlist(thatis,abulletedlist)usingthe<ul>tag.Inthe
list,youwillincludefivelistitemsusing<li>tags,andineachlistitemyouwillinclude
sometextsurroundedby<span>tags.
Theupdatedindex.htmlisshownbelow.Notethatthroughoutthisbookweshownew
codethatyouareaddinginboldtype.Codethatyouaretodeleteisshownstruckthrough.
Existingcodeisshowninplaintexttohelpyoupositionyourchangeswithinthefile.
WeencourageyoutomakeuseofAtomsautocompletionandautoformattingfeatures.
Withyourcursorinposition,type“ul”andpressReturn.Next,type“li”andpressReturn
twice,thentype“span”andpressReturnonce.Enterthenameofanotter,thencreatefour
morelistitemsandspansinthesameway.
<!doctypehtml>
<html>
<head>
<metacharset="utf-8">
<title>ottergram</title>
<linkrel="stylesheet"href="stylesheets/styles.css">
</head>
<body>
<header>
<h1>ottergram</h1>
</header>
<ul>
<li>
<span>Barry</span>
</li>
<li>
<span>Robin</span>
</li>
<li>
<span>Maurice</span>
</li>
<li>
<span>Lesley</span>
</li>
<li>
<span>Barbara</span>
</li>
</ul>
</body>
</html>
The<span>tagsnestedinsideeach<li>tagdonothaveanyspecialmeaning.Theyare
genericcontainersforothercontent.YouwillbeusingtheminOttergramforstyling
purposes,andyouwillseeotherexamplesofcontainerelementsasyoucontinuethrough
thisbook.
Next,youwilladdimagesofotterstogowiththenamesyouhaveentered.
Addingimages
Theresourcefilesforalltheprojectsinthisbookareatwww.bignerdranch.com/
downloads/front-end-dev-resources.zip.TheyincludefiveCreative
Commons-licensedotterimagestakenbyMichaelL.Baird,JoeRobertson,andAgunther
thatwerefoundoncommons.wikimedia.org.
Downloadandunziptheresources.Insidetheottergram-resourcesfolder,locate
theimgfolder.Copytheimgfoldertoyourottergram/projectdirectory.(The.zip
containsotherresources,butfornowyouwillonlyneedtheimgfolder.)
Youwantyourlisttoincludeclickablethumbnailimagesinadditiontothetitles.Youwill
achievethisbyaddinganchorandimagetagstoeachiteminyourul.Wewillexplain
thesechangesinmoredetailafteryouenterthem.(Ifyouuseautocompletion,notethat
youwillneedtomovethe</a>tagssothattheyfollowthespans.)
...
<ul>
<li>
<ahref="#">
<imgsrc="img/otter1.jpg"alt="BarrytheOtter">
<span>Barry</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter2.jpg"alt="RobintheOtter">
<span>Robin</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter3.jpg"alt="MauricetheOtter">
<span>Maurice</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter4.jpg"alt="LesleytheOtter">
<span>Lesley</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter5.jpg"alt="BarbaratheOtter">
<span>Barbara</span>
</a>
</li>
</ul>
...
Ifyourlinesarenotnicelyindented,youcantakeadvantageoftheatom-beautifyplug-inthat
youinstalled.ClickPackages→AtomBeautify→Beautifyandyourcodewillbealignedand
indentedforyou.
Let’slookatwhatyouhaveadded.
The<a>tagistheanchortag.Anchortagsmakeelementsonthepageclickable,sothat
theytaketheusertoanotherpage.Theyarecommonlyreferredtoas“links,”butbeware:
Theyarenotlikethe<link>tagyouusedearlier.
Anchortagshaveanhrefattribute,whichindicatestheresourcetheanchorpointsto.
Usuallythevalueisawebaddress.Sometimes,though,youdonotwantalinktogo
anywhere.Thatisthecasefornow,soyouassignedthe“dummy”value#tothehref
attributes.Thiswillmakethebrowserscrolltothetopofthepagewhentheimageis
clicked.Lateryouwillusetheanchortagstoopenalargercopyofanimagewhenthe
thumbnailisclicked.
Insidetheanchortagsyouadded<img>,orimage,tagswithsrcattributesindicating
filenamesintheimgdirectoryyouaddedearlier.Youalsoaddedadescriptivealt
attributetoyourimagetags.altattributescontaintextthatreplacestheimageifitis
unabletoload.alttextisalsowhatscreenreadersusetodescribeanimagetoauserwith
avisualimpairment.
Imagetagsaredifferentfrommostotherelementsinthattheydonotwrapotherelements,
butinsteadrefertoaresource.Whenthebrowserencountersan<img>tag,itdrawsthe
imagetothepage.Thisisknownasareplacedelement.Otherreplacedelementsinclude
embeddeddocumentsandapplets.
Becausetheydonotwrapcontentorotherelements,<img>tagsdonothavea
correspondingclosingtag.Thismakesthemself-closingtags(alsoknownasvoidtags).
Youwillsometimesseeself-closingtagswrittenwithaslashbeforetherightangle-
bracket,like<imgsrc="otter.jpg"/>.Whethertoincludetheslashisamatterof
preferenceanddoesnotmakeadifferencetothebrowser.Inthisbook,self-closingtags
arewrittenwithouttheslash.
Saveindex.html.Inamoment,youwillseetheresultsofyourcoding.
ViewingtheWebPageintheBrowser
Toviewyourwebpage,youneedtoberunningthebrowser-synctoolthatyouinstalled
inChapter1.
Opentheterminalandchangedirectorytoyourottergramfolder.Recallfrom
Chapter1thatyouchangedirectoryusingthecdcommandfollowedbythepathofthe
folderyouaremovinginto.OneeasywaytogettheottergrampathistoControl-click
(right-click)theottergramfolderinAtomslefthandpanelandchooseCopyFullPath
(Figure2.12).Then,atthecommandline,typecd,pastethepath,andpressReturn.
Figure2.12CopyingtheottergramfolderpathfromAtom
Thepathyouentermightlooksomethinglikethis:
cd/Users/chrisaquino/Projects/front-end-dev-book/ottergram
Onceyouareintheottergramdirectory,runthefollowingcommandtoopen
OttergraminChrome.(Wehavebrokenthecommandacrosstwolinessothatitfitsonthe
page.Youshouldenteritonasingleline.)
browser-syncstart--server--browser"GoogleChrome"
--files"stylesheets/*.css,*.html"
IfChromeisyourdefaultbrowser,youcanleaveoutthe--browser"GoogleChrome"
portionofthecommand:
browser-syncstart--server--files"stylesheets/*.css,*.html"
Thiscommandstartsbrowser-syncinservermode,allowingittosendresponseswhena
browsersendsarequesttogetafile,suchastheindex.htmlfileyoucreated.
Thecommandyouenteredalsotellsbrowser-synctoautomaticallyreloadthebrowserif
anyHTMLorCSSfilesarechanged.Thismakesthedevelopmentexperiencemuchnicer.
Beforetoolslikebrowser-sync,youhadtomanuallyreloadthepageaftereverychange.
Figure2.13showstheresultofenteringthiscommandonaMac.
Figure2.13Startingbrowser-syncintheOSXTerminal
YoushouldseethesameoutputonWindows(Figure2.14).
Figure2.14Startingbrowser-syncintheWindowsCommandPrompt
OncetheOttergrampagehasloadedinChrome,youshouldseeyourpagewiththe
“ottergram”heading,“ottergram”asthetablabel,andaseriesofotterphotosandnames
(Figure2.15).
Figure2.15ViewingOttergraminthebrowser
TheChromeDeveloperTools
Chromehasbuilt-inDeveloperTools(commonlyknownas“DevTools”)thatareamongthe
bestavailablefortestingstyles,layouts,andmoreonthefly.UsingtheDevToolsismuch
moreefficientthantryingthingsoutincode.TheDevToolsareverypowerfulandwillbe
yourconstantcompanionasyoudofront-enddevelopment.
YouwillstartusingtheDevToolsinthenextchapter.Fornow,openthewindowand
familiarizeyourselfwithitsmajorareas.
ToopentheDevTools,clickthe icontotherightoftheaddressbarinChrome.Next,
clickMoreTools→DeveloperTools(Figure2.16).
Figure2.16OpeningtheDeveloperTools
ChromedisplaystheDevToolstotherightbydefault.Yourscreenwilllooksomethinglike
Figure2.17.
Figure2.17TheDevToolsshowingtheelementspanel
TheDevToolsshowtherelationshipbetweenthecodeandtheresultingpageelements.
Theyletyouinspectindividualelements’attributesandstylesandseeimmediatelyhow
thebrowserisinterpretingyourcode.Seeingthisrelationshipiscriticalforboth
developmentanddebugging.
InFigure2.17,youcanseetheDevToolsnexttothewebpage,displayingtheelements
panel.Theelementspanelisdividedintotwosections.OntheleftistheDOMtreeview.
ThisisarepresentationoftheHTML,interpretedasDOMelements.(Youwilllearnmuch
moreaboutDOM,whichstandsfor“documentobjectmodel,”inupcomingchapters.)On
therighthandsideoftheelementspanelisthestylespane.Thisshowsanyvisualstyles
appliedtoindividualelements.
HavingtheDevToolsdockedontherightsideofthescreenwhileyouareworkingis
usuallyconvenient.IfyouwanttochangethelocationoftheDevTools,youcanclickthe
buttonneartheupper-rightcorner.Thiswillshowyouamenuofoptions,including
buttonsfortheDockside,whichwillchangetheanchorlocationoftheDevTools
(Figure2.18).
Figure2.18ChangingthedocksideoftheDevTools
WithyourottersandmarkupinplaceandtheDevToolsopen,youarereadytobegin
stylingyourprojectinthenextchapter.
FortheMoreCurious:CSSVersions
TheversionhistoryofCSSincludesstandardversions1,2,and2.1.After2.1,itwas
decidedthatthestandardneededtobebrokenupbecauseitwasgettingtoobig.
Thereisnoversion3.Instead,CSS3isablankettermforanumberofmodules,eachwith
itsownversionnumber.
Table2.1CSSversions,realandimagined
Version
Number
Release
Year NotableFeatures
1 1996 Basicfontproperties(font-family,font-style),foregroundand
backgroundcolors,textalignment,margin,border,andpadding.
2 1998 Absolute,relative,andfixedpositioning;newfontproperties.
2.1 2011 Removedfeaturesthatwerepoorlysupportedbybrowsers.
“3” Various Acollectionofdifferentspecifications,suchasmediaqueries,new
selectors,semi-transparentcolors,@font-face.
FortheMoreCurious:Thefavicon.ico
Haveyouevernoticedthelittleiconthatappearsattheleftendofyourbrowsersaddress
barwhenyouvisitmostwebsites?Sometimestheyalsoappearinyourbrowsertab,asin
Figure2.19.
Figure2.19Thebignerdranch.comfavicon.ico
Thatisthefavicon.icoimagefile.Manysiteshaveone,andbrowsersrequestoneby
default.BecauseOttergramdoesnothaveone,youmayseeanerrorliketheonein
Figure2.20intheDevTools.
Figure2.20Erroraboutmissingfavicon.ico
Donotworryaboutthiserrorifitappears.Itwillnotaffectyourproject.However,you
caneasilyaddafavicon.icoimage–andthatisyourfirstchallenge.
SilverChallenge:Addingafavicon.ico
Youhavedecidedthatyoulikeottersmorethanyoulikeseeingthefavicon.icoerror
message.Youaregoingtocreateafavicon.icofileusingoneoftheotterimages.
Doawebsearchfor“favicongenerator”andyoushouldseealistofwebsitesthatwilldo
afileconversionforyou.Mostwillletyouuploadanimageandthenprovideyouwitha
favicon.icoversion.
Chooseoneanduploadanyoneoftheotterimages.
Savetheresultingfavicon.icofileinthesamefolderasyourindex.htmlfile.
Finally,reloadyourbrowser.YourbrowsertabwilllooksomethinglikeFigure2.21.
Figure2.21Ottergramwithafavicon.ico
3
Styles
Inthischapter,youwilldesignastaticversionofOttergram.Inthechaptersthatfollow,
youwillmakeOttergraminteractive.
Whenyoureachtheendofthischapter,yourwebsitewilllooklikeFigure3.1.
Figure3.1Ottergram:stylish
Thischapterintroducesanumberofconceptsandexamples.Donotworryifyoudonot
feelthatyouhavemasteredallofthemwhenyougettotheend.Youwillbeencountering
themagainandagainasyouprogressthroughthisbook,andyourworkinthischapterwill
provideasolidfoundationonwhichyouwillbuildtrueunderstanding.
Ofcourse,wecanonlyintroduceyoutoatinyfractionofallthestylesthatareavailablein
CSS.YouwillwanttoconsulttheMDNforinformationaboutthefullsetofproperties
andtheirvalues.
Front-enddevelopershavetochoosebetweentwoapproachestostylingawebsite:start
withtheoveralllayoutandworkdowntothesmallestdetails,orstartwiththesmallest
detailsandworkuptotheoveralllayout.
Notonlydoesworkingfromdetailtobigpictureproducecleaner,morereusablecode,it
alsohasacoolname:atomicstyling.Youwillusethisapproachasyoustyletheotter
thumbnailsfirst,thenthethumbnaillistlayout.Inthenextchapter,youwillworkonthe
layoutofthesiteasawhole.
CreatingaStylingBaseline
Youaregoingtobeginbyaddingthenormalize.cssfiletoyourproject.
normalize.csshelpstheCSSyouwritedisplayconsistentlyacrossbrowsers.All
browserscomewithasetofdefaultstyles,butthedefaultsaredifferentfrombrowserto
browser.normalize.cssgivesyouagoodstartingpointfordevelopingyourown
customCSSforawebsiteorwebapp.
normalize.cssisfreelyavailableonline.Youdonotneedtodownloadit.Toadditto
Ottergram,youonlyneedtolinktoitinindex.html.
Toensurethatyouareusingthemostcurrentversionofnormalize.css,youare
goingtogetitsaddressfromacontentsharingsite.Gotocdnjs.com/libraries/
normalizeandfindtheversionofthefileendingwith.min.css.(Thisversionisa
smallerdownloadthantheothers,withtheextrawhitespacestrippedout.)ClicktheCopy
buttontocopyitsaddress(Figure3.2).
Figure3.2Gettingalinktonormalize.cssfromcdnjs.com
Thecurrentversionatthetimeofthiswritingis3.0.3,buttheversionyouusemaybe
morerecent.
OpenyourOttergramfolderinAtom,thenopenindex.html.Addanew<link>tagand
pasteintheaddress.(Inthecodebelow,the<link>hasbeenbrokenintotwolinestofit
onthepage.Youcanleaveyoursonasingleline.)
<!doctypehtml>
<html>
<head>
<metacharset="utf-8">
<title>ottergram</title>
<linkrel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">
<linkrel="stylesheet"href="stylesheets/styles.css">
</head>
...
Makesurethatyouaddthe<link>tagfornormalize.cssbeforethe<link>tagfor
styles.css.Thebrowserneedstoreadthestylesfoundinnormalize.cssbeforeit
readsyours.
And,justlikethat,yourprojectcantakeadvantageofthisusefultool.Noothersetupis
required.
Youmaybewonderingwhyyouarelinkingtoanaddressonacompletelydifferentserver.
Infact,itisnotunusualforanHTMLfiletospecifyresourceslocatedondifferentservers
(Figure3.3).
Figure3.3Requestingresourcesfromdifferentservers
Inthiscase,normalize.cssishostedoncdnjs.com,apublicserverthatispartofa
contentdeliverynetwork,orCDN.CDNshaveserversallaroundtheworld,eachwith
copiesofthesamefiles.Whenusersrequestafile,theyreceiveitfromaservernearby,
cuttingdownontheloadtimeforthatfile.cdnjs.comhostsmanyversionsofpopular
front-endlibrariesandframeworks.
PreparingtheHTMLforStyling
Inthelastchapter,youcreatedastylesheetcalledstyles.css,andinthischapteryou
willaddanumberofCSSstylingrulestoit.Butbeforeyougetstartedaddingstyles,you
needtosetupyourHTMLwithtargetsforyourstylingrulestoreferto.
Youaregoingtoaddclassattributesidentifyingthespanelementswiththeotters’names
as“thumbnailtitles.”classattributesareawaytoidentifyagroupofHTMLelements,
usuallyforstyling.Your“thumbnailtitle”classwillallowyoutoeasilystyleallthe
namesatonce.
Inindex.html,addtheclassnamethumbnail-titleasanattributeofthespansinside
thelielements,asshown:
...
<ul>
<li>
<ahref="#">
<imgsrc="img/otter1.jpg"alt="BarrytheOtter">
<span>Barry</span>
<spanclass="thumbnail-title">Barry</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter2.jpg"alt="RobintheOtter">
<span>Robin</span>
<spanclass="thumbnail-title">Robin</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter1.jpg"alt="MauricetheOtter">
<span>Maurice</span>
<spanclass="thumbnail-title">Maurice</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter4.jpg"alt="LesleytheOtter">
<span>Lesley</span>
<spanclass="thumbnail-title">Lesley</span>
</a>
</li>
<li>
<ahref="#">
<imgsrc="img/otter5.jpg"alt="BarbaratheOtter">
<span>Barbara</span>
<spanclass="thumbnail-title">Barbara</span>
</a>
</ul>
...
Inamoment,youwillusethisclassnametostylealltheimagetitles.
AnatomyofaStyle
Whenyoucreateindividualstyles,youdosobywritingstylingrules,whichconsistoftwo
mainparts:selectorsanddeclarations(Figure3.4).
Figure3.4Anatomyofastylingrule
Thefirstpartofastylingruleisoneormoreselectors.Selectorsdescribetheelementsthat
thestyleshouldbeappliedto,likeh1,span,orimg.Butselectorsarenotlimitedtotag
names.Youcanwriteselectorsthatapplytoamoretargetedsetofelementsbyincreasing
theselectorsspecificity.
Forexample,youcanwriteselectorsbasedonattributes–suchasthethumbnail-title
classattributeyoujustaddedtothe<span>tags.Selectorsbasedonattributesaremore
specificthanselectorsbasedonelementnames.
Inadditiontomakingsurethatstylesareonlyappliedtoalimitedsetofelements(e.g.,
elementswiththeclassnamethumbnail-titleversusall<span>elements),specificity
alsodeterminestheselectorsrelativepriority.Ifastylesheetcontainsmultiplestylesthat
couldapplytothesameelement,thestyleswithaselectorofhigherspecificitywillbe
usedinsteadstyleswhoseselectorhasalowerspecificity.Youcanreadmoreabout
specificityinaFortheMoreCurioussectionattheendofthischapter.
Throughoutthischapter,youwillbeintroducedtoanumberofdifferentkindsofselectors
thatvaryintheirspecificity.Thoughthereareoftenmanywaystotargetthesameelement
forstyling,understandingspecificityiskeytochoosingthebestselectortousesothat
yourstylesaremaintainable.
Thesecondpartofastylingruleisthedeclarationblock,wrappedincurlybraces,which
definesthestylestobeapplied.Theindividualdeclarationswithintheblockeachinclude
apropertynameandavalueforthatproperty.
Inyourfirststylingrule,youwillusetheclassattributeyoujustaddedasaselectorto
applystylesaroundtheotters’names.
YourFirstStylingRule
Touseaclassasaselectorinastylingrule,youprefixtheclassnamewithadot(period),
asin.thumbnail-title.Thefirststylesyouaregoingtoaddwillsetthebackgroundand
foregroundcolorsforthe.thumbnail-titleclass.
Openstyles.cssandaddyourstylingrule:
.thumbnail-title{
background:rgb(96,125,139);
color:rgb(202,238,255);
}
Youwilllearnmoreaboutcolorlaterinthischapter.Fornow,justtakealookatyour
changes.Savestyles.cssandmakesurebrowser-syncisrunning.Ifyouneedto
restartit,thecommandis:
browser-syncstart--server--browser"GoogleChrome"
--files"stylesheets/*.css,*.html"
ThiswillopenyourwebpageinChrome(Figure3.5).
Figure3.5AslightlymorecolorfulOttergram
Youcanseethatyouhavesetthebackgroundforthethumbnailtitlestoadeepgray-blue
andthefontcolortoalighterblue.Nice.
Continuestylingthethumbnailtitles:Returntostyles.cssandaddtoyourexisting
stylingruleforthe.thumbnail-titleclass,asshown:
.thumbnail-title{
display:block;
margin:0;
padding:4px10px;
background:rgb(96,125,139);
color:rgb(202,238,255);
}
Thethreedeclarationsyouhaveaddedallaffectanelement’sbox.ForeveryHTMLtag
thathasavisualrepresentation,thebrowserdrawsarectangletothepage.Thebrowser
usesaschemecalledthestandardboxmodel(orjust“boxmodel”)todeterminethe
dimensionsofthatrectangle.
Theboxmodel
Tounderstandtheboxmodel,youaregoingtolookatitsrepresentationintheDevTools.
Savestyles.css,switchtoChrome,andmakesuretheDevToolsareopen(Figure3.6).
Figure3.6Exploringtheboxmodel
Clickthe buttonintheupper-leftoftheelementspanel.ThisistheInspectElement
button.Nowmoveyourcursorovertheword“ottergram”onthewebpage.Asyouhover
overtheword,theDevToolssurroundstheheadingwithablue-andpeach-colored
rectangle(Figure3.7).
Figure3.7Hoveringovertheheading
Clicktheword“ottergram”onthewebpage.Althoughyounolongerseethemulticolored
overlay,theelementisnowselectedandtheDOMtreeviewintheelementspanelwill
expandtoshowandhighlightthecorresponding<h1>tag.
Therectangulardiagraminthelower-rightoftheelementspanelrepresentstheboxmodel
fortheh1element.Youcanseethattheregionsofthediagramhavesomeofthesame
colorsastherectangleyousawoverlayingtheheadingwhenyouinspectedit(Figure3.8).
Figure3.8Viewingtheboxmodelforanelement
Theboxmodelincorporatesfouraspectsoftherectangledrawnforanelement(whichthe
DevToolsrendersinfourdifferentcolorsinthediagram).
content(showninblue)
thevisualcontent–here,thetext
padding(showningreen)
transparentspacearoundthecontent
border(showninyellow)
aborder,whichcanbemadevisible,aroundthecontentandpadding
margin(showninpeach)
transparentspacearoundtheborder
ThenumbersinFigure3.8arepixelvalues;apixelisaunitcorrespondingtothesmallest
rectangularareaofacomputerscreenthatcandisplayasinglecolor.Inthecaseoftheh1
element,thecontentareahasbeenallocatedanareaof197pixelsby54pixels(your
valuesmaybedifferent,dependingonthesizeofyourbrowserwindow).Thereispadding
of40pixelsontheleftside.Theborderissetat0,andthereisamarginof16pixelsabove
andbelowtheelement.
Wheredidthatmarginvaluecomefrom?Eachbrowserprovidesadefaultstylesheet,
calledtheuseragentstylesheet,incaseanHTMLfiledoesnotspecifyone.Stylesthat
youspecifyoverridethedefaults.Becauseyouhavenotspecifiedvaluesfortheh1
element’sbox,thedefaultstyleshavebeenapplied.
Nowyouarereadytounderstandthestylingdeclarationsyouadded:
.thumbnail-title{
display:block;
margin:0;
padding:4px10px;
background:rgb(96,125,139);
color:rgb(202,238,255);
}
Thedisplay:blockdeclarationchangestheboxforallelementsoftheclass
.thumbnail-titlesothattheyoccupytheentirewidthallowedbytheircontaining
element.(NoticeinFigure3.6thatthebackgroundcolorforthetitlesnowcoversawider
area.)Otherdisplayvalues,suchasthedisplay:inlinepropertyyouwillseelater,
makeanelement’swidthfittoitscontent.
Youalsosetthemarginforthethumbnailtitlesto0andthepaddingtotwodifferent
values:4pxand10px(pxistheabbreviationfor“pixels”).Thissetsthepaddingtospecific
pixelvalues,overridingthedefaultsizesetbytheuseragentstylesheet.
Padding,margin,andcertainotherstylescanbewrittenasshorthandproperties,inwhich
onevalueisappliedtomultipleproperties.Youaretakingadvantageofthishere:When
twovaluesareprovidedforthepadding,thefirstisappliedtobothverticalvalues(topand
bottom)andthesecondisappliedtobothhorizontalvalues(leftandright).Itisalso
possibletoprovideasinglevaluetobeappliedtoallfoursidesortospecifyaseparate
valueforeachside.
Tosumup,yournewdeclarationssaythattheboxforallelementsofthe.thumbnail-
titleclasswillfillthewidthofitscontainerwithnomarginandwithpaddingthatis4
pixelsatthetopandbottomand10pixelsattheleftandrightsides.
StyleInheritance
Next,youaregoingtoaddstylestochangethesizeandappearanceofthetext.
Addanewstylingruleinstyles.csstosetthefontsizeforthebodyelement.Todo
this,youwilluseadifferenttypeofselector–anelementselector–bysimplyusingthe
element’sname.
body{
font-size:10px;
}
.thumbnail-title{
display:block;
margin:0;
padding:4px10px;
background:rgb(96,125,139);
color:rgb(202,238,255);
}
Thisstylingrulesetsthebodyelement’sfont-sizeto10px.
Youwillrarelyuseelementselectorsinyourstylesheets,becauseyouwillnotoftenwant
toapplytheexactsamestylestoeveryoccurrenceofaparticulartag.Also,element
selectorslimityourabilitytoreusestyles;usingthemmeansthatyoumayendupretyping
thesamedeclarationsthroughoutyourstylesheets.Thisisnotgreatformaintenanceifyou
needtoalterthosestyles.
But,inthiscase,targetingthebodyelementisexactlytherightamountofspecificity.
Therecanbeonlyone<body>element,andyouwillnotbereusingitsstyles.
Savestyles.cssandcheckoutyourwebpageinChrome(Figure3.9).
Figure3.9Aftersettingthebodyfontsize
Yourheadlineandthumbnailtitleshavegottensmaller.Youmay–ormaynot–have
expectedthis.Whiletheheadlineisdirectlywithinthebodyelementwhereyoudeclared
thefont-sizeproperty,thethumbnailtitlesarenot.Theyarenestedseverallevelsdeep.
However,manystyles,includingfontsize,areappliedtotheelementsspecifiedbythe
stylingruleaswellasthedescendantsofthoseelements.
Thestructureofyourdocumentcanbedescribedusingatreediagram,asinFigure3.10.
RepresentingyourelementsasatreeisagoodwaytovisualizetheDOM.
Figure3.10SimplifiedstructureofOttergram
Anelementcontainedwithinanotherelementissaidtobeitsdescendent.Inthiscase,
yourspansarealldescendentsofthebody(aswellastheulandtheirrespectiveli),so
theyinheritthebodysfont-sizestyle.
IntheDevTools’DOMtreeview,locateandselectoneofthespanelements.Inthestyles
pane,noticetheboxeslabeledInheritedfroma,Inheritedfromli,andInheritedfromul.Thesethree
areas,asindicated,showstylesinheritedateachlevelfromtheuseragentstylesheet.
UnderInheritedfrombody,youcanseethatthefont-sizepropertyhasbeeninheritedfrom
thestylesetforthebodyelementinstyles.css(Figure3.11).
Figure3.11Stylesinheritedfromancestorelements
Whatifadifferentfontsizeweresetatanotherlevel,suchastheul?Stylesfromthe
closerancestortakepriority,soafontsizesetinstyles.cssfortheulwouldoverride
onesetforthebodyandafontsizesetforthespanelementitselfwouldoverridethem
both.
Toseethis,clickontheulelementintheDOMtreeview.Thiswillallowyoutotryout
stylesonthefly.Thestylesyouaddherewillbeimmediatelyreflectedinthewebpage
view,butwillnotbeaddedtoyouractualprojectfiles.
Atthetopofthestylespaneintheelementspanel,youwillseeasectionlabeled
elements.style.Clickanywhereinbetweenthecurlybracesoftheelements.style,and
theDevToolswillgiveyouaprompt(Figure3.12).
Figure3.12Promptingforastylerule
Starttypingfont-size,andtheDevToolswillsuggestpossiblecompletions(Figure3.13).
Figure3.13Autocompletionoptionsinstylespane
Choosefont-size,thenpresstheTabkey.Enteralargevalue,suchas50px,andpress
Return.Youmayneedtoscrollthepage,butyouwillseethattheulsfont-sizehas
overriddenthebodys(Figure3.14).
Figure3.14Givingtheulafont-sizeof50px
Notallstylepropertiesareinherited–border,forexample,isnot.Tofindoutwhethera
propertyisinherited,refertotheproperty’sMDNreferencepage.
Backinstyles.css,updateyourdeclarationblockforthe.thumbnail-titleclassto
overridethebodysfont-sizeandusealargerfont.
body{
font-size:10px;
}
.thumbnail-title{
display:block;
margin:0;
padding:4px10px;
background:rgb(96,125,139);
color:rgb(202,238,255);
font-size:18px;
}
Forelementsoftheclass.thumbnail-title,youchangedthefontsizeto18pixels.
Savestyles.cssandadmireyourthumbnailtitlesinChrome(Figure3.15).
Figure3.15Styledthumbnailtitles
Theylookgood,buttheuseragentstylesheetisaddingunderlinestothe.thumbnail-
titleelements.Thisisbecauseyouwrappedthem(alongwiththe.thumbnail-image
elements)withananchortag,makingtheminherittheunderlinestyle.
Youdonotneedtheunderlines,soyouaregoingtoremovethembychangingthetext-
decorationpropertyfortheanchortagsinanewstylingruleinstyles.css.What
selectorshouldyouuseforthisrule?
Ifyouareconfidentthatyouwanttoremovetheunderlinesfromthethumbnailtitlesas
wellasanyotheranchorelementsinOttergram,youcansimplyuseanelementselector:
a{
/*styledeclaration*/
}
(Thetextbetweenthe/**/indicatorsisaCSScomment.Codecommentsareignoredby
thebrowser;theyallowthedevelopertomakenotesinthecodeforfuturereference.)
Ifyouthinkyoumightuseanchorsforanotherpurpose(andwillwanttostylethem
differently),youcanpairtheelementselectorwithanattributeselector,likethis:
a[href]{
/*styledeclaration*/
}
Thisselectorwouldmatchanyanchorelementwithanhrefattribute.Ofcourse,anchor
elementsgenerallydohavehrefattributes,sothatmightnotbetargetedenoughtomatch
onlythethumbnailimagesandtitles.Tomakeanattributeselectormoreprecise,youcan
alsospecifythevalueoftheattribute,likethis:
a[href="#"]{
/*styledeclaration*/
}
Thisselectorwouldmatchonlythoseanchorelementswhosehrefattributehasavalueof
#.
Bytheway,youcanalsouseattributeselectors,withorwithoutvalues,ontheirown,such
as:
[href]{
/*styledeclaration*/
}
Asithappens,Ottergramisafairlysimpleprojectandyouwillnot,infact,beusing
anchortagsforanythingotherthanthethumbnailsandtheirtitles.Itisthereforesafeto
useanelementselector,andyoushoulddosobecauseitisthemoststraightforward
solutionwiththerightamountofspecificity.
Addthenewstyledeclarationtostyles.css:
body{
font-size:10px;
}
a{
text-decoration:none;
}
.thumbnail-title{
...
}
Saveyourfileandcheckyourbrowser.Theunderlinesaregoneandyourthumbnailtitles
arenicelystyled(Figure3.16).
Figure3.16Aftersettingtext-decorationtonone
Notethatyoushouldnotremovetheunderlinesfromlinksthatareinnormaltext–text
thatisnotanobviousheading,title,orcaption.Theunderliningoflinkedtextisan
importantvisualindicatorthatusershavecometoexpect.Youdiditherebecausethe
thumbnailsdonotrequirethesamevisualcues.Userswillreasonablyexpectthemtobe
clickable.
Intherestofthechapter,youwilluseclassselectorstostylethethumbnailimages,the
unorderedlistofimages,thelistitems(whichincludethethumbnailimagesandtheir
titles),and,finally,theheader.Goaheadandaddclassnamestotheh1,ul,li,andimg
elementsinindex.htmlsotheyarereadyasyouneedthem.
...
</head>
<body>
<header>
<h1>ottergram</h1>
<h1class="logo-text">ottergram</h1>
</header>
<ul>
<ulclass="thumbnail-list">
<li>
<liclass="thumbnail-item">
<ahref="#">
<imgsrc="img/otter1.jpg"alt="BarrytheOtter">
<imgclass="thumbnail-image"src="img/otter1.jpg"alt="BarrytheOtter">
<spanclass="thumbnail-title">Barry</span>
</a>
</li>
<li>
<liclass="thumbnail-item">
<ahref="#">
<imgsrc="img/otter2.jpg"alt="RobintheOtter">
<imgclass="thumbnail-image"src="img/otter2.jpg"alt="RobintheOtter">
<spanclass="thumbnail-title">Robin</span>
</a>
</li>
<li>
<liclass="thumbnail-item">
<ahref="#">
<imgsrc="img/otter3.jpg"alt="MauricetheOtter">
<imgclass="thumbnail-image"src="img/otter3.jpg"alt="MauricetheOtter">
<spanclass="thumbnail-title">Maurice</span>
</a>
</li>
<li>
<liclass="thumbnail-item">
<ahref="#">
<imgsrc="img/otter4.jpg"alt="LesleytheOtter">
<imgclass="thumbnail-image"src="img/otter4.jpg"alt="LesleytheOtter">
<spanclass="thumbnail-title">Lesley</span>
</a>
</li>
<li>
<liclass="thumbnail-item">
<ahref="#">
<imgsrc="img/otter5.jpg"alt="BarbaratheOtter">
<imgclass="thumbnail-image"src="img/otter5.jpg"alt="BarbaratheOtter">
<spanclass="thumbnail-title">Barbara</span>
</a>
</li>
</ul>
...
Byaddingclassnamestotheseelements,youhavegivenyourselftargetsforthestyles
youwillbeadding.
Wefavorclassselectorsoverotherkindsofselectors,andyoushould,too.Youcanwrite
verydescriptiveclassnamesthatmakeyourcodeeasytodevelopandmaintain.Also,you
canaddmultipleclassnamestoanelement,makingthemaflexibleandpowerfultoolfor
styling.
Besuretosaveindex.htmlbeforemovingon.
MakingImagesFittheWindow
Followingtheatomicstylingpattern,theimagesarenextinlineforstyling.Theyareso
largethattheyarecutoffunlessthebrowserwindowisalsolarge.Addastylingrulefor
.thumbnail-imageinstyles.csstomakethethumbnailsfitinthewindow:
...
a{
text-decoration:none;
}
.thumbnail-image{
width:100%;
}
.thumbnail-title{
...
}
Yousetthewidthto100%,whichconstrainsittothewidthofitscontainer.Thismeans
thatasyouwidenthebrowserwindow,theimagesgetproportionallylarger.Checkitout:
Savestyles.css,switchtoyourbrowser,andmakeyourbrowserwindowlargerand
smaller.Theimagesgrowandshrinkalongwiththebrowserwindow,alwayskeeping
theirproportions.Figure3.17showsOttergraminonenarrowandonewiderbrowser
window.
Figure3.17Fittinganimagebywidth
Ifyoulookclosely,thespacingaroundthe.thumbnail-titlesisoff,sothatitappears
thatthetitlesgowiththeimagesbelowthem.Fixthatinstyles.cssbysettingthe
.thumbnail-imagesdisplaypropertytoblock.
...
.thumbnail-image{
display:block;
width:100%;
}
...
Nowthespacebetweentheimageanditstitleisgone(Figure3.18).
Figure3.18Aftersetting.thumbnail-imagetodisplay:block
Whydoesthiswork?Imagesaredisplay:inlinebydefault.Theyaresubjecttosimilar
renderingrulesastext.Whentextisrendered,thelettersaredrawnalongacommon
baseline.Somecharacters,suchasp,q,andy,haveadescender-thetailthatdrops
belowthisbaseline.Toaccommodatethem,thereissomewhitespaceincludedbelowthe
baseline.
Settingthedisplaypropertytoblockremovesthewhitespacebecausethereisnoneedto
accommodateanytext(oranyotherdisplay:inlineelementsthatmightberendered
alongsidetheimage).
Color
Itistimetoexplorecoloralittlemoredeeply.Addthefollowingcolorstylesforthebody
elementandthe.thumbnail-itemclassinstyles.css.
body{
font-size:10px;
background:rgb(149,194,215);
}
a{
text-decoration:none;
}
.thumbnail-item{
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
}
...
Youhavedeclaredvaluesforthe.thumbnail-itemsbordertwice.Why?Noticethatthe
twodeclarationsuseslightlydifferentcolorfunctions:rgbandrgba.Thergbacolor
functionacceptsafourthargument,whichistheopacity.However,somebrowsersdonot
supportrgba,soprovidingbothdeclarationsisatechniquethatprovidesafallbackvalue.
Allbrowserswillseethefirstdeclaration(rgb)andregisteritsvaluefortheborder
property.Whenbrowsersthatdonotsupportrgbaseetheseconddeclaration,theywillnot
understanditandwillsimplyignoreit,usingthevaluefromthefirstdeclaration.Browsers
thatdosupportrgbawillusethevalueintheseconddeclarationanddiscardthevalue
fromthefirstdeclaration.
(Wonderingwhythebodysbackgroundcolorisdefinedwithintegersandthe
.thumbnail-itemsbordercolorisdefinedwithpercentages?Wewillcomebacktothatin
justamoment.)
Savestyles.cssandswitchtoyourbrowser(Figure3.19).
Figure3.19Backgroundcolorandborders
IntheDevTools,youcanseethatChromesupportsrgba.Itdenotesthatthergbcolorisnot
usedbystrikingthroughthestyle(Figure3.20)
Figure3.20rgbaisusedwhensupportedbybrowser
Now,stillintheDevTools,selectthebody.Inthestylespane,noticethedeclarationfor
thebackgroundcolorthatyoujustadded.TotheleftoftheRGBvalueisasmallsquare
showingyouwhatthecolorwilllooklike.
Clickthatsquare,andacolorpickeropens(Figure3.21).Thecolorpickerletsyouchoose
acolorandwillgiveyoutheCSScolorvalueinavarietyofdifferentformats.
Figure3.21Thecolorpickerinthestylespane
Toseethebackgroundcolorindifferentcolorformats,clicktheupanddownarrowsto
therightoftheRGBAvalues.YoucancyclethroughHSLA,HEX,andRGBAformats.
TheHSLAformat(whichstandsfor“huesaturationlightnessalpha”)isusedless
frequentlythantheothers,partlybecausesomeofthemostpopulardesigntoolsdonot
provideHSLAvaluesthatareaccurateforCSS.IfyouarecuriousaboutHSLA,visitthe
HSLAExploreratcss-tricks.com/examples/HSLaExplorer.
TakealookattheHEXvalueforthebackgroundcolor:#95C2D7.HEX,orhexadecimal,is
theoldestcolorspecificationformat.Eachdigitrepresentsavaluefrom0to15.(Ifyou
arenotfamiliarwithhexadecimalnumbers,thisisdonebyincludingthecharactersA
throughFasdigits.)Eachpairofdigits,then,canrepresentavaluefrom0to255.From
lefttoright,thepairsofdigitscorrespondtotheintensityofred,green,andblueinthe
colorbeingspecified(Figure3.22).
Figure3.22HEXvaluescorrespondtored,green,andbluevalues
ManyfindHEXcolorsunintuitive.AmodernalternativeistouseRGB(red,green,and
blue)values.Inthismodel,eachcolorisalsoassignedavaluefrom0to255,butthe
valuesarerepresentedinmorefamiliardecimalnumbersandseparatedbycolor.As
mentionedearlier,formorecapablebrowsersafourthvaluecanspecifytheopacityor
transparencyofthespecifiedcolor,from0.0(fullytransparent)to1.0(fullyopaque).The
opacityisofficiallyknownasthealphavalue–hencetheAinRGBA.TheRGBAvalue
ofthebodysbackgroundcoloris(149,194,215,1).
Asanalternativetodeclaringintegervaluesforred,green,andblue,youcanalsouse
percentages,asyoudidforthe.thumbnail-itemborders.Thereisnofunctional
differencebetweenthetwooptions.Justdonotmixpercentagesandintegersinthesame
declaration.
Bytheway,forhelpselectingpleasingcolorpalettes,Adobeprovidesafreeonlinetoolat
color.adobe.com.
AdjustingtheSpaceBetweenItems
Ottergramnowhassomenicecolorsreminiscentofotters’oceanhome.Butaddingthe
colorshasrevealedsomeunwantedwhitespaceinsidetheborderofthe.thumbnail-item
elements.Also,thosepeskybulletsaredrawingattentionawayfromthegloryofthe
otters.
Togetridofthebullets,setthe.thumbnail-listslist-stylepropertytononein
styles.css:
...
.thumbnail-item{
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
}
.thumbnail-list{
list-style:none;
}
.thumbnail-image{
...
Togetridofthewhitespace,youwillusethesametechniqueyouusedwiththe
.thumbnail-image.Each.thumbnail-itemhasthatwhitespacebydefaultto
accommodateitemsinalist,justasthe.thumbnail-imageelementshadwhitespaceto
accommodateneighboringtext.Addadisplay:blockdeclarationfor.thumbnail-item
toremoveit.
...
.thumbnail-item{
display:block;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
}
...
Withthoseadditions,thebulletsandtheexcessspaceabovetheimagesdisappear,
resultinginthemorepolishedlayoutshowninFigure3.23.
Figure3.23Improvedlayout
Whyuseabulletlistifyoudonotwantbullets?ItisbesttochooseHTMLtagsbasedon
whattheyareandnothowthebrowserwillstylethembydefault.Inthiscase,youwant
anunorderedlistofimages,soaulisthewaytogo.Theulcontainerforyourimages
willletyoustylethemasascrollinglistwhenyouaddadetailimagetoyourprojectin
Chapter4.Thefactthatthebrowserrepresentsulswithbulletsbydefaultisnot
important,astheyareeasilyremoved.
Next,youaregoingtoadjustthespacingoftheitemsinthelist.Theindividual
.thumbnail-itemelementscurrentlyhavenospacebetweenthem.Youaregoingtoadd
marginsbetweenadjacentthumbnails.
However,youdonotwanttoaddamargintoallofthelistitems.Whynot?Becausethe
headingalreadyhasamargin,sothefirstlistitemdoesnotneedone.Thismeansthatyou
cannotusethe.thumbnail-itemclassselector,atleastnotonitsown.Instead,youwill
useselectorsyntaxthattargetselementsbasedontheirrelationshiptootherelements.
Relationshipselectors
LookagainatthediagramofyourprojectinFigure3.10.Itlooksmuchlikeafamilytree,
doesn’tit?Thissimilaritygivesthesetofrelationshipselectorstheirnames:descendent
selectors,childselectors,siblingselectors,andadjacentsiblingselectors.
Relationshipselectorsyntaxincludestwoselectors(likeclassorelementselectors)joined
byasymbolcalledacombinatorthatdeterminesthetargetedrelationshipbetweenthem.
Tounderstandhowrelationshipselectorswork,itisimportanttokeepinmindthatthe
browserreadsselectorsyntaxfromrighttoleft.Let’slookatsomeexamples.
Adescendentselectortargetsanyelementofonespecifiedtypethatisthedescendentof
anotherspecifiedelement.Forexample,toselectanyspanelementthatisthedescendent
ofthebodyelement,thesyntaxwouldbe:
bodyspan{
/*styledeclarations*/
}
Thissyntaxusesnocombinator.Becauseitisreadfromrighttoleft,ittargetsanyspan
descendedfromabody,whichinthecurrentcodemeansthethumbnailtitles.Itwould
alsoaffectanyspansthatmightbeaddedwithintheheaderorelsewherewithinthebody.
Notethatyoucanalsouseaclassselector(orattributeselector,orindeedanytypeof
selector)withinarelationshipselector,sotheselectorabovecouldalsobewrittenas:
body.thumbnail-title{
/*styledeclarations*/
}
Childselectorstargetelementsofaspecifiedtypethataretheimmediatechildrenof
anotherspecifiedelement.Childselectorsyntaxusesthecombinator>.Tousechild
selectorsyntaxtotargetallthespanscurrentlyinOttergram,thesyntaxwouldbe:
li>span{
/*styledeclarations*/
}
Readingfromrighttoleft,thisselectortargetsanyspanthatistheimmediatechildofali
element–again,thethumbnailtitles.
Siblingselectorsyntaxusesthecombinator~.Asyoumightexpect,thissyntaxtargets
elementswiththesameparent.However,becauseofthedirectionalnatureofrelationship
selectors,theresultsmightnotbeexactlyasyouexpect.Takethisexample:
header~ul{
/*styledeclarations*/
}
Thisselectortargetsanyulthatisprecededbyaheaderwiththesameparentelement.
ThisselectorwouldeffectivelytargetOttergram’sul,becauseithasasiblingheaderthat
precedesitinthecode.However,reversingthesyntax(ul~header)wouldresultinno
elementsbeingselected,becausethereisnoheaderprecededbyasiblingul.
Thefinalrelationshipselectortypeistheadjacentsiblingselector,whichtargetselements
thatareimmediatelyprecededbyasiblingofthespecifiedtype.Theadjacentsibling
combinatoris+:
li+li{
/*styledeclarations*/
}
Thissyntaxwouldselectalllielementsimmediatelyprecededbyasiblingli.Theresult
isthatthedeclaredstyleswouldbeappliedtothesecondthroughfifthli–butnotthe
first,becauseitisnotimmediatelyprecededbyanotherli.(Notethatthegeneralsibling
selectorandtheadjacentsiblingselectorwouldworkthesamewayatthemoment,dueto
Ottergram’srelativelysimplestructure.)
Backtothetaskathand:addingamargintothetopofeachlistitemexceptthefirst.If
youusedadescendentorchildselectortotargetthe.thumbnail-itemclassorthespanor
lielements,themarginwouldbeappliedtoallfivethumbnails.Becauseyouwantto
styleallbutthefirst,usetheadjacentsiblingsyntaxinstyles.csstoaddatopmargin
toonlythosethumbnailsthatareimmediatelyprecededbyanotherthumbnail.
...
a{
text-decoration:none;
}
.thumbnail-item+.thumbnail-item{
margin-top:10px;
}
.thumbnail-item{
...
Saveyourfileandcheckouttheresultsinyourbrowser(Figure3.24).
Figure3.24Spacingbetweenadjacent.thumbnail-itemelements
NotethattheDevToolsgiveyouaneasywaytofindoutthenestingpathofanelement,
whichcanhelpwithwritingrelationshipselectors.Ifyouclickoneofthespanelements
insideoneofthelielements,youcanseeitspathatthebottomoftheelementspanel
(Figure3.25).
Figure3.25Nestingpathshownbytheelementspanel
Foronefinaltweaktothethumbnaillist’sappearance,returntostyles.cssand
overridethepaddingthattheulinheritsfromtheuseragentstylesheetsothattheimages
arenolongerindented.
...
.thumbnail-list{
list-style:none;
padding:0;
}
...
Asusual,saveyourfileandswitchtoyourbrowsertoseeyourresults(Figure3.26).
Figure3.26ulwithpaddingremoved
Ottergramisstartingtolookpolished.Withsomestylingfortheheader,youwillhavea
nicestaticwebpage.
AddingaFont
Earlier,youaddedthe.logo-textclasstotheh1element.Usethatclassastheselector
foranewstylingruleinstyles.css.Insertitafterthestylesfortheanchortag.(In
general,theorderofyourstylesonlymatterswhenyouhavemultiplerulesetsforthe
sameselector.InOttergram,thestylesarearrangedinroughlythesameorderasthey
appearinthecode.Thisisamatterofpreference,andyouarefreetoorganizeyourstyles
asyouseefit.)
...
a{
text-decoration:none;
}
.logo-text{
background:white;
text-align:center;
text-transform:uppercase;
font-size:37px;
}
.thumbnail-item+.thumbnail-item{
...
First,yougavetheheaderawhitebackground.Thenyoucenteredthetextinsidethe
.logo-textelementandusedthetext-transformpropertytoformatitasuppercase.
Finally,yousetthefontsize.YourresultswilllooklikeFigure3.27.
Figure3.27Stylingtheheader
Ottergramlooksgreat.Great…butalittleplainforawebsitewithotters.Toaddsome
pizzazz,youcanuseafontfortheheaderotherthanthedefaultprovidedbytheuseragent
stylesheet.
Weincludedsomefontsintheresourcefilesyoualreadydownloadedandaddedtoyour
projectdirectory.Tousethem,youneedtocopythefontsfolderintoyourproject.Place
itinsideyourstylesheetsfolder(Figure3.28).
Figure3.28fontsfolderinsidestylesheetsfolder
Nowyouonlyneedtopointsomestylestothosefonts.
Theresourcefilesincludemanyformatsofeachfont.Asusual,differentbrowservendors
supportdifferentkindsoffonts.Tosupportthewidestarrayofbrowsers,youneedto
includealloftheminyourproject.Yes,allofthem.
Tohelpyouout,the@font-facesyntaxletsyougiveacustomnametoafamilyoffonts
thatyoucanthenuseintherestofyourstyles.
An@font-faceblockisalittledifferentfromthedeclarationblocksyouhavebeenusing.
Insideofthe@font-faceblockarethreemainparts:
First,thefont-familyproperty,whosevalueisastringidentifyingthecustom
fontnameyoucanusethroughoutyourCSSfile.
Next,severalsrcdeclarationsspecifyingdifferentfontfiles.(Takenote–the
orderisimportant!)
Last,declarationsthatmodifythefont’spresentation,suchasthefont-weight
andthefont-style.
Addan@font-facedeclarationforthelakeshorefontfamilytothetopofstyles.css
andastyledeclarationtousethenewfontforthe.logo-textclass.
@font-face{
font-family:'lakeshore';
src:url('fonts/LAKESHOR-webfont.eot');
src:url('fonts/LAKESHOR-webfont.eot?#iefix')format('embedded-opentype'),
url('fonts/LAKESHOR-webfont.woff')format('woff'),
url('fonts/LAKESHOR-webfont.ttf')format('truetype'),
url('fonts/LAKESHOR-webfont.svg#lakeshore')format('svg');
font-weight:normal;
font-style:normal;
}
body{
font-size:10px;
background:rgb(149,194,215);
}
a{
text-decoration:none;
}
.logo-text{
background:white;
text-align:center;
text-transform:uppercase;
font-family:lakeshore;
font-size:37px;
}
...
Admittedly,gettingthe@font-facedeclarationjustrightcanbetricky,becausetheorder
oftheindividualurlvaluesisimportant.Itisagoodideatokeepacopyofthedeclaration
forreference.YoucanalsolookintoAtomssnippetsdocumentationatflight-
manual.atom.io/using-atom/sections/snippetstoseehowtocreateyour
owncode“snippet,”ortemplate.
Afterdeclaringthecustom@font-face,therestofyourCSShasaccesstothenew
lakeshorevalueforthefont-familyproperty.Inthe.logo-textdeclaration,youset
font-family:lakeshoretoapplythenewfont.
Savestyles.css,switchtoChrome,andseehowgooditfeelstohaveawebpageas
stylishasanotter(Figure3.29).
Figure3.29Applyingacustomfonttotheheader
Youdidalotofstylingworkinthischapter,andOttergramlooksgreat!Inthenext
chapteryouwillmakeitevenbetterbyaddinginteractivefunctionality.
BronzeChallenge:ColorChange
Changethebackgroundcolorstylesforbody.UsethecolorpickerintheDevTools
(Figure3.21)tohelpyouchooseone.
Foramoresophisticatedcolorpalette,gotocolor.adobe.comandcreateyourown
schemeforthebodyand.thumbnail-titlebackgroundcolors.
FortheMoreCurious:Specificity!WhenSelectors
Collide…
Youhavealreadyseenhowyoucanoverridestyles.Youincludedthelinkfor
normalize.cssbeforetheoneforstyles.css,forexample.Thismadethe
browserusenormalize.csssstylesasabaseline,withyourstylestakingprecedence
overthebaselinestyles.
Thisisthefirstbasicconceptofhowthebrowserchooseswhichstylestoapplytothe
elementsonthepage,knowntofront-enddevelopersasrecency:Asthebrowserprocesses
CSSrules,theycanoverriderulesthatwereprocessedearlier.Youcancontroltheorderin
whichthebrowserprocessesCSSbychangingtheorderofthe<link>tags.
Thisissimpleenoughwhentheruleshavethesameselector(forexample,ifyourCSS
andnormalize.cssweretodeclareadifferentmarginforthebodyelement).Inthis
case,thebrowserchoosesthemorerecentdeclaration.Butwhataboutelementsthatare
matchedbymorethanoneselector?
SayyouhadthesetworulesinyourOttergramCSS:
.thumbnail-item{
background:blue;
}
li{
background:red;
}
Bothofthesematchyour<li>elements.Whatbackgroundcolorwillyour<li>elements
have?Eventhoughtheli{background:red;}ruleismorerecent,.thumbnail-item
{background:blue;}willbeused.Why?Becauseitusesaclassselector,whichis
morespecific(i.e.,assignedahigherspecificityvalue)thantheelementselector.
Classselectorsandattributeselectorshavethesamedegreeofspecificity,andbothhavea
higherspecificitythanelementselectors.ThehighestdegreeofspecificitygoestoID
selectors,whichyouhavenotseenyet.Ifyougiveanelementanidattribute,youcan
writeanIDselectorthatismorespecificthananyotherselector.
IDattributeslooklikeotherattributes.Forexample:
<liclass="thumbnail-item"id="barry-otter">
TousetheIDinaselector,youprefixitwith#:
.thumbnail-item{
background:blue;
}
#barry-otter{
background:green;
}
li{
background:red;
}
Inthisexample,the<li>ismatchedbyallthreeselectors,butitwillhaveagreen
backgroundbecausetheIDselectorhasthehighestspecificity.Theorderofyourrulesets
makesnodifferencehere,becauseeachhasadifferentspecificity.
OnenoteaboutusingIDselectors:Itisbesttoavoidthem.IDvaluesmustbeuniquein
thedocument,soyoucannotusetheid="barry-otter"attributeforanyotherelementin
yourdocument.EventhoughIDselectorshavethehighestspecificity,theirassociated
stylescannotbereused,makingthemamaintenance“worstpractice.”
Tolearnmoreaboutspecificity,gototheMDNpagedeveloper.mozilla.org/
en-US/docs/Web/CSS/Specificity.
TheSpecificityCalculatoratspecificity.keegan.stisagreattoolforcomparing
thespecifictyofdifferentselectors.Checkitouttogetamorepreciseunderstandingof
howspecificityiscomputed.
4
ResponsiveLayoutswithFlexbox
Oneofthedutiesoffront-enddevelopersistoprovidethebestexperiencetousers
regardlessofwhatdeviceorbrowsertheyareusing.
Thiswasnotalwaystheprevailingattitude,andthecompaniesthatmadebrowserswere
partlytoblame.Intheearlydaysoftheweb,browsermakerswerefightingawar.Each
wouldinventnewnonstandardfeaturesinanattempttoout-dotheothers.Inresponse,
webdeveloperscameupwithschemesfordetectingwhichbrowserwasrequestinga
documentandwhatscreensizewasbeingused.Basedonthisinformation,adifferent
versionofthedocumentwasservedout.
Sadly,thismeantthatfront-enddevelopmentbecameweigheddownwithcreating
multiplecopiesofeverypageonasite,eachcopybuiltwiththemarkupandstylesthat
wouldworkforaspecificversionofabrowserrunningataparticularscreensize.
Maintainingallofthesecopieswasbothtimeconsumingandfrustrating.
Thankfully,theBrowserWarsareover,andbrowsermakersnowstrivetoconformtothe
samesetofstandardfeatures–andmodernfront-enddevelopersarefreetofocusona
singlecodebaseforawebsite.Gonearethedaysofneedingtocreatebrowser-specific
versionsofapage.Butthatdoesnotmeanthatdeveloperscannolongerprovidetailored
pagesbasedondifferentscreensizesororientations.Newtechnologies–likeflexbox,
whichyouwilllearnaboutinthischapter–allowlayoutstoadjusttotheusersscreen
sizewithoutrequiringduplicatedocuments.
Inthischapter,youaregoingtoexpandOttergramfromasimplelistofimagestoaproper
userinterfacereadyforinteractivecontent.UsingflexboxandCSSpositioning,youwill
buildasetofinterfacecomponentsthatadjustasneededtovariationsinthesizeofthe
browserwindowwhilemaintainingtheoveralllayout.Attheendofthechapter,
Ottergramwillfeatureascrollinglistofthumbnailimagesandanareathatdisplaysa
large,detailedversionofasingleimage(Figure4.1).
Figure4.1Ottergramwithflexiblelayout
Youwilldothisintwoparts.First,youwilladdtheminimalmarkupandstylesnecessary
toshowthelargeimageonthepageandtomakethethumbnailssmallerandscrollable.
Then,youwilladdstylesthatletpartsofthepagestretchandshrinkasthewindow
changessizeortoaccommodatescreensofdifferentsizes.
ExpandingtheInterface
SincetheintroductionoftheiPhone,thetrendtowardaccessingtheinternetviaa
smartphone,ratherthanadesktoporlaptop,hasgrownsteadily.
Forfront-enddevelopers,thistrendhasmeantthatmobile-firstdevelopmenthasprovento
bethebestdesignapproach:designingforsmallscreensfirst,thenbuildingonthatdesign
fortablet-sizescreens,andfinallybuildinguptoadesktop-sizeddesign.
Ottergram’ssimplelayoutisalreadymobile-friendly.Itdisplaysthetextandimagesata
scalethatisappropriateforsmallerscreensizes.Becauseofthis,youcanmoverightinto
addingthenextlevelofcomplexitytoyourlayout.
Averticallyscrollinglistofottersisfine,butitwouldbeevenbetteriftheusercouldalso
seealargerversionoftheimages.TheplanforOttergramistomakethethumbnaillist
scrollhorizontallywhilealargerdetailimageisfeatured.Fornow,thedetailimagewillbe
belowthelist.ThisplanisdiagrammedinFigure4.2.
Figure4.2NewlayoutforOttergram
Youwillbeginbyaddingthedetailimage.
Addingthedetailimage
Fornow,yourdetailimagewillbefixedtoasingleimage.InChapter6youwilladd
functionalitysothattheusercanclickonathumbnailtomakeanyimagethedetailimage.
Addanewsectionofcodetocreatethedetailimageinindex.html:
...
<liclass="thumbnail-item">
<ahref="#">
<imgclass="thumbnail-image"src="img/otter5.jpg"alt="BarbaratheOtter">
<spanclass="thumbnail-title">Barbara</span>
</a>
</li>
</ul>
<divclass="detail-image-container">
<imgclass="detail-image"src="img/otter1.jpg"alt="">
<spanclass="detail-image-title">Stayin'Alive</span>
</div>
</body>
</html>
Youaddeda<div>withadetail-image-containerclass.A<div>isagenericcontainer
forcontent–usuallyforthepurposeofapplyingstylingtotheenclosedcontent,whichis
exactlyhowyouwilluseit.
Insidethe<div>youaddedan<img>tagtodisplaythelargeversionoftheotterimage.
Youalsoaddeda<span>,whichwrapsaroundthetitletextforthedetailimage.Yougave
the<img>and<span>tagstheclassnamesdetail-imageanddetail-image-title,
respectively.
Saveindex.html,switchtostyles.css,and,attheend,constrainthewidthofyour
new.detail-imageclass.
...
.thumbnail-title{
...
}
.detail-image{
width:90%;
}
Savestyles.cssandstartbrowser-synctoopenyourprojectinChrome(Figure4.3).
(Thecommandisbrowser-syncstart--server--browser"GoogleChrome"--
files"stylesheets/*.css,*.html".)
Figure4.3Initialstylingforthedetailimage
Your.detail-imagewillappearatthebottomofthepage,abitnarrowerthanyour
thumbnails.Bymakingthedetailimage90%ofitscontainerswidth,youhaveleftalittle
spacenexttoit.Thebrowserputsthetextofthe.detail-image-titleinthatspace.(You
willstylethattextlaterinthischapter.)
Ifyouresizethepage,youwilldiscoverabug:Thedetailimagemaybepushedoutof
viewbythethumbnailsastheyadjusttothenewwidth.Youwilladdressthisproblem
laterinthischapter.
Horizontallayoutforthumbnails
Next,youwillupdatethe.thumbnail-listand.thumbnail-itemclassessothatthe
imagesscrollhorizontally.
Tohelpyoutestyourscrolling,duplicateallfive<li>elementsinindex.html.This
willgiveyoulotsofcontenttoscrollthrough.Todothis,simplyselectallofthelines
between<ulclass="thumbnail-list">and</ul>,copythem,andpastetheresultjust
abovethe</ul>.Youshouldendupwith10listitems,containingimagesotter1.jpg
throughotter5.jpgtwice.
Besuretosaveindex.htmlwhenyouaredone.Duplicatingcontentwhileyouare
developingisagoodtechniqueforsimulatingamorerobustproject.Itallowsyoutosee
howyourcodehandlesreal-worldsituations.
Forahorizontallyscrollinglistofthumbnails,eachthumbnailmustbeconstrainedtoa
specificwidthandthethumbnailsshouldbelaidouthorizontallyonasingleline.
Thedisplay:blockproperty,whichyouhaveusedseveraltimes,willnotcreatethe
desiredeffect.Itcausesthebrowsertorenderalinebreakbeforeandaftertheelement.
However,arelatedstyle,display:inline-block,isperfectforthissituation.With
inline-block,theelement’sboxisdrawnasifyoudeclareddisplay:block,butwithout
thelinebreaks–allowingyourthumbnailstostaylinedupinarow.
Addawidthdeclarationandchangethedisplaydeclarationforthe.thumbnail-item
classinstyles.css.
...
.thumbnail-item{
display:block;
display:inline-block;
width:120px;
border:1pxsolidrgb(100%,100%,100%,0.8);
border:1pxsolidrgba(100%,100%,100%,0.8);
}
...
(NotethatAtomslintermaywarnyouthat“Usingwidthwithbordercansometimesmake
elementslargerthanyouexpect.”Thisisbecausethewidthpropertyonlyappliestothe
contentportion–notthepaddingorborder–oftheelement’sbox.Youdonotneedtodo
anythingaboutthiswarning.)
Withthe.thumbnail-itemelement’swidthsettoanabsolutevalueof120px,the
.thumbnail-imageiseffectivelyfixedaswell,sincethe.thumbnail-imageadjuststoits
containerswidth.
Whynotjustsetthe.thumbnail-imagetowidth:120px?Youwantthe.thumbnail-
imageandthe.thumbnail-titletobethesamewidth.Insteadofsettingthewidth
propertyforeachofthese,yousetitontheircommonparentelement.Thatway,ifyou
needtochangethewidth,youonlyneedtochangeitinoneplace.Generally,itisagood
practicetohaveinnerelementsadapttotheircontainers.
Savestyles.cssandcheckyourpageinChrome.Youcanseethatthe.thumbnail-
itemelementslineupsidebyside–butwhentheyfillthewidthoftheircontainer,they
wraparound(Figure4.4).
Figure4.4inline-blockcreatesrowsthatwrap
Togetthescrollingbehavioryouwant,set.thumbnail-listtopreventwrappingand
allowscrollinginstyles.css.
...
.thumbnail-list{
list-style:none;
padding:0;
white-space:nowrap;
overflow-x:auto;
}
...
Thewhite-space:nowrapdeclarationpreventsthe.thumbnail-itemelementsfrom
wrapping.Theoverflow-x:autotellsthebrowserthatitshouldaddascrollbaralongthe
horizontalspace(thexaxis)ofthe.thumbnail-listelementtoaccommodatecontent
thatoverflows–i.e.,doesnotfitwithinthe.thumbnail-list.Withoutthisdeclaration,
youwouldhavetoscrolltheentirewebpagetoseetheadditionalthumbnails.
Saveyourfileagainandtakealookattheresultsinyourbrowser.Thethumbnailsare
nowinasinglerow,andyoushouldbeabletoscrollthroughthemhorizontally
(Figure4.5).
Figure4.5Horizontallyscrollingthumbnails
ThisisagoodstarttotheenhancedOttergraminterface.Itworksjustfineforsomescreen
sizes.However,itisnotperfect,becauseitdoesnotadaptwelltoawiderangeofsizes–
especiallythosethataremuchlargerorsmallerthanthecomputeryouarecurrentlyusing.
Inthenexttwosections,youwilladdcodethatgivesOttergramamorefluidlayoutand
allowsitsUI-itsuserinterface-toshiftbetweendifferentlayoutstoadapttorangesof
screensizes.
Flexbox
Youhaveseendisplaystylesspecifyingthepropertiesblockandinline.Inline
elements,likethethumbnailitemsinyournewlyscrollinglist,arelaidoutnexttoone
another,whileblockelementsoccupytheirownhorizontalline.
Anotherwaytothinkofthisisthatblockelementsflowfromtoptobottomandinline
elementsflowfromlefttoright(Figure4.6).
Figure4.6Blockvsinlineelements
Thedisplaypropertytellsthebrowserhowanelementshouldflowinthelayout.For
blogsoronlineencyclopedias,theinlineandblockvaluesworkwell.Butfor
application-stylelayoutslikeweb-basedemailandsocialmediasites,thereisanewCSS
specificationthatallowselementstoflowmoredynamically.Thisistheflexiblebox
model,orflexbox.
FlexboxCSSpropertiescanensurethatthumbnailanddetailareasfillthescreenand
maintaintheirproportionsrelativetooneanother.Thisisexactlywhatyouneedfor
Ottergram.Youcanalsouseflexboxpropertiestocenterthecontentsofthedetailarea
bothhorizontallyandvertically,ataskwhichisnotoriouslydifficultusingstandardbox
modelproperties.
Creatingaflexcontainer
Beforeyouaddyourfirstflexboxproperty,setyour<html>and<body>elementsto
height:100%instyles.css.The<html>elementistherootelementofyourDOM
tree,withthe<body>asachildelementdrawninsideofit.Settingtheheightto100%for
bothofthemallowsthecontenttofillthebrowserordevicewindow.
@font-face{
...
}
html,body{
height:100%;
}
body{
font-size:10px;
background:rgb(149,194,215);
}
...
Noticethatyouhavegroupedtwoselectors,separatedbyacomma,inthisstylingrule.
Selectorsofanytypecanbecombinedinthiswaytosetcommonstyles.
Noticealsothatyounowhavetwostylingruleswiththebodyelementselector.Whenthe
browserseesadditionalstylingdeclarationsforaselector,itsimplyaddstoitsexisting
stylinginformationforthatselector.Inthiscase,itfirstseesthatthe<body>shouldhavea
heightof100%andstoresthatinformation.Whenitreadsthenextstylingruleforthe
<body>,itstoresthebackgroundandfont-sizeinformationalongwiththeheightstyle.
Nowyouarereadytocreateyourfirstflexcontainer.Whenanelementisaflexcontainer,
itcancontrolhowitschildelements(itsflexitems)arelaidout.Insideaflexcontainer,the
sizeandplacementofflexitemsoccursalongthemainaxisandthecrossaxis
(Figure4.7).
Figure4.7Themainandcrossaxesofaflexcontainer
Makeyour<body>elementaflexcontainerbyaddingadisplay:flexdeclarationtoits
stylingruleinstyles.css.
...
body{
display:flex;
font-size:10px;
background:rgb(149,194,215);
}
...
Ifyousavednow,yourbrowserwoulddisplayarathersad-lookingOttergram,asin
Figure4.8.Thisisbecausethemainaxisgoesfromlefttoright,layingtheflexitems(all
thechildrenofthe<body>)outinarow.
Figure4.8Flexitemslaidoutalongthemainaxis
However,youcanseethattheindividualitemsshrinktoaccommodatethespace,instead
ofwrapping.Thatisthefirstpieceofgoodnews.Thesecondpieceofgoodnewsisthat
youcanfixthelayoutwithjustonestyle.(Well,almost.)
Changingtheflex-direction
Tofixthelayout,setthe<body>element’sflex-directiontocolumninstyles.css:
...
body{
display:flex;
flex-direction:column;
font-size:10px;
background:rgb(149,194,215);
}
...
Thisswapsthemainandcrossaxesfortheflexcontainer,asillustratedinFigure4.9.
Figure4.9Mainandcrossaxeswithflex-direction:column
Afterchangingtheflex-directiontocolumn,Ottergramisbacktonormal–almost.
Thereisavisualbuginthelayoutwhenthebrowserwindowisalotwiderthanitistall,
showninFigure4.10.
Figure4.10Missingthumbnailswhenthepageisstretchedwide
Youwillremedythisbyaddingawrapperelementandapplyingnewflexboxproperties.
Groupingelementswithinaflexitem
The<body>hasthreeflexitems:the<header>,the.thumbnail-list,andthe.detail-
image-container.Nomatterwhathappensduringthedevelopment(anduse)of
Ottergram,the<header>isnotlikelytochangemuchinitslayoutorcomplexity.Itis
goingtobeatthetopofthepage,displayingtext.Thatisaboutit.
Ontheotherhand,asyoudevelopOttergramthe.thumbnail-listand.detail-image-
containerandtheircontentsmayverywellchangeinlayoutandcomplexity.Also,
changestooneoftheseitemsarelikelytoaffecttheother.
Forthesereasons,youaregoingtogroupthe.thumbnail-listandthe.detail-image-
containerintheirownflexcontainer.Todothis,youwillwrapthemina<main>tagwith
aclassnameof.main-content(Figure4.11).
Figure4.11Wrappingthe.thumbnail-listand.detail-image-container
Makeitsoinindex.html:Givethe<header>elementtheclassmain-header,then
wrapthe.thumbnail-list(<ul>)andthe.detail-image-container(<div>)ina
<main>elementwiththeclassmain-content.
...
<body>
<header>
<headerclass="main-header">
<h1class="logo-text">ottergram</h1>
</header>
<mainclass="main-content">
<ulclass="thumbnail-list">
...
</ul>
<divclass="detail-image-container">
<imgclass="detail-image"src="img/otter1.jpg"alt="">
<spanclass="detail-image-title">Stayin'Alive</span>
</div>
</main>
...
.main-headerand.main-contentarenowthetwoflexitemsinsidethe<body>.
Bywrappingthe.thumbnail-listand.detail-image-containerinthe.main-content
element,youarenowfreetodeclareaheightforthe<header>,leavingtherestofthe
<body>sverticalspaceforthe.main-contenttooccupy.Thatway,thespaceinsideof
.main-contentcanbedistributedto.thumbnail-listand.detail-image-container
withoutaffectingtheheader.
Saveindex.html.Nowthatyouhavethemarkupforthetwoflexitemsinsidethe
body,youcansettheirsizesrelativetooneanotherusingtheflexproperty.
Theflexshorthandproperty
Aflexcontainerdistributesitsspacetotheflexitemsinsideofit.Iftheflexitemsdonot
specifytheirsizealongthemainaxis,thenthecontainerdistributesthespaceevenlybased
onthenumberofflexitems,witheachflexitemgettingthesameshareofspacealongthe
mainaxis.Thisisthedefault,illustratedinFigure4.12.
Figure4.12Equaldistributionofspacebetweenthreeflexitems
ButimaginethatoneofthethreeflexitemsinFigure4.12isabitgreedierthantheothers
andclaimstwosharesofthetotalspace.Inthatcase,theflexcontainerdividesthespace
alongthemainaxisintofourshares.Thegreedyitemoccupiestwoofthem(halfthe
space)andtheotheritemsgetoneshareeach(Figure4.13).
Figure4.13Unequaldistributionofspacebetweenthreeflexitems
InOttergram,youwantthe.main-contentelementtobethegreedyelement,takingupas
muchspacealongthemainaxisaspossible.The.main-header,ontheotherhand,should
takeupaslittlespaceaspossible.
Theflexpropertyletsyourflexitemsspecifyhowmuchoftheavailablespacetheywill
takeup.Itisashorthandproperty,asshowninFigure4.14.
Figure4.14Theflexshorthandpropertyanditsvalues
Westronglyrecommendthatyouuseflexinsteadoftheindividualpropertiesit
represents.Itprotectsyoufrominadvertentlyleavingapropertyoutandgetting
unexpectedresults.
Thefirstvalueistheonetofocusonrightnow,asitdetermineshowmuchtheflexitem
cangrow.Bydefaultflexitemsdonotgrowatall.Youwantthatdefaultbehaviorforyour
.main-header,butnotyour.main-content.
Instyles.css,addadeclarationblockforthe.main-headerclassselector,specifying
aflexshorthandpropertywithdefaultvalues:01auto.
...
a{
text-decoration:none;
}
.main-header{
flex:01auto;
}
.logo-text{
background:white;
...
Thevalue01autocanbereadas,“Idonotwanttogrowanylarger;Iwillshrinkas
needed;pleasecalculatemysizeforme.”Theendresultwillbethatthe.main-header
willtakeuponlyasmuchspaceasitneeds,andnomore.
Next,addadeclarationblockfor.main-content,settingitsflexto11auto.
...
.logo-text{
...
}
.main-content{
flex:11auto;
}
.thumbnail-item+.thumbnail-item{
...
Thefirstvaluein.main-contentsflexdeclarationcorrespondstotheflex-grow
property.Avalueof1tellsthecontainer,“Iwouldliketogrowasmuchaspossible.”
Becauseitsonlysiblinghasdeclaredthatitwillnotgrow,the.main-contentelementwill
growtotakeupallthespacenotneededforthe.main-header.
The<body>stwoflexitems,the.main-headerandthe.main-contentelements,occupy
theflexiblespaceaccordingtotheirneeds.Nowitistimetoadjustthelayoutofthe
.main-contentelement.
Ordering,justifying,andaligningflexitems
Flexboxalsoallowsyoutosubdivideflexitemsintoflexcontainers.Thistechniquelets
youfocusonthelayers.Inamoment,youaregoingtomakeyour.main-contentaflex
container.
Workingwithnestedflexcontainersisanexceptiontotheatomicstylingapproachto
creatingthelookandfeelofvisualcomponents.Insteadofstylingthesmallest,innermost
elementsfirstandthenworkingyourwayouttothelargestelements,whenworkingona
layoutwithflexboxitismoreusefultostartwiththeoutermostelementsandworkyour
wayin.
Hereiswhatyouwilltacklenext.Youwillchangethe.main-contenttoaflexcontainer
withaverticalmainaxis.Also,youwillspecifytheflexpropertiesfor.main-contents
flexitemssothatthe.thumbnail-listtakesthedefaultamountofspaceand.detail-
image-containergrowstofillthespaceleftover.Finally,youwillmovethe
.thumbnail-listbelowthe.detail-image-container(Figure4.15).
Figure4.15Making.main-contentaflexcontainer
Makethesechangesinstyles.cssbyaddingdisplay:flexandflex-direction:
columnto.main-contentsdeclarationblock,addingflexpropertiesto.thumbnail-
listsdeclarationblock,andwritinganewdeclarationblockforthe.detail-image-
containerclass.
...
.main-content{
flex:11auto;
display:flex;
flex-direction:column;
}
...
.thumbnail-list{
flex:01auto;
list-style:none;
padding:0;
white-space:nowrap;
overflow-x:auto;
}
...
.thumbnail-title{
...
}
.detail-image-container{
flex:11auto;
}
.detail-image{
...
Youmightbewonderingwhyyouarenotdefiningtheheightsofthe.thumbnail-list
and.detail-image-containerboxeswithpercentages,thewayyoudefinedthewidthof
the.detail-image.Settingtheheightofthe.thumbnail-listat,forexample,25%and
the.detail-image-wrapperat75%seemslogical–butitwouldnotworkthewayyou
intend.Theinteractionwiththewidthpropertyofthe.detail-imagewouldresultinthe
.detail-image-containerbeingmuchtoolarge,andthe.thumbnail-listwouldendup
eithertoosmallortoolarge,dependingonthewindowsize.
Inshort,usingtheflexpropertytosettheflexitems’sizesinconjunctionwiththeone
fixedsizeyoucareabout–thewidthofthe.detail-image–isthewaytogo.
Nowtomovethethumbnaillistbelowthedetailimage.Bydefault,flexitemsaredrawn
intheorderthattheyappearintheHTML.Thisisknownassourceorderandisthemain
waythatdeveloperscontroltheorderinwhichelementsaredrawn.
Oneoptionformovingthedetailimageupwouldbetocutandpastethemarkupforthe
detailimagesothatitcamebeforethemarkupforthe.thumbnail-list–tochangethe
sourceorder.However,itcanalsobedoneusinganewflexboxproperty.
Tochangetheorderusingflexbox,addanorderdeclarationtothe.thumbnail-list
selectorinstyles.css.
...
.thumbnail-list{
flex:01auto;
order:2;
list-style:none;
padding:0;
white-space:nowrap;
overflow-x:auto;
}
...
Theorderpropertycanbeassignedanyintegervalue.Thedefaultvalueis0,whichtells
thebrowsertousethesourceorder.Anyothervalues,includingnegativenumbers,tellthe
browsertodrawaflexitembeforeorafterotherflexitems.Giving.thumbnail-listthe
declarationorder:2tellsthebrowsertodrawitafteranyofitssiblingsthathavealower
valuefororder–suchas.detail-image-container,whichisusingthedefault.
Savestyles.cssandswitchtoChrome.Youwillseethatthethumbnailsarerendered
alongthebottomofthepage(Figure4.16).
Figure4.16Changingtheorderelementsaredrawn
Next,youwillcontinuetoapplydisplay:flexasyouworkonthelayoutofthe
OttergramUI.Sofar,youhaveworkedwithflexcontainersthatholdonlyacoupleofflex
items.Makethe.thumbnail-listaflexcontainersothatyoucanfurtherexplorewhat
flexboxcanofferyou.
...
.thumbnail-list{
flex:01auto;
order:2;
display:flex;
list-style:none;
padding:0;
white-space:nowrap;
overflow-x:auto;
}
...
Donotpanicifyousaveyourchangesandseethatthethumbnailsarerenderedoddly,as
inFigure4.17.
Figure4.17Otters,askew
Tofixthis,replacethe.thumbnail-itemswidthdeclarationwithapairofdeclarations,
oneformin-widthandanotherformax-width.Thiswillremovethevariationsinsizethat
arecausingthestrangelayout.
Youcanalsoremovethedeclarationblockthatsetsthemargin-topfor.thumbnail-item
+.thumbnail-itemelements.Itisnolongerneededforthislayout.
...
.thumbnail-item+.thumbnail-item{
margin-top:10px;
}
.thumbnail-item{
display:inline-block;
width:120px;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
}
...
Next,youwillworkwiththespacingoftheflexitemsinsideof.thumbnail-list.In
styles.css,addadeclarationforjustify-contenttothe.thumbnail-listselector.
...
.thumbnail-list{
flex:01auto;
order:2;
display:flex;
justify-content:space-between;
list-style:none;
padding:0;
white-space:nowrap;
overflow-x:auto;
}
...
Thejustify-contentpropertyletsaflexcontainercontrolhowflexitemsaredrawnon
themainaxis.Youusedspace-betweenasthevaluetomakesurethereisanevenamount
ofspacingaroundeachindividualflexitem.
Therearefivedifferentvaluesyoucanspecifyforjustify-content.Figure4.18
illustrateshoweachofthesevaluesworks.
Figure4.18Valuesforthejustify-contentproperty
Youhavetackledthelayoutofthe.thumbnail-list.Next,youwillworkwiththe
.detail-image-containeranditscontents.
Centeringthedetailimage
ThedetailimageshouldbeOttergram’smainfocus.Itshouldbefrontandcentertomake
surethattheuserisadmiringthemajestyoftheotter.Itshouldalsobeadornedwitha
snazzytitle.
Tocenterthedetailimage,youwillfirstwraptheimageanditstitleinacontainer,then
centerthewrapperinsidethe.detail-image-container.Thisideaisillustratedin
Figure4.19.
Figure4.19Framingthe.detail-imageand.detail-image-title
Whileyoucouldcenterthe.detail-imageitselfinsidethe.detail-image-container,it
wouldbedifficulttocorrectlyoffsetthe.detail-image-title,becauseboththe
.detail-imageandthe.detail-image-containeraredynamicallyresizing.
Anintermediarywrapperelementisausefultechniqueforthissituation.Itwillconstrain
thesizeofthe.detail-imageandserveasareferenceforpositioningthe.detail-
image-title.
Inindex.html,beginbyaddinga<div>withtheclassnamedetail-image-frame:
...
</ul>
<divclass="detail-image-container">
<divclass="detail-image-frame">
<imgclass="detail-image"src="img/otter1.jpg"alt="">
<spanclass="detail-image-title">Stayin'Alive</span>
</div>
</div>
</main>
</body>
</html>
Saveindex.html.Now,instyles.css,addadeclarationblockfor.detail-image-
framewithasinglestyledeclaration:text-align:center.Thisisonewaytocenter
contentwithoutflexbox,butnotethatitonlyworkshorizontally.
...
.detail-image-container{
flex:11auto;
}
.detail-image-frame{
text-align:center;
}
.detail-image{
width:90%;
}
Next,tocenterthe.detail-image-frameinsidethe.detail-image-container,update
styles.csstomake.detail-image-containeraflexcontainer.Drawitsflexitemsin
thecenterofthemainaxis(inthiscase,horizontally–thedefault)withjustify-
content:center,andaddanewflexboxproperty,align-items:center,todrawits
flexitemsinthecenterofthecrossaxis(vertically).
...
.detail-image-container{
flex:11auto;
display:flex;
justify-content:center;
align-items:center;
}
...
Saveyourchangesandenjoytheproudotter,noblycenteredinthe.detail-image-
container(Figure4.20).
Figure4.20Aftercentering.detail-image-frameinside.detail-image-
container
AbsoluteandRelativePositioning
Sometimesyouneedtoplaceanelementinanexactspotinsideofanotherelement.CSS
givesyouawaytodothisusingabsolutepositioning.
Youwilluseabsolutepositioningtoplacethedetail-image-titleinthelowerleft
cornerofthe.detail-image-frame,asshowninFigure4.21.
Figure4.21Absolutelypositioned.detail-image-title
Therearethreerequirementsforabsolutepositioning.Theabsolutelypositionedelement
musthave:
thepropertyposition:absolute,totellthebrowsertotakeitoutofthe
normalflowratherthanlayingitoutalongwithitssiblings
coordinates,providedusingoneormoreofthetop,right,bottom,andleft
properties;absolutelengths(suchaspixels)orrelativelengths(suchas
percentages)maybeusedasvalues
anancestorelementwithanexplicitlydeclaredpositionpropertywithavalue
ofrelativeorabsolute;thisisimportant–ifnoancestorhasadeclared
positionproperty,theabsolutelypositionedelementwillbeplacedrelativeto
the<html>element(thebrowserwindow)
Awordofwarning:Itmightbetemptingtouseposition:absoluteforeverything,butit
shouldbeusedsparingly.Awholelayoutwithabsolutepositioningisnearlyimpossibleto
maintainandwilllookterribleonanyscreensizeotherthantheoneitwasdevelopedfor.
Whenspecifyingacoordinate,youarereallyspecifyingthedistancefromtheedgeofthe
elementtotheedgeofitscontainer,asshowninFigure4.22.
Figure4.22Elementsareabsolutelypositionedbasedontheiredges
Figure4.22hastwoexamplesofabsolutepositioning.Inthefirstone,theelementis
positionedsothatitstopedgeis50pxfromitscontainerstopedgeanditsleftedgeis
200pxfromitscontainersleftedge.Thesecondexampleshowsavariation,wherethe
elementispositionedbyitsbottomandleftedges.
Topositionthe.detail-image-title,startbydeclaringthe.detail-image-frameto
haveposition:relativeinstyles.css.Youwillpositionthe.detail-image-title
relativetoit.
...
.detail-image-frame{
position:relative;
text-align:center;
}
...
Youusedposition:relativefor.detail-image-framebecauseyouwantittoremain
innormalflow.Youalsowantittoserveasthecontainerforanabsolutelypositioned
descendant,soitspositionpropertymustbeexplicitlydefined.
Attheendofstyles.css,addadeclarationblockforthe.detail-image-title
selector.Fornow,makethetitlewhiteandsetthefontsizetobefourtimesthedefault.
...
.detail-image{
width:90%;
}
.detail-image-title{
color:white;
font-size:40px;
}
Sofar,sogood(Figure4.23).Butsobasic.
Figure4.23Basictextstylingfor.detail-image-title
Foratouchofstyle,let’saddsometexteffectstothe.detail-image-title.When
positioningstyledtextelements,bearinmindthattheelement’sboxmaychangedueto
thevisualcharacteristicsofacustomtypefaceorothereffects.Forthisexample,youwill
doallofthetextstylingfor.detail-image-titlebeforeyousetitsposition.Adda
text-shadowpropertyto.detail-image-titleinstyles.css.
...
.detail-image-title{
color:white;
text-shadow:rgba(0,0,0,0.9)1px2px9px;
font-size:40px;
}
Asthenamesuggests,thetext-shadowpropertyaddsashadowtotext.Itacceptsacolor
fortheshadow,apairoflengthsfortheoffset(i.e.,whethertheshadowfallsaboveor
belowandtotheleftorrightofthetext),andalengthfortheblurradius–anoptionalpart
ofatext-shadowdeclarationthatmakestheshadowlargerandlighterincolorasyou
makethevaluehigher.
Yougaveyourshadowthecolorattributergba(0,0,0,0.9)tomakeitaslightly
transparentblack.Itisoffset,orshifted,1pxtotherightand2pxbelowthetext(negative
valueswouldplaceittotheleftorabovethetext).Thelastvalueof9pxistheblurradius.
Figure4.24showsyournewshadow.
Figure4.24Atext-shadowforthe.detail-image-title
Tryadjustingthetext-shadowvaluesinthestylespaneoftheDevTool’selementspanel
togetafeelforhowtheywork(Figure4.25).
Figure4.25ExaggeratingthetextshadowusingtheDevTools
Whenyouareready,addonelastflourishwithacustomfont.AsyoudidinChapter3,
addan@font-facedeclarationinstyles.csstoaddtheAirstreamfonttoyourproject.
Addafont-family:airstreamregulardeclarationto.detail-image-titletoputitto
use.
@font-face{
font-family:'airstreamregular';
src:url('fonts/Airstream-webfont.eot');
src:url('fonts/Airstream-webfont.eot?#iefix')format('embedded-opentype'),
url('fonts/Airstream-webfont.woff')format('woff'),
url('fonts/Airstream-webfont.ttf')format('truetype'),
url('fonts/Airstream-webfont.svg#airstreamregular')format('svg');
font-weight:normal;
font-style:normal;
}
@font-face{
font-family:'lakeshore';
...
}
...
.detail-image-title{
font-family:airstreamregular;
color:white;
text-shadow:rgba(0,0,0,0.9)1px2px9px;
font-size:40px;
}
Sofar,sostylish(Figure4.26)!
Figure4.26Igottahavemorefancy
Nowthatyouhavefinishedthestylingof.detail-image-title,giveitaposition:
absolutedeclarationsothatthebrowserwillplaceitatapreciselocationwithin
.detail-image-frame.Specifythatlocationwithbottom:-16pxandleft:4px,toputit
justbelowthebottomedgeof.detail-image-frameandalittlebitinsidetheleftedgeof
.detail-image-frame.(Negativevaluesarefineforthecoordinates.)
...
.detail-image-title{
position:absolute;
bottom:-16px;
left:4px;
font-family:airstreamregular;
color:white;
text-shadow:rgba(0,0,0,0.9)1px2px9px;
font-size:40px;
}
Savestyles.css,andyouwillseeinthebrowserthatthe.detail-image-titlenow
sitsbelowandneartheleftoftheotterphoto.YounowhaveapositivelychicOttergramin
yourbrowser(Figure4.27).
Figure4.27Hello,gorgeous!
Takeastepbacktoenjoythefruitsofyourlabor.Ottergramhasadynamic,fluidlayout
thankstotheadditionofflexboxtoyourstyles.Inthenextchapteryouwillmakethe
layoutadapttodifferentbrowserwindowsizes.
5
AdaptiveLayoutswithMediaQueries
Inthischapter,youwillexploreatechniqueforturningstylesonandoffbasedonthesize
ofthebrowserwindowandothercharacteristics.Youwillprovideanalternatelayoutfor
largerscreensusingaminimalamountofcode.Thebrowserwillbeabletoswitch
betweenthedifferentlayoutsinrealtime,asthebrowserwindowchangessize–without
reloadingthepage.Figure5.1showstheoriginallayoutandthealternatelayout.
Figure5.1TwoOttergramlayouts
Theindustrytermforthisbehaviorisresponsivewebsite.Unfortunately,thistermisoften
apointofconfusion.Somethinkthatitmeans“fastwebsite”or“websitewithvisual
animations.”Weprefertocallitanadaptivelayout.
Thereareseveralwaysofincludingalternatestylestobeusedbasedonthecurrent
browserconditions.Therecommendedapproachistowriteyourstylesforthesmallest
screenandthenprovideoverridestylesinmediaqueriesthataretriggeredwhenthe
viewport–thebrowsersviewablearea–islargerthanasetthreshold.
Onatraditionalbrowser(liketheoneyouareusingwhiledevelopingOttergram),the
viewportistheareashownbythebrowserwindow.Thisisprettyintuitive.Onamobile
browser,itgetsmorecomplicated.Mobilebrowsershavemultipleviewports,andeach
oneplaysaroleinhowapageisrendered.
Front-enddevelopersneedtofocusonthelayoutviewport(sometimescalledtheactual
viewport).Thelayoutviewporttellsthebrowser,“PretendthatI’mactually980pixels
wideandthendrawthepage.”
Usersaremoreconcernedwithamobilebrowsersvisualviewport.Thisisthethingthat
theycanpinchtozoominandoutonapage(Figure5.2).
Figure5.2Visualviewportvslayoutviewport
IfyouviewedOttergramonyoursmartphonerightnow,youwouldseesomethinglike
Figure5.2,withthebrowserzoomedinontheupper-leftcornerofthepage.Needlessto
say,eventhoughamobileusercanzoomoutmanually,youdonotwantOttergramto
behavelikethisbydefault.
Earlierwementionedthatyouaretakingamobile-firstapproachtodevelopingOttergram.
Thatwasmostlytrue.Yourmarkupandstyleswerewritteninamobile-friendlyway–
usingaminimalamountofmarkupandstylingthesmallestelementsfirst.Now,youjust
needtogivethebrowserinformationaboutthelayoutviewportitshoulduse.
ResettingtheViewport
InChapter3youaddednormalize.csstoOttergram.Thisensuredthatanybrowser
viewingOttergramwouldhavethesamesetofdefaultstyles.Ontopofthesedefaults,you
couldconfidentlyaddyourownCSS,knowingitwouldworkconsistentlyfrombrowser
tobrowser.
Youwilldosomethingsimilarforthelayoutviewport.Justaseverybrowsermayhavea
differentuseragentstylesheet,everybrowsermayhaveadifferentdefaultlayout
viewport.However,unlikeusingnormalize.css,youarenotgoingtoresetthe
viewportforallbrowserstothesamevalue.Instead,youwillusea<meta>tagtotellall
browserstodisplayOttergramatthebestsizeforthedevice’sphysicalscreen.
Inindex.html,adda<meta>tagthattellsthebrowserthatthewidthofthelayout
viewportisthesameasthedevice’sscreenwidth.Makesuretosetthezoomto100%by
settingtheinitial-scaleto1.
<!doctypehtml>
<html>
<head>
<metacharset="utf-8">
<metaname="viewport"content="width=device-width,initial-scale=1">
<linkrel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">
<linkrel="stylesheet"href="stylesheets/styles.css">
<title>Ottergram</title>
</head>
...
Saveyourchanges.Thistechniquesetsthelayoutviewporttotheidealviewport.The
idealviewportisbestviewportsizeforaspecificdevice,asrecommendedbythebrowser
maker.Thisvariessignificantly,sincetherearemany,manydifferentdevicesandquitea
numberofdifferentbrowsers.
Table5.1summarizesthedifferenttypesofviewports.
Table5.1Summaryofthedifferentviewports
Viewport Description Device
viewport Theareaequaltothebrowserswindow.Itservesasthe<html>
element’scontainer.
desktop,
laptop
layout
viewport
Avirtualscreen,largerthantheactualdevicescreen,usedfor
calculatingthepagelayout. mobile
visual
viewport
Thezoomableareathatausercanseeonadevice’sscreen.
Zoominghasnoeffectonthepagelayout. mobile
ideal
viewport
Theoptimaldimensionsforaspecificbrowseronaspecific
device. mobile
Startbrowser-syncandmakesuretheDevToolsareopeninChrome.Looktotheleftof
theElementsmenuitemandfindtheToggleDeviceModebutton,whichlookslikethis: .It
isshownincontextinFigure5.3.
Figure5.3ToggleDeviceModebutton
Clickthisbuttontoactivatedevicemode.Youwillseethatthewebpageviewnowshows
Ottergramonasimulatedsmartphonescreen.Thereisamenuforchoosingbetween
differentscreensizesbasedonpopulardevices.Youcanalsoclickthegraybarbelowthe
presetstotogglebetweensmall,medium,andlargescreensizes.Andthereisamenufor
quicklychoosingascreenorientationoflandscapeorportrait.Figure5.4showsa
screenshotofthedevicemodeatthetimeofthiswriting.Yoursmaylookquitedifferent,
astheDevToolsundergoregularupdates.
Figure5.4Usingdevicemodeforresponsivetesting
Youcanseethat,thankstoyournew<meta>element,Ottergramdisplayswellonasmall
screen,suchasasmartphone.Fordeviceswithlargerscreens,suchastabletsorlaptops,a
slightlydifferentlayoutmaybemoreappropriate.Next,youwillapplydifferentlayout
stylesusingacombinationofflexboxandmediaqueries.
Clickthe buttonagaintodeactivatedevicemodebeforeyoucontinue.
AddingaMediaQuery
MediaqueriesletyougroupCSSdeclarationblocksandspecifytheconditionsunder
whichtheyshouldbeapplied.Thoseconditionsmaybesomethinglike“ifthescreenisat
least640pixelswide”or“ifthescreeniswiderthanitistallandhasahighpixeldensity.”
Thesyntaxbeginswith@media,followedbytheconditionstobematched.Nextisasetof
curlybracesthatwrapsaroundentiredeclarationblocks.Let’sseewhatthislookslike.
Beginyourfirstmediaqueryattheendofstyles.css.Youwillcreateamediaquery
thatwillactivatestyleswhenbeingviewedonanykindofdevicewhentheviewportisat
least768pixelswide,whichisacommondevicewidthfortablets.
...
.detail-image-title{
...
}
@mediaalland(min-width:768px){
/*Styleswillgohere*/
}
@mediaisfollowedbythemediatypeall.Mediatypeswereoriginallyintendedto
differentiatebetweendevices,suchassmarttelevisionsandhandhelddevices.
Unfortunately,browsersdonotimplementthisaccurately,soyoushouldalwaysspecify
all.Theonlytimeyoumightnotusealliswhenyouwanttospecifystylesforprinting,
whenyoucansafelyusethemediatypeprint.
Afterthemediatype,youwritetheconditionsforapplyingthestyles.Here,youareusing
theusefulconditionmin-width.Youcanseethatconditionslooksimilartostyle
declarations.
ToachievetheeffectshowninFigure5.1,youwillneedtochangetheflex-directionof
the.main-contentelement.Thiswillletthethumbnailsandthedetailimagesitnextto
oneanother.Youdonotwantthethumbnailstocausethebrowsertoscroll.Instead,they
shouldcontinuetoscrollindependentlyofthebrowserwindow.Forthat,youwilladd
overflow:hidden.
Addthosestylestoyourmediaqueryattheendofstyles.css.
...
@mediaalland(min-width:768px){
/*Styleswillgohere*/
.main-content{
flex-direction:row;
overflow:hidden;
}
}
Youwouldbeinforashockifyousavedandthenstretchedyourbrowserwideenoughto
triggeryourmediaquery.Atthemoment,yourpagelookslikeFigure5.5.Nottoworry.
Youwillfixthiswithonlyafewmorelinesofcode.
Figure5.5Ottersindisarray
Thethumbnailsneedtobedisplayedinacolumninsteadofarow.Thisiseasytodo,
becauseyouusedflexboxforlayingthemout.Addadeclarationblockinsidethebodyof
themediaqueryinstyles.csssetting.thumbnail-listsflex-directiontocolumn.
...
@mediaalland(min-width:768px){
.main-content{
flex-direction:row;
overflow:hidden;
}
.thumbnail-list{
flex-direction:column;
}
}
Savestyles.css.Thathasimprovedthingssignificantly(Figure5.6)!
Figure5.6Aftersettingflex-directiontocolumn
Accordingtoyourdesign,thethumbnailsshouldgoontheleft.Youcansolvethisby
changing.thumbnail-listsorder.Earlier,yousetitto2sothatitwouldbedrawnafter
the.detail-image-container.Now,setitto0withinthemediaqueryinstyles.css
sothatitfollowsthesourceorderandisdrawnbeforethe.detail-image-container.
...
@mediaalland(min-width:768px){
.main-content{
flex-direction:row;
overflow:hidden;
}
.thumbnail-list{
flex-direction:column;
order:0;
}
}
Saveyourchangesandconfirmthatthethumbnailsaredrawnontheleftsideofthepage.
Youarealmostthere!Addafewmorestylesinstyles.cssforthe.thumbnail-list
and.thumbnail-itemstomakethesizingandspacingalittlenicer.
...
@mediaalland(min-width:768px){
.main-content{
flex-direction:row;
overflow:hidden;
}
.thumbnail-list{
flex-direction:column;
order:0;
margin-left:20px;
}
.thumbnail-item{
max-width:260px;
}
.thumbnail-item+.thumbnail-item{
margin-top:20px;
}
}
Onceagain,savestyles.cssandswitchtoyourbrowser.Yourlayoutnowlookssharp
whethertheviewportisnarrowerorwider(Figure5.7).
Figure5.7Responsiveotters
Ottergramismakingsteadyprogress!Youhavecreatedagood-lookingwebsitewitha
layoutthatcanadapttomanyscreensizes.Inthenextchapter,youwillbeginusing
JavaScripttoaddalayerofinteractivitytoOttergram.
BronzeChallenge:Portrait
Yourcurrentmediaquerychangesthelayoutbasedonthewidthoftheviewport.You
couldlookatthisinadifferentway.Oneisforviewportsthataretallerthantheyarewide,
andtheotherisforviewportsthatarewiderthantheyaretall.Thesearetwoorientation
modesthatyourviewportcanbein.
CheckMDN’sdocumentationformediaqueriesandupdateyourmediaquerysothatthe
layoutchangesaccordingtoorientationandnotbasedonwidth.
FortheMoreCurious:CommonSolutions(andBugs)
withFlexboxLayouts
PhilipWaltonisadeveloperwhomaintainstwoveryimportantflexboxresources.The
firstistheSolvedbyFlexboxsite(philipwalton.github.io/solved-by-
flexbox),whichoffersdemosofcommonlayoutsimplementedusingflexboxandall
theinformationyouneedtocreatethemyourself.Someofthelayoutsareverydifficultto
achievewithoutflexbox.
ThesecondresourceistheFlexbugspageatgithub.com/philipwalton/
flexbugs.Flexboxiswonderful,butitisnotperfect.Flexbugsprovidessolutionsand
workaroundsforcommonproblemsthatdevelopersrunintowhenusingflexbox.The
informationisprovidedbymembersofthedevelopmentcommunitywhohave
encounteredthesebugs,andthelistiswellmaintained.
GoldChallenge:HolyGrailLayout
Besuretomakeacopyofyourcodebeforeattemptingthischallenge!Itwillrequire
significantchangestothemarkupandstyles.Useyourcopyforworkingonthechallenge
andleavetheoriginalintactforstartingthenextchapter.
UsingSolvedbyFlexboxasareference,implementtheHolyGraillayoutinOttergram.
Createasecondnavigationbarwiththumbnails,butplaceitontheothersideofthe
viewport.
Makesuretoaddafooterelementtothebottomofyourpage.Usethe<footer>tagand
putan<h1>insideofit.
6
HandlingEventswithJavaScript
Youknowwhatiscoolaboutotters?Amongotherthings,theyholdhandswhentheysleep
sothattheydonotfloataway.Keepthisimageinmindasyoulearntoworkwithevent
callbacksinJavaScript.
JavaScriptisaprogramminglanguagethataddsinteractivitytowebsitesbymanipulating
DOMelementsandCSSstylesonapage.Itwasoriginallycreatedforusebypeoplewho
werenotprofessionalprogrammers.Ithasgrowninpowerandpopularityandisnowused
formanykindsofapplicationdevelopment.WhenyouusesiteslikeGmailorNetflix,you
areinteractingwithprogramswritteninJavaScript.Infact,theAtomtexteditorisactually
adesktopapplicationwritteninJavaScript.
Despiteitspowerandwidespreaduse,ithasitsquirks,likeanyprogramminglanguage.
AsyoucontinueworkingonOttergramandtheotherprojectsinthisbook,youwilllearn
tonavigatetheroughpatchesofthelanguageandtotakeadvantageofitsbestparts.
ThereareseveralversionsofJavaScript,andyouwillusethreeofthemfortheprojectsin
thisbook.TheyareallrevisionsofastandardspecificationknownasECMAScript(or
“ES”).Table6.1summarizesthem.
Table6.1JavaScriptversionsusedinthisbook
ECMAScript
Edition
Release
Date Notes
3December
1999
Mostwidelysupportedversion;encompassesmostofthe
languagefeaturesyouwilluse,suchasvariables,types,and
functions.
5December
2009
Backwardcompatible,withopt-inenhancementssuchasa
strictmodethatpreventstheusageofthemoreerror-prone
partsofthelanguage.
6June
2015
Includesnewsyntaxandlanguagefeatures;atthetimeof
thiswriting,mostbrowsersdonotyetsupportES6,butES6
codecanbetranslatedintoES5,makingitusablebymost
browsers.
Inthischapter,youwilluseJavaScripttomakeOttergraminteractive:Thedetailimage
anddetailtitlewillchangewhentheuserclicksortapsoneofthethumbnails.
Todothis,youaregoingtowriteaJavaScriptfunction–asetofstepsforthebrowserto
follow–thatreadstheURLforanimageandshowsitinthedetailarea.Thenyouwill
ensurethatthisfunctionisrunwhenathumbnailisclicked.Youwillalsowriteaseparate
functionthathidesthedetailareaandrunthatfunctionwhentheEscapekeyispressed.
Attheendofthechapter,Ottergramwillbeabletofeatureanyotterinthedetailimage
(Figure6.1).
Figure6.1Clickingthumbnailschangesdetailimageandtitle
Asyouwritethesefunctions,youwillinteractwiththepageusingasetofpredefined
interfacesbuiltintothebrowser.Therearealargenumberofthem,andthecodewillonly
walkyouthroughtheonesnecessaryforthetaskathand.Ifyouarecurious,youcanfind
morein-depthinformationaboutthemontheMDNatdeveloper.mozilla.org/
en-US/docs/Web/API/Element.
PreparingtheAnchorTagsforDuty
BeforeyoustartaddinginteractivefeatureswithJavaScript,youneedtomakeafew
updatestothemarkup.Yourthumbnailimagesarewrappedinanchortags,butthosetags
donotactuallylinktoanyresource.Instead,theyusethe#valueforthehrefattribute,
whichtellsthebrowsertostayonthesamepage.Inordertomakeaclickonathumbnail
doanythinginteresting,youneedtofixthat.
First,inindex.html,removeallbutfiveofthe.thumbnail-itemelements.Youno
longerneedtheduplicates,becauseyourlayoutisingoodshape.
Then,changetheanchortags’hrefpropertiestonolongerusethedummyvalue#.
Instead,setthevaluestobethesameaseach<img>tag’ssrcvalue.
Atomcanhelpyoumakethesechanges,takingthetediumoutofworkingwithHTML.
Likeanytexteditor,ithasawaytofindandreplacetext.SelectFind→FindinBufferoruse
thekeyboardshortcutCommand-F(Ctrl-F).ThiswillopentheFindinBufferpanelatthe
bottomoftheeditorwindow(Figure6.2).
Figure6.2UsingAtom’sfind-and-replacefeature
Enter“#”intheFindincurrentbuffertextboxand“img/otter.jpg”intheReplaceincurrentbuffer
textbox.ThenclickReplaceAllinthelowerright.
Thiswillchangeallofthe<ahref="#">tagsto<ahref="img/otter.jpg">.Nowitis
justamatterofmanuallyaddingtheappropriatenumbertoeachone(img/otter1.jpg,
img/otter2.jpg,etc.).
PresstheEscapekeytoclosetheFindinBufferpanel.index.htmlshouldlooklikethis:
...
<ulclass="thumbnail-list">
<liclass="thumbnail-item">
<ahref="#">
<ahref="img/otter1.jpg">
<imgclass="thumbnail-image"src="img/otter1.jpg"alt="">
<spanclass="thumbnail-title">Barry</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="#">
<ahref="img/otter2.jpg">
<imgclass="thumbnail-image"src="img/otter2.jpg"alt="">
<spanclass="thumbnail-title">Robin</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="#">
<ahref="img/otter3.jpg">
<imgclass="thumbnail-image"src="img/otter3.jpg"alt="">
<spanclass="thumbnail-title">Maurice</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="#">
<ahref="img/otter4.jpg">
<imgclass="thumbnail-image"src="img/otter4.jpg"alt="">
<spanclass="thumbnail-title">Lesley</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="#">
<ahref="img/otter5.jpg">
<imgclass="thumbnail-image"src="img/otter5.jpg"alt="">
<spanclass="thumbnail-title">Barbara</span>
</a>
</li>
</ul>
...
Next,youneedtoaddadditionalpropertiestoyouranchorelementssoyoucanaccess
themusingJavaScript.WhenstylingwithCSS,youuseclassnameselectorstoreferto
elementsonthepage.ForJavaScript,youusedataattributes.
DataattributesarejustliketheotherHTMLattributesyouhavebeenusingexceptthat,
unlikeattributessuchassrcorhref,dataattributesdonothavespecialmeaningtothe
browser.Theonlyrequirementisthattheattributenamestartswithdata-.Usingcustom
dataattributesletsyoudesignatewhatHTMLelementsonthepageyourJavaScript
interactswith.
Technically,inJavaScript,youcouldaccesselementsonthepageusingclassnames.
Likewise,youcouldusedataattributesinyourselectorsforstyling.Butyoureallyshould
not.YourcodewillbemuchmoremaintainableifyourJavaScriptandyourCSSdonot
relyonthesameattributes.
Updateyouranchortagsinindex.htmlwithdataattributes.Notethatthelinebreaksin
thecodebelowhavebeenaddedtomakesurethateverythingfitsnicelyonthepage.You
arefreetoaddthemornot,asyouprefer.Theywillnotmakeadifferencetothebrowser.
...
<liclass="thumbnail-item">
<ahref="img/otter1.jpg"data-image-role="trigger"
data-image-title="Stayin'Alive"
data-image-url="img/otter1.jpg">
<imgclass="thumbnail-image"src="img/otter1.jpg"alt="">
<spanclass="thumbnail-title">Barry</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="img/otter2.jpg"data-image-role="trigger"
data-image-title="HowDeepIsYourLove"
data-image-url="img/otter2.jpg">
<imgclass="thumbnail-image"src="img/otter2.jpg"alt="">
<spanclass="thumbnail-title">Robin</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="img/otter3.jpg"data-image-role="trigger"
data-image-title="YouShouldBeDancing"
data-image-url="img/otter3.jpg">
<imgclass="thumbnail-image"src="img/otter3.jpg"alt="">
<spanclass="thumbnail-title">Maurice</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="img/otter4.jpg"data-image-role="trigger"
data-image-title="NightFever"
data-image-url="img/otter4.jpg">
<imgclass="thumbnail-image"src="img/otter4.jpg"alt="">
<spanclass="thumbnail-title">Lesley</span>
</a>
</li>
<liclass="thumbnail-item">
<ahref="img/otter5.jpg"data-image-role="trigger"
data-image-title="ToLoveSomebody"
data-image-url="img/otter5.jpg">
<imgclass="thumbnail-image"src="img/otter5.jpg"alt="">
<spanclass="thumbnail-title">Barbara</span>
</a>
</li>
...
Adddataattributesforthedetailimage,aswell:
...
<divclass="detail-image-container">
<divclass="detail-image-wrapper">
<imgclass="detail-image"data-image-role="target"src="img/otter1.jpg"alt="">
<spanclass="detail-image-title"data-image-role="title">Stayin'Alive</span>
</div>
</div>
...
YourJavaScriptcodecanrefertothesedataattributestoaccessspecificelementsonthe
pagebecausethebrowserletsyouuseJavaScripttomakequeriesaboutthecontentsofa
webpage.Forexample,youcanqueryforanyelementsthatmatchaselector,suchas
data-image-role="trigger".Ifthequeryfindsmatches,itwillreturnreferencestothe
matchingelements.
Whenyouhaveareferencetoanelement,youcandoallsortsofthingswiththeelement.
Youcanreadorchangethevaluesofitsattributes,changethetextinsideofit,andeven
getaccesstotheelementsaroundit.Whenyoumakechangestoanelementusinga
reference,thebrowserupdatesthepageimmediately.
Inthischapter,youwillwriteJavaScriptcodethatwillgetreferencestotheanchorand
detailimageelements,readthevaluesfromtheanchorsdataattributes,andthenchange
thevalueofthedetailimage’ssrcattribute.ThisishowyouwillmakeOttergram
interactive.
Youmayhavenoticedthattheanchortagsandthedetailimage’s<img>tagallhavea
data-image-roleattribute,buttheirvaluesaredifferent.
Usingthesamedataattributenamesfortheanchorand<img>tagsisnotrequired,butitis
agoodpractice.Itremindsyou,thedeveloper,thattheseelementswillbepartofthesame
JavaScriptbehavior.
OnelastchangeisneededinyourHTMLbeforeyoubeginworkonyourJavaScript:You
needtotelltheHTMLtoruntheJavaScript.Dothisbyaddinga<script>tagin
index.html.This<script>tagwillrefertothefilescripts/main.js,whichyou
willcreateinjustamoment.
...
</div>
</div>
</main>
<scriptsrc="scripts/main.js"charset="utf-8"></script>
</body>
</html>
Whenthebrowserseesa<script>tag,itbeginsrunningthecodeinthereferencedfile
immediately.JavaScriptcannotaccessanelementwithinyourHTMLbeforeithasbeen
renderedbythebrowser,soputtingthe<script>tagatthebottomofthebodyensures
thatyourJavaScriptdoesnotrununtilafterallthemarkuphasbeenparsed.
YourHTMLisnowreadytoconnectwiththeJavaScriptyouareabouttowrite.Besureto
saveindex.htmlbeforeyoumoveon.
YourFirstScript
Timetocreateascriptsfolderandthemain.jsfile.Recallthatyoucancreate
foldersfromwithintheAtomeditor.Control-click(right-click)ottergraminthelefthand
panelandclickNewFolderinthepop-up.Enterthenamescriptsinthepromptthat
appears.
Then,Control-click(right-click)scriptsinthelefthandpanelandchooseNewFile.The
promptwillpre-fillthetextscripts/.Afterthis,entermain.jsandpressReturn.
MakesureyourfolderstructurelookslikeFigure6.3.
Figure6.3Ottergramfolderstructure
Thenamemain.jsdoesnothaveanyspecialsignificanceforthebrowser,butitisa
commonconventionusedbymanyfront-enddevelopers.
OnelastthingbeforeyoudiveintoJavaScript.Youneedtostartbrowser-sync,andtodo
soyouneedtochangethecommandyouhavebeenusingslightly:
browser-syncstart--server--browser"GoogleChrome"
--files"*.html,stylesheets/*.css,scripts/*.js"
Youaddedthepathscripts/*.jstothelistoffilessothatbrowser-syncwillwatchfor
changestotheJavaScriptaswellastheHTMLandCSS.
OverviewoftheJavaScriptforOttergram
Beforeyoustartcoding,itisalwaysgoodtohaveaplan.HereistheplainEnglishversion
ofwhatyouneedtodowithOttergram.
1. Getallthethumbnails.
2. Listenforaclickoneachone.
3. Ifaclickoccurs,updatethedetailimagewithinfofromthatthumbnail.
Youcanbreakdown#3intothreesubparts:
1. GettheimageURLfromthethumbnail’sdataattribute.
2. Getthetitletextfromthethumbnail’sdataattribute.
3. Settheimageandtitleonthedetailimage.
Hereisthatsameplanexpressedasadiagram(Figure6.4)
Figure6.4PlanofattackforOttergram
Thischapterwillwalkyouthroughcreatingthecodestartingwiththelaststep.Thisisthe
“bottom-up”approach,anditworkswellwhenwritingJavaScript.
DeclaringStringVariables
YourfirstJavaScripttaskistocreatestringvariablesforeachofthedataattributesyou
addedtothemarkup.(Ifthoseareunfamiliarterms,donotworry–wewillexplaininjust
amoment.)
Atthetopofmain.js,startbyaddingavariablenamedDETAIL_IMAGE_SELECTORand
assigningitthestring'[data-image-role="target"]'.
varDETAIL_IMAGE_SELECTOR='[data-image-role="target"]';
Thismightnotbemuchcode,butitisworthacloserlook.Let’sstartinthemiddle,with
the=symbol.Thisistheassignmentoperator.Unlikeinmathematics,the=symbolin
JavaScriptdoesnotmeanthattwothingsareequal.Instead,itmeans“Takethevalueon
therighthandsideandgiveitthenameonthelefthandside.”
Ontherighthandsideofthisparticularassignmentisastringoftext:'[data-image-
role="target"]'.Astringisjustasequenceofcharactersrepresentingtext,anditis
delimitedbysinglequotationmarks.Thetextinsidethesinglequoteshappenstobethe
attributeselectorforyourdetailimage.Thisisacluethatyouwillusethisstringtoaccess
thatelement.
Onthelefthandsideoftheassignmentisavariabledeclaration.Itmaybeusefultothink
ofavariableasalabelthatyoucanusetorefertosomevalue,whichcouldbeanumeric
value,astring(asinthiscase),orsomeothertypeofvalue.Usingthevarkeyword,you
arecreatingavariablenamedDETAIL_IMAGE_SELECTOR.
Next,declarevariablesinmain.jsforthedetailtitleselectorandthethumbnailanchor
selector.Assignthestringsfortheseselectorsaswell.
varDETAIL_IMAGE_SELECTOR='[data-image-role="target"]';
varDETAIL_TITLE_SELECTOR='[data-image-role="title"]';
varTHUMBNAIL_LINK_SELECTOR='[data-image-role="trigger"]';
Asthenamevariablesuggests,theirvaluescanbereassigned–theycanvary.Writing
variablenamesinallcapitallettersisaconventionthatdeveloperssometimesusewhen
thevaluesshouldnotchange.Otherlanguageshaveconstantsthatservethispurpose.
JavaScriptisintransition:ES5doesnothaveconstants;ES6does–but,aswesaidearlier,
itisnotyetfullysupported.Untilconstantsbecomewellsupported,youcanfollowthis
conventiontolabelavaluethatshouldnotchange.
Asanaside,stringscanbedelimitedbysingleordoublequotes.Youarefreetouseeither,
butthisbookwillusesinglequotesasaconventionandwesuggestthatyoufollowalong
atleastfortheprojectsinthisbook.
Ifyouwanttousedoublequotes,youhavetoescapeanydoublequotesthatarepartofthe
stringsothatthebrowserdoesnotincorrectlyparsethemaspartofthecode.Toescapea
character,youprecedeitwithabackslash,likethis:
varDETAIL_IMAGE_SELECTOR="[data-image-role=\"target\"]";
Usingsinglequotesisnotaguaranteethatyouwillnotneedtoescapecharacters.Ifa
stringdelimitedbysinglequotescontainssinglequotes–orapostrophes–youhaveto
escapethem.
Savemain.js.Withthesevariablesinhand,let’stakethemforaspininChromes
DevTools.
WorkingintheConsole
OneofthemostusefulpartsoftheDevToolsistheconsole,whichletsyouenter
JavaScriptcodeandevaluateitimmediately.Thisisespeciallyusefulforiteratively
developingJavaScriptcodethatmakeschangestoapage.
IntheDevTools,clickontheConsoletab,totherightoftheElementstab(Figure6.5).
Figure6.5Choosingtheconsoletab
Theconsolehasapromptwhereyoucanenterlinesofcode.Clicktotherightofthe
symbolsothattheconsoleisreadyforinput(Figure6.6).
Figure6.6Theconsole,readyforinput
Typethefollowingmathexpressionintotheconsole:
137+349
PresstheReturnkey.Theconsolewillprintouttheresult(Figure6.7).
Figure6.7Evaluatingamathexpression
Theconsole’smainjobistotellyou,inthesimplestterms,thevalueofthecodeyouenter.
Aswithmanythingsinlife,ordermatters.Ifyouneedcertainitemstobeevaluatedasa
group,youcanwrapparenthesesaroundthem.(Thisismucheasierthanmemorizingthe
orderinwhichJavaScriptwoulddothiswithouttheparentheses.)Enterthefollowing
expressionintheconsole.
3*((2*4)+(3+5))
PresstheReturnkey,andtheconsolewillcrunchthenumbersinthecorrectorder
(Figure6.8).(Bytheway,althoughwehaveaddedspacesbetweenthenumbersand
operatorsforthesakeofreadability,youdonotneedtoincludethem.Theconsoledoes
notcare.)
Figure6.8Evaluatingamorecomplexmathexpression
Now,ontousingyourvariables.Youcanclearthecontentsoftheconsolebypressingthe
iconintheupperleftoftheconsolepanelorwiththekeyboardshortcutCommand-K
(Ctrl-K).
StarttypingDETAIL_IMAGE_SELECTOR.Asyoutypethefirstfewletters,youcanseethat
theconsolealreadyknowsaboutthevariablesyoucreatedandprovidesalistof
autocompletesuggestions(Figure6.9).
Figure6.9Theconsole’sautocompletemenu
PresstheTabkeyandlettheconsoleautocompletethevariablenameforyou.Whenyou
presstheReturnkey,theconsolereportsthatthevalueofDETAIL_IMAGE_SELECTORisthe
string"[data-image-role="target"]".
Figure6.10Theconsoleprintingavariable’svalue
(Theconsolealwaysprintsstringswithdoublequotes,eventhoughyouactuallyused
singlequotesinmain.js.)
StringsareoneoffiveprimitivevaluetypesinJavaScript.(NumbersandBooleansaretwo
oftheothers.)Theyare“primitive”becausetheyrepresentsimplevalues.Thisisin
contrasttomorecomplexvaluesinJavaScript,whichyouwilllearnaboutnext.
AccessingDOMElements
Youhavejustseenthattheconsolegivesyouaccesstothevariablesyoucreated.Earlier
wesaidthatthesevariablescouldbeusedforaccessingelementsonthepage.Youcantry
thatnow.Enterthefollowingintheconsole:
document.querySelector(DETAIL_IMAGE_SELECTOR);
PresstheReturnkey.ItwillshowyoutheHTMLforthedetailimage.Hoveroverthis
HTMLintheconsole.Youwillseethatthedetailimageishighlightedonthepage,justas
ifyouclickedHTMLintheelementspanel(Figure6.11).
Figure6.11HTMLintheconsolecorrespondstoanelementonthepage
Inthelineofcodeyouwroteontheconsole,theworddocumentisthevariablebuiltinto
thebrowserthatgivesyouaccesstothewebpage.Itsvalueisnotoneoftheprimitive
types.Itisacomplexvalue,whosetypeisobject.
Thedocumentobjectcorrespondstotheentirepage.Itgivesyouaccesstoanumberof
methodsforgettingreferencestoelementsonthepage.Methodsareatypeoffunction
(theyarefunctionswithanexplicitlydesignatedowner,butyoudonotneedtoworry
aboutthatdetailrightnow)–alistofstepsforthebrowsertofollow.Youusedthe
querySelectormethodinthelineyouenteredintheconsole.Thedotoperator(i.e.,
theperiod)indocument.querySelectorishowyouaccessanobject’smethods.
YouaskedthedocumenttouseitsquerySelectormethodtofindanyelement
matchingthestring'[data-image-role="target"]'.querySelectorrespondedwith
areferencetotheelementthatitfound,thedetailimage(Figure6.12).
Figure6.12Accesstothepageprovidedbydocumentand
document.querySelector
Andnow,abitofterminology.Youdidnotreally“ask”thepageformatchingelements.
YoucalledthedocumentsquerySelectormethodandyoupasseditastring.The
methodreturnedareferencetothedetailimageelement.
Whenyoucallamethod,youaremakingitrunwhatevertaskitwasdesignedtoperform.
Youwilloftenneedtopassitinformationitneedstodothattask,whichyouplacein
parenthesesafterthemethod’sname.Then,inadditiontoitsassignedtasks,themethod
mayreturnavaluethatyoucanuse.
RememberthatDETAIL_IMAGE_SELECTORwasassignedthevalue'[data-image-
role="target"]',whichmeansthatthisiswhatispassedtoquerySelector.
Behindthescenes,querySelectorusesthisstringtosearchforanyelementsthat
matchthatselector.Whenitsearches,thedocumentisnotactuallysearchingthepage,itis
searchingthedocumentobjectmodel,orDOM.TheDOMisthebrowsersinternal
representationofanHTMLdocument.Itbuildsthisrepresentationasitreadsthroughand
interpretstheHTML.
InJavaScript,youcaninteractwiththeDOMusingthedocumentobjectanditsmethods,
suchasquerySelector.ForeachHTMLtag,thereisacorrespondingelementinthe
DOM,andyoucaninteractwithanyoftheseelementsusingJavaScript.(Generally,when
werefertoan“element,”wemeana“DOMelement.”)
Intheconsole,calldocument.querySelectoragain,passingit
DETAIL_IMAGE_SELECTORtogetareferencetotheelementforthedetailimage.Butthis
time,assignthereferencetoanewvariablenameddetailImage:
vardetailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);
PressReturn,andtheconsolewillprintundefined(Figure6.13).Donotpanic!Thisisnot
anerror.
Figure6.13Declaringavariableintheconsole
Theconsoleisjustdoingitsjob,tellingyouthatthereisnoresultingvaluefromdeclaring
avariable.InJavaScript,theabsenceofavalueisrepresentedbythekeywordundefined.
ThatdoesnotmeanthatyourdetailImagevariablewasnotassigned.Tocheckit,just
typedetailImageintheconsoleandpressReturn.YouwillseetheHTML
representationofthedetailimage,justasyousawwhenyouentered
document.querySelector(DETAIL_IMAGE_SELECTOR)(Figure6.14).
Figure6.14CheckingthevalueofdetailImage
Whatisthepointofallthis?Byassigningareferencetoavariable,youcanusethe
variablenameanytimeyouwanttorefertotheelement.Now,insteadofhavingtotype
document.querySelector(DETAIL_IMAGE_SELECTOR)everytime,youcanjusttype
detailImage.
Whenyouhaveareferencetothedetailimage,itiseasytochangethevalueofitssrc
attribute.Intheconsole,assigndetailImage.srctothestring'img/otter2.jpg'.
detailImage.src='img/otter2.jpg';
Usingthedotoperator,youaccessedthesrcpropertyofthedetailImageobject.A
propertyislikeavariable,butitbelongstoaparticularobject.Whenyouassign(orset)
srctothestring'img/otter2.jpg',youwillseethatadifferentotteroccupiesthedetail
imagearea(Figure6.15).
Figure6.15Settingthesrcpropertyofthedetailimage
Thesrcpropertycorrespondstothesrcattributeofthe<img>taginindex.html.
Becauseofthisrelationship,anotherwaytoachievethesameresultistousethe
detailImagessetAttributemethod.
Callthismethodintheconsoleandpassittwostrings:thenameoftheattributeandthe
newvalue.
detailImage.setAttribute('src','img/otter3.jpg');
Thedetailimagechangesonceagain(Figure6.16).
Figure6.16UsingsetAttributetochangetheimage
Younowhaveallthepiecesyouneedtocreateanautomatedwaytochangethedetail
image.Getreadytowriteyourfirstfunction!
WritingthesetDetailsFunction
Youhavebeenworkingwithmethodsandhaveseenthattheycanbeinvokedtocausea
blockofcodetorun.Functionsandmethodsarereallyjustalistofstepsthatyouwould
liketouseagainandagain.Callingafunctionislikesaying“Makeasandwich”insteadof
“Layouttwoslicesofbread.Putprosciutto,salami,andprovoloneononeslice.Putthe
othersliceofbreadontop.”
YouwillwritesevenfunctionsforOttergraminthischapter.Yourfirstfunctionwilldo
twothings:changethedetailimageandthedetailimagetitle.Addthisfunction
declarationtomain.js.
varDETAIL_IMAGE_SELECTOR='[data-image-role="target"]';
varDETAIL_TITLE_SELECTOR='[data-image-role="title"]';
varTHUMBNAIL_LINK_SELECTOR='[data-image-role="trigger"]';
functionsetDetails(){
'usestrict';
//Codewillgohere
}
YoudeclaredafunctionnamedsetDetailsusingthefunctionkeyword.When
declaringafunction,thenameisalwaysfollowedbyapairofparentheses.Theyarenot
partofthename,however–youwillfindoutwhattheyareforsoon.
Aftertheparenthesesisapairofcurlybraces.Insidethecurlybracesisthebodyofthe
function.Thebodywillcontainthestepsthefunctionneedstoperform.Thesestepsare
moreformallyreferredtoasstatements.
Thefirstlineofyourfunctionisthestring'usestrict';.Youwillusethisstringatthe
beginningofallyourfunctionstotellthebrowserthattheyconformtothemostrecent
standardversionofJavaScript.(ThereismoreaboutstrictmodeinaFortheMoreCurious
sectionattheendofthischapter.)
TheotherlineinthesetDetailsfunctionisacomment.LikeCSScomments,
JavaScriptcommentsareignoredbythebrowserbutusefulfordevelopers.JavaScript
commentsthatareonlyonelinecanbewrittenthisway,with//.Forcommentsthatspan
multiplelines,youcanusethe/**/style.BotharecorrectinJavaScript.
Intheconsole,youhavealreadytriedoutallofthestatementsneededtochangethephoto
inthedetailimage.GobacktotheconsoleandpresstheUparrowkey.Youwillseethe
mostrecentstatementyouenteredcopiedattheprompt.TheUpandDownarrowsallow
youtogobackwardandforwardthroughyourhistoryofstatements.
Usingthearrowkeys,findthestatementthatgetsareferencetothedetailimage:var
detailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);.Copythisline
fromtheconsoleandpasteitintomain.jsinplaceofthecomment.Then,copyand
pastethelineintheconsolethatcallsthedetailImage.setAttributemethod:
detailImage.setAttribute('src','img/otter3.jpg');.
YoursetDetailsfunctioninmain.jsshouldlooklikethis:
...
functionsetDetails(){
'usestrict';
//Codewillgohere
vardetailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);
detailImage.setAttribute('src','img/otter3.jpg');
}
Savemain.jsandgobacktotheconsole.EnterthefollowingandpressReturntorun
yoursetDetailsfunction.
setDetails();
Entering–orcalling–thenameofafunctionfollowedimmediatelybyparenthesesmakes
thefunctionexecuteallofthecodeinitsbody.Youshouldseethatimg/otter3.jpgis
nowdisplayedasthedetailimage(Figure6.17).
Figure6.17RunningsetDetailstochangetheimage
setDetailshaschangedthedetailimage,butnotthedetailimagetitle.Youwantitto
doboth.Asyoudidwiththedetailimage,youwilladdstatementstogetareferencetothe
elementandtochangetheelement’sproperties.
InyoursetDetailsfunctioninmain.js,calldocument.querySelectoragain,
passingitDETAIL_TITLE_SELECTOR.Assigntheresulttoanewvariablenamed
detailTitle.Then,setitstextContentpropertyto'YouShouldBeDancing'.
...
functionsetDetails(){
'usestrict';
vardetailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);
detailImage.setAttribute('src','img/otter3.jpg');
vardetailTitle=document.querySelector(DETAIL_TITLE_SELECTOR);
detailTitle.textContent='YouShouldBeDancing';
}
ThetextContentpropertyisthetext(notincludingHTMLtags)insideofanelement.
SaveyourchangesandrunsetDetailsintheconsole.Nowtheimageandtitlechange
(Figure6.18).
Figure6.18ChangingtheimageandtitleusingsetDetails
Acceptingargumentsbydeclaringparameters
setDetailsdoestheworkofchangingthedetailimageandtitle.Buteverytimeyou
runit,itsetstheimage’ssrcto'img/otter3.jpg'andthetitle’stextContentto'You
ShouldBeDancing'.Whatifyouwanttouseotherimagesandtext?
YouneedawaytotellsetDetailswhichimageandwhattexttousewhenyoucallit.
Toachievethis,youneedyourfunctiontoacceptarguments–valuesthatarepassedtothe
functionandthatitcanworkwith.Andtodothat,youhavetospecifyparametersinthe
functiondeclaration.
AddtwoparameterstosetDetailsinmain.js:
...
functionsetDetails(imageUrl,titleText){
'usestrict';
vardetailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);
detailImage.setAttribute('src','img/otter3.jpg');
vardetailTitle=document.querySelector(DETAIL_TITLE_SELECTOR);
detailTitle.textContent='YouShouldBeDancing';
}
Now,usethoseparametersinplaceof'img/otter3.jpg'and'YoushouldBe
Dancing':
...
functionsetDetails(imageUrl,titleText){
'usestrict';
vardetailImage=document.querySelector(DETAIL_IMAGE_SELECTOR);
detailImage.setAttribute('src','img/otter3.jpg');
detailImage.setAttribute('src',imageUrl);
vardetailTitle=document.querySelector(DETAIL_TITLE_SELECTOR);
detailTitle.textContent='YouShouldBeDancing';
detailTitle.textContent=titleText;
}
Yourtwoparameters,imageUrlandtitleText,areusedaslabelsassignedtovalues
passedtosetDetails.Savemain.jsandtryitoutintheconsoletoseethisworking.
CallsetDetailsandpassitthevalues'img/otter4.jpg'and'NightFever'.(Make
surethereisacommabetweenthem.)
setDetails('img/otter4.jpg','NightFever');
Youshouldseethenewimageandtitletext,asinFigure6.19.
Figure6.19PassingvaluestosetDetails
Thereisanimportantdistinctionbetweenargumentsandparameters.Parametersare
definedaspartofthefunction.InJavaScript,parametersareexactlylikevariablesthatare
declaredinsideafunctionbody.Argumentsarevaluesyousupplytoafunctionwhenyou
callit.
Also,beawarethatnomatterwhatvariablenamesyouuseforyourarguments,their
valuesarealwaysmappedtotheparameternamessotheycanbeusedinsidethefunction
body.Forexample,imaginethatyouusedvariablesfortheimageURLandthetitletext.
WhenyoucallsetDetails,youpassinthesetwovariablesasarguments.
varotterOneImage='img/otter1.jpg';
varotterOneTitle='Stayin\'Alive';
setDetails(otterOneImage,otterOneTitle);
ThesetDetailsfunctionacceptsthevalues,labelsthemwiththeparameternames
imageUrlandtitleText,andthenrunsthecodeinsideitsbody.ThatcodeusesimageUrl
andtitleText,passingthemasargumentstodocument.querySelector.
Likevariablenames,parameternamesarejustlabelsforvalues.Youcanusewhatever
parameternamesyoulike,butitisgoodpracticetousedescriptivenames,asyouhave
donehere,tomakeyourcodeeasiertoreadandmaintain.
ReturningValuesfromFunctions
Youhavecompletedthefirst(or,rather,last)itemontheplanandpickedupsome
JavaScriptknow-howalongtheway.Nowyouwillmoveontothenexttwoitemsonthe
list:gettingtheimageandthetitlefromathumbnail.Foreachofthese,youwillwritea
newfunction.
Addafunctiondeclarationinmain.jsforimageFromThumb.Itwillacceptasingle
parameter,thumbnail,whichisareferencetoathumbnailanchorelement.Itwillretrieve
andreturnthevalueofthedata-image-urlattribute.
...
functionsetDetails(imageUrl,titleText){
...
}
functionimageFromThumb(thumbnail){
'usestrict';
returnthumbnail.getAttribute('data-image-url');
}
ThegetAttributemethoddoestheoppositeofthesetAttributemethodyou
usedinthesetDetailsfunction.Itonlytakesasingleargument,thenameofan
attribute.
UnlikesetDetails,theimageFromThumbfunctionusesthereturnkeyword.When
youcallafunctionthathasareturnstatement,itgivesyoubackavalue.
querySelectorisanexampleofthis.Whenyoucalledit,itreturnedavaluethatyou
thenassignedtoavariable.
Savemain.jsandtryoutthefollowingintheconsole,pressingReturnbetweenthe
lines.
varfirstThumbnail=document.querySelector(THUMBNAIL_LINK_SELECTOR);
imageFromThumb(firstThumbnail);
Theconsolereportsthatthevaluereturnedwasthestring"img/otter1.jpg",because
imageFromThumbreturnsthedata-image-urlofthethumbnail.
Figure6.20ValuereturnedfromimageFromThumb
Notethatanystatementsthatcomeafterareturnstatementwillnotberun.Areturn
statementeffectivelystopsarunningfunction.
Thenextfunctiontowriteisonethatwillacceptathumbnailelementreferenceandreturn
thetitletext.
Addafunctiondeclarationinmain.jsfortitleFromThumb,withathumbnail
parameter.Itwillreturnthevalueofthedata-image-titleattribute.
...
functionimageFromThumb(thumbnail){
...
}
functiontitleFromThumb(thumbnail){
'usestrict';
returnthumbnail.getAttribute('data-image-title');
}
Savemain.jsandtrythisfunctionoutintheconsole,too:
varfirstThumbnail=document.querySelector(THUMBNAIL_LINK_SELECTOR);
titleFromThumb(firstThumbnail);
Figure6.21ValuereturnedfromtitleFromThumb
Thenextfunctiontowritebringsthethreeotherfunctionstogetherforconvenience,so
thatyoudonotneedtocallthemseparately.Itwillacceptareferencetoathumbnail
elementandthencallsetDetails,passinginthevaluesfromcalling
imageFromThumbandtitleFromThumb.
AddsetDetailsFromThumbinmain.js.
...
functiontitleFromThumb(thumbnail){
...
}
functionsetDetailsFromThumb(thumbnail){
'usestrict';
setDetails(imageFromThumb(thumbnail),titleFromThumb(thumbnail));
}
NoticethatsetDetailsisbeingcalledwithtwoarguments–andthoseargumentsare
functioncalls,too.Howdoesthiswork?
BeforesetDetailsisactuallycalled,itsargumentsarereducedtotheirsimplest
values.First,imageFromThumb(thumbnail)runsandreturnsavalue.Then,
titleFromThumb(thumbnail)runsandreturnsavalue.Finally,setDetailsis
calledwiththevaluesreturnedbyimageFromThumb(thumbnail)and
titleFromThumb(thumbnail).Figure6.22showsthisprocess.
Figure6.22Functioncallsasarguments
Savemain.js.Youhavecompletedallthecodeforretrievingdata-attributevaluesfrom
thumbnailsandusingthosevaluestoupdatewhatisshowninthedetailimageandtitle.
Movingupfromthelow-leveloperations,thenextthingtodoiswritecodethatwill
performyourdatatransferfromthumbnailtodetailwhentheuserclicksathumbnail.
AddinganEventListener
Browsersarebusypiecesofsoftware.Everytap,click,scroll,andkeystrokeisnoticedby
thebrowser.Eachoftheseisaneventthatthebrowsermayrespondto.Tomakewebsites
moredynamicandinteractive,youcantriggeryourowncodewhenoneoftheseevents
occurs.Inthissection,youwilladdeventlistenerstoeachofyourthumbnails.
Aneventlistenerisanobjectthat,asthenamesuggests,“listens”foraparticularevent,
suchasamouseclick.Whenitsassignedeventoccurs,theeventlistenertriggersa
functioncallinresponsetotheevent.
(Mouseevents,likeclicksanddouble-clicks,andkeyboardeventslikekeypressesare
amongthemostcommoneventtypes.Foracompletelistingofevents,checktheevent
referenceintheMDNatdeveloper.mozilla.org/en-US/docs/Web/
Events.)
TheaddEventListenermethodisavailableoneveryDOMelement,includingthe
document.Asbefore,youwillexperimentwithsomecodeintheconsolefirstandthenuse
yourtestedcodetowritefunctionsinmain.js.
SwitchtoChromeandenterthefollowingcodeintheconsole.YouwillneedtopressShift-
Returntoenterthelinebreaks.PressReturnwhenyouhavefinishedtypingallthecode.
document.addEventListener('click',function(){
console.log('youclicked!');
});
Thecodeyouenteredaddedaneventlistenerforthedocumentobjectthatislisteningfor
anyclicksthatoccuronthepage.Whenaclickhappens,theeventlistenerwillprint“you
clicked!”totheconsoleusingthebuilt-inconsole.logmethod(Figure6.23).
Figure6.23Addingalistenerforclickevents
Clickontheheader,thedetailimage,orthebackground.Youshouldseethatthetext“you
clicked!”appearsprintedintheconsole.(Donotclickthethumbnails–thosewilltake
youawayfromOttergram’sindex.htmlpage.Whenyouarenotontheindex.html
page,noneofyourmarkup,CSS,orJavaScriptwillbeloadedandrunninginthebrowser.)
addEventListeneracceptstwoarguments:astringwiththenameoftheeventanda
function.ThisfunctionwillberunbyaddEventListeneranytimetheeventoccurs
fortheelement.Thewaythisfunctioniswrittenmaylookalittlestrangeatfirst.Itisan
anonymousfunction.
Sofar,youhaveworkedwithnamedfunctions,likesetDetailsand
titleFromThumb.Namedfunctionshavenames–nosurprisethere–andarecreated
usingfunctiondeclarations.
Youcanalsowriteliteralfunctionvalues,thesamewayyoucanwriteliteralnumber
valueslike42andliteralstringvalueslike"BarrytheOtter".Anothernameforliteral
functionvaluesisanonymousfunctions.
Anonymousfunctionsarefrequentlyusedasargumentstootherfunctions,liketheone
youpassedasthesecondargumenttodocument.addEventListener.Thispractice
ofpassingafunctiontoanotherfunctionisquitecommoninJavaScriptandisknownasa
callbackpatternbecausethefunctionyoupassinasanargumentwillget“calledback”at
somepointinthefuture.
Itisperfectlyfinetouseanamedfunctionasacallback,butmanyfront-enddevelopers
willuseanonymousfunctionsbecausetheycanprovidemoreflexibilitythannamed
functions.Youwillseehowthisworksshortly.
Nowyouwilladdaneventlistenerforanindividualthumbnail.Enterthefollowinginthe
console.(RemembertouseShift-Returnforthelinebreaksinthecallto
firstThumbnail.addEventListener.)
varfirstThumbnail=document.querySelector(THUMBNAIL_LINK_SELECTOR);
firstThumbnail.addEventListener('click',function(){
console.log('youclicked!');
});
Ifyoutryclickingthefirstthumbnail(BarrytheOtter,farthesttotheleft),yourbrowser
willtakeyoutothelargeimageofBarry.Whathappened?Rememberthateachthumbnail
iswrappedinananchortagwithanhrefthatpointstoanimage,like
img/otter1.jpg.Thisisthenormalbehaviorofabrowserwhenauserclicksalink:
Ithasopenedthefileindicatedbythehrefattribute.
ButyoudonotwanttonavigateawayfromOttergramwhenathumbnailisclicked,and
youshouldnothavetochangeyouranchortagstosomethingelse.Luckily,youcan
handleallofthisfromyourcallbackfunction.
Recallfromearlierinthechapterthatfunctionscarryouttheirtaskswithoutyouhavingto
worryaboutthedetails.Usuallyyouonlyneedtoknowwhatinformationtopassas
argumentsandwhatinformationwillbereturned.Whenyoupassacallbackfunctionasan
argument,thereisonemorethingyouneedtoknow:whatinformationwillbepassedto
yourcallback.
WhenyoucalladdEventListener,youaretellingthebrowser,“Whenthe
firstThumbnailisclicked,callthisfunction”–andthenthebrowserdiligentlywaitsfor
thatelementtobeclicked.Ifaclickhappens,thebrowsermakesnoteofallthedetails
abouttheevent(suchastheexactpositionofthemouse,whetheritwastheleftorright
mousebutton,andwhetheritwasasingleordoubleclick).Thebrowserthenpassesan
objectwiththisinformationtoyourfunction.Thisobjectisaneventobject.
ThisrelationshipisdiagrammedinFigure6.24,usingamade-upimplementationof
addEventListener.
Figure6.24Passingananonymousfunctionthatexpectsanargument
Inamoment,youwillpassananonymousfunctiontoaddEventListener,justlike
before.But,thistime,youranonymousfunctionwillexpecttoreceiveanargument.Make
sureOttergramisontheindex.htmlpageandenterthefollowingintheconsole:
varfirstThumbnail=document.querySelector(THUMBNAIL_LINK_SELECTOR);
firstThumbnail.addEventListener('click',function(event){
event.preventDefault();
console.log('youclicked!');
console.log(event);
});
ThebrowserwillcallyouranonymousfunctioneachtimefirstThumbnailisclicked,
anditwillpassyouranonymousfunctiontheeventobject.Usingthisobject(whichyou
havelabeledevent),youcallitspreventDefaultmethod.Thismethodwillstopthe
linkfromtakingthebrowsertoadifferentpage.Finally,youcallconsole.logonthe
eventobjectsothatyoucaninspectitintheDevTools.
Nowclickonthefirstthumbnail.YourbrowserremainsontheOttergrampageandthe
eventisloggedtotheconsole:MouseEvent{isTrusted:true}.Ifyouclickthe
disclosurearrownexttoMouseEvent,youshouldseequiteabitofinformationaboutthe
event(Figure6.25),includingthemousecoordinatesonthepage,whichmousebutton
wasclicked,andwhetheranyspecialmodifierkeyswerepressedduringtheclick.
Figure6.25Preventingtheeventdefaultandloggingtheeventobject
Fornow,donotfocusonthedifferentpropertiesoftheeventobject.Justknowthatit
carrieslotsofinformationaboutthebrowsereventthatwastriggered.
Bytheway,itisnotrequiredthatthecallbackfunction’sparameterbenamedevent–it
willbemappedtothevaluethatispassedinnomatterwhatyounameit.Youcanuse
whateverparameternamesyoulike,butitisgoodpracticetousedescriptivenames,as
youhavedonehere,tomakeyourcodeeasiertoreadandmaintain.
Younowhaveafunctionthatacceptsathumbnailandaddsaneventlistener.Adda
functiondeclarationtomain.jsforaddThumbClickHandler.Itshoulddefinea
parameternamedthumb.
YoucancopyyourexperimentaladdEventListenercodefromtheconsoleandpaste
itintothebodyofaddThumbClickHandler.Modifyitsothatyouarecalling
thumb.addEventListener.Fornow,youwillonlyneedthecallto
event.preventDefaultintheeventcallback.
...
functionsetDetailsFromThumb(thumbnail){
...
}
functionaddThumbClickHandler(thumb)
'usestrict';
thumb.addEventListener('click',function(event){
event.preventDefault();
});
}
Insidetheeventcallback,youhaveaccesstothethumbparameterdeclaredaspartof
addThumbClickHandler.PassittoacalltosetDetailsFromThumb.
...
functionaddThumbClickHandler(thumb){
'usestrict';
thumb.addEventListener('click',function(event){
event.preventDefault();
setDetailsFromThumb(thumb);
});
}
JavaScript,likemanyotherprogramminglanguages,hasrulesaboutdefiningand
accessingvariablesandfunctions.Theanonymousfunctionyoupassedto
addEventListenerisabletoaccessthesetDetailsFromThumbfunction
becausesetDetailsFromThumbwasdeclaredintheglobalscope.Thismeansthatit
canbeaccessedfromanyotherfunctionorfromtheconsole.Thesameistruefor
variableslikeDETAIL_IMAGE_SELECTOR,whichisalsodeclaredintheglobalscope.
However,thevariablesdetailImageanddetailTitle,whichyoudeclaredinside
setDetails,areonlyavailablewithinthebodyofsetDetails.Youcannotaccess
themfromtheconsoleorfromotherfunctions.Thesevariablesaredeclaredinthe
functionscope(orlocalscope)ofsetDetails.Afunction’sparametersworkvery
muchlikevariablesdeclaredinsideafunction.Theytooarepartofthatfunction’sscope.
Normally,functionscannotaccessvariablesorparametersthatarepartofanother
function’sscope.addThumbClickHandlerisinterestingbecauseitdefinesthe
parameterthumb,whichisaccessedbyanotherfunction–thecallbackfunctionyou
passedtoaddEventListener.Thisispossiblebecausethecallbackfunctionispartof
addThumbClickHandlersscope.
YoucanreadmoreabouthowallofthisworksinaFortheMoreCurioussectionatthe
endofthischapter.
AccessingAlltheThumbnails
Intheconsole,youaddedaneventlistenerforthefirstthumbnail.Nowyouwilladdan
eventlistenerforallofthethumbnails,usinganewDOMmethod.
Whenyouretrievedthedetailimageandthedetailtitle,youusedthe
document.querySelectormethodtosearchtheDOMforanelementthatmatched
theselectorpassedin.document.querySelectorwillonlyreturnasinglevalue,
evenifyoupassinaselectorthatmatchesmultipleelements.
Thedocument.querySelectorAllmethod,ontheotherhand,willreturnalistof
allmatchingelements.Calldocument.querySelectorAll(THUMBNAIL_LINK_SELECTOR)in
theconsoleandexaminetheresults.Youshouldseethelistofanchorelementresults
(Figure6.26).
Figure6.26document.querySelectorAllreturnsmultiplematching
elements
Knowingthis,youcantestsetDetailsFromThumbproperly.Intheconsole,assign
theresultofcallingdocument.querySelectorAll(THUMBNAIL_LINK_SELECTOR)toa
variablenamedthumbnails.Usebracketsyntaxtoretrievethefifthelementfromthe
thumbnailslist,passingittosetDetailsFromThumb.Bracketsyntaxletsyouspecify
aniteminthelistbyitsnumericalindex.Theindexstartsat0,sothefifthitemisatindex
4.
Hereisyourcodefortheconsole:
varthumbnails=document.querySelectorAll(THUMBNAIL_LINK_SELECTOR);
setDetailsFromThumb(thumbnails[4]);
Afterrunningthisintheconsole,youcanseethatanitemfromthethumbnailslistcanbe
passedtosetDetailsFromThumb,successfullyupdatingthedetailimageandtitle
(Figure6.27).
Figure6.27PassinganitemfromquerySelectorAllto
setDetailsFromThumb
Inmain.js,addafunctionnamedgetThumbnailsArrayandpasteinthecodethat
retrievesallmatchingelementsforTHUMBNAIL_LINK_SELECTORandassignstheresulttoa
thumbnailsvariable.
...
functionaddThumbClickHandler(thumb){
...
}
functiongetThumbnailsArray(){
'usestrict';
varthumbnails=document.querySelectorAll(THUMBNAIL_LINK_SELECTOR);
}
Beforeyougoanyfurther,thereisasmall“gotcha”whenworkingwithDOMmethods.
Methodsthatreturnlistsofelementsdonotreturnarrays.Instead,theyreturnNodeLists.
BotharraysandNodeListsarelistsofitems,butarrayshaveanumberofpowerful
methodsforworkingwithcollectionsofitems,someofwhichyouwillwantfor
Ottergram.
YouwillneedtoconverttheNodeListreturnedfromquerySelectorAlltoanarray
usinganodd-lookingbitofJavaScript.Donotworryaboutthissyntaxrightnow.Itisa
backward-compatiblewaytoconvertfromaNodeListtoanarray.Makethischangein
main.js:
...
functiongetThumbnailsArray(){
'usestrict';
varthumbnails=document.querySelectorAll(THUMBNAIL_LINK_SELECTOR);
varthumbnailArray=[].slice.call(thumbnails);
returnthumbnailArray;
}
Now,armedwithalloftheotterthumbnails,youcanconnectthemtoyoureventlistening
code,whichwillchangethedetailimageandtitleinresponsetoaclick.
IteratingThroughtheArrayofThumbnails
Connectingthethumbnailstoyoureventhandlingcodewillbeshortandsweet.Youwill
writeafunctionthatwillbethestartingpointforallofOttergram’slogic.Other
programminglanguageshaveabuilt-inmechanismforstartinganapplication,which
JavaScriptlacks.Butnottoworry–itiseasyenoughtoimplementbyhand.
BeginbyaddinganinitializeEventsfunctionattheendofmain.js.This
methodwilltietogetherallofthestepsformakingOttergraminteractive.First,itwillget
thearrayofthumbnails.Then,itwilliterateoverthearray,addingtheclickhandlerto
eachone.Afteryouhavewrittenthefunction,youwilladdacallto
initializeEventsattheveryendofmain.jstorunit.
Inthebodyofyournewfunction,addacalltogetThumbnailsArrayandassignthe
result(thearrayofthumbnails)toavariablenamedthumbnails.
...
functiongetThumbnailsArray(){
...
}
functioninitializeEvents(){
'usestrict';
varthumbnails=getThumbnailsArray();
}
Next,youneedtogothroughthearrayofthumbnails,oneitematatime.Asyouvisiteach
one,youwillcalladdThumbClickHandlerandpassthethumbnailelementtoit.That
mayseemlikeseveralsteps,butbecausethumbnailsisaproperarray,youcandoallof
thiswithasinglemethodcall.
Addacalltothethumbnails.forEachmethodinmain.jsandpassitthe
addThumbClickHandlerfunctionasacallback.
...
functioninitializeEvents(){
'usestrict';
varthumbnails=getThumbnailsArray();
thumbnails.forEach(addThumbClickHandler);
}
Notethatyouarepassinganamedfunctionasacallback.Asyouwillreadlater,thisisnot
alwaysagoodchoice.However,inthiscaseitworkswell,because
addThumbClickHandleronlyneedsinformationthatwillbepassedtoitwhen
forEachcallsit–anitemfromthethumbnailsarray.
Finally,toseeeverythinginaction,addacalltoinitializeEventsattheveryendof
main.js.
...
functioninitializeEvents(){
'usestrict';
varthumbnails=getThumbnailsArray();
thumbnails.forEach(addThumbClickHandler);
}
initializeEvents();
Remember,asthebrowserreadsthrougheachlineofyourJavaScriptcode,itrunsthe
code.Formostofmain.js,itisonlyrunningvariableandfunctiondeclarations.But
whenitreachesthelineinitializeEvents();,itwillrunthatfunction.
Saveandreturntothebrowser.Clickafewdifferentthumbnailsandseethefruitsofyour
labor(Figure6.28).
Figure6.28Youshouldindeedbedancing
Sitback,relax,andenjoyclickingsomeotters!Therewasalottoworkthroughand
absorbwhilebuildingyoursite’sinteractivelayer.Inthenextchapteryouwillfinish
Ottergrambyaddingvisualeffectsforextrapop.
SilverChallenge:LinkHijack
TheChromeDevToolsgiveyoualotofpowerfortoyingwithpagesthatyouvisit.This
nextchallengeistochangeallofthelinksonasearchresultspagesothattheydonotgo
anywhere.
Gotoyourfavoritesearchengineandsearchfor“otters.”OpentheDevToolstothe
console.WiththefunctionsyouwroteinOttergramasareference,attacheventlistenersto
allofthelinksanddisabletheirdefaultclickfunctionality.
GoldChallenge:RandomOtters
Writeafunctionthatchangesthedata-image-urlofarandomotterthumbnailsothatthe
detailimagenolongermatchesthethumbnail.UsetheURLofanimageofyourchoosing
(thoughawebsearchfor“tacocat”shouldprovideagoodone).
Foranextrachallenge,writeafunctionthatresetsyourotterthumbnailstotheiroriginal
data-image-urlvaluesandchangesanotheroneatrandom.
FortheMoreCurious:StrictMode
Whatisstrictmode,andwhydoesitexist?ItwascreatedasacleanermodeofJavaScript,
catchingcertainkindsofcodingmistakes(liketyposinvariablenames),steering
developersawayfromsomeerror-pronepartsofthelanguage,anddisablingsome
languagefeaturesthatarejustplainbad.
Strictmodeprovidesanumberofbenefits.It:
enforcestheuseofthevarkeyword
doesnotrequirewithstatements
placesrestrictionsonthewaytheevalfunctioncanbeused
treatsduplicatenamesinafunction’sparametersasasyntaxerror
Allthisjustforaddingthe'usestrict'directivetothetopofafunction.Asabonus,the
'usestrict'directiveisignoredbyolderbrowsersthatdonotsupportit.(These
browserssimplyseethedirectiveasastring.)
YoucanreadmoreaboutstrictmodeontheMDNatdeveloper.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Strict_mode.
FortheMoreCurious:Closures
Earlierwementionedthatdevelopersoftenprefertouseanonymousfunctionsas
callbacksinsteadofnamedfunctions.addThumbClickHandlerillustrateswhyan
anonymousfunctionisabettersolution.
Let’ssayyoutriedtouseanamedfunction,clickFunction,forthecallback.Insideof
thatfunction,youhaveaccesstotheeventobjectbecauseitwillbepassedinby
addEventListener.ButthebodyofclickFunctionhasnoaccesstothethumb
object.ThatparameterisonlyaccessibleinsidetheaddThumbClickHandler
function.
functionclickFunction(event){
event.preventDefault();
setDetailsFromThumb(thumb);//<---Thiswillcauseanerror
}
functionaddThumbClickHandler(thumb){
thumb.addEventListener('click',clickFunction);
}
Ontheotherhand,usingananonymousfunctiondoesgiveitaccesstothethumb
parameter,becauseitisalsoinsideofaddThumbClickHandler.Whenafunctionis
definedinsideofanotherfunction,itcanuseanyofthevariablesandparametersofthis
outerfunction.Incomputerscienceterms,thisisknownasaclosure.
WhentheaddThumbClickHandlerfunctionruns,itcallsaddEventListener,
whichassociatesthecallbackfunctionwiththeclickevent.Thebrowserkeepstrackof
theseassociations,internallyholdingareferencetothecallbackfunctionandrunningthe
callbackwhentheeventoccurs.
Technically,whenthecallbackiseventuallyexecuted,thevariablesandparametersof
addThumbClickHandlernolongerexist.Theywentawaywhen
addThumbClickHandlerfinishedrunning.But,thecallback“captures”thevaluesof
addThumbClickHandlersvariablesandparameters.Thecallbackusesthese
capturedvalueswhenitruns.
Foradeeperdive,readuponclosuresintheMDN.
FortheMoreCurious:NodeListsand
HTMLCollections
TherearetwowaystoretrievelistsofelementsthatliveintheDOM.Thefirstoneis
document.querySelectorAll,whichreturnsaNodeList.Theotheris
document.getElementsByTagName,whichdiffersfrom
document.querySelectorAllinthatyoucanonlypassitastringwithatagname,
like"div"or"a",andalsointhatitreturnsanHTMLCollection.
NeitherNodeListsnorHTMLCollectionsaretruearrays,sotheylackarraymethodssuch
asforEach,buttheydohavesomeveryinterestingproperties.
HTMLCollectionsarelivenodes.ThismeansthatwhenchangesaremadetotheDOM,
thecontentsofanHTMLCollectioncanchangewithoutyouhavingtocall
document.getElementsByTagNameagain.
Toseehowthisworks,trythefollowingintheconsole.
varthumbnails=document.getElementsByTagName("a");
thumbnails.length;
AftergettingalloftheanchorelementsasanHTMLCollection,youprintthelengthof
thatlisttotheconsole.
Now,removesomeoftheanchortagsfromthepageusingtheelementspanelinthe
DevTools:Control-click(right-click)oneofthelistitemsandchooseDeleteelement
(Figure6.29).
Figure6.29DeletingaDOMelementwiththeDevTools
Dothisseveraltimes,thenenterthumbnails.lengthintotheconsoleagain.Youshould
seethatthelengthisdifferent(Figure6.30).
Figure6.30Thelengthvaluechangesafterdeletingelements
ConvertingNodeListsandHTMLCollectionstoarraysnotonlymakesthemmore
convenienttoworkwithviaarraymethods,butyoualsohavetheguaranteethattheitems
inthearraywillnotchange,eveniftheDOMismodified.
FortheMoreCurious:JavaScriptTypes
Throughoutthechapter,youcreatedvariablessoyoucouldrefertosomedatainsideyour
functions.Earlyon,wetoldyouthatstrings,numbers,andBooleansarethreeofthefive
primitivedatatypes.Theothertwotypesarenullandundefined.
Table6.2summarizesthepropertiesofthefiveprimitivetypes.
Table6.2PrimitivedatatypesinJavaScript
Type Example Description
string “Andyouget$100!Andyou
get$100!And…!”
Letters,numbers,orsymbolsenclosedin
matchingquotationmarks.
number 42,3.14159,-1 Wholenumbersanddecimals.
Boolean true,false Thekeywordstrueandfalse,
correspondingtologicaltrueandfalse.
null null Thevaluethatdenotesaninvalidvalue.
undefined undefined Thevalueofavariablethathasnotbeen
assignedtoanything.
AllothertypesinJavaScriptareconsideredcompoundtypesorcomplextypes.These
includearraysandobjects,whichcanhaveothertypesinsideofthem.Forexample,you
wroteafunctionthatproducedanarrayofthumbnailobjects.Arraysalsohaveproperties
(likelength)andmethods(suchasforEach).
Youwillcontinuetoworkwithprimitiveandcomplexdatatypesthroughoutthisbook.
7
VisualEffectswithCSS
Inthelastchapter,yougaveOttergramtheabilitytorespondtouserinteractionby
changingthedetailimagewhentheuserclicksathumbnail.Youwillbuildonthatinthis
chapterbyaddingthreedifferentvisualeffectstoOttergram.
Thefirsteffectisasimplelayoutchangethatinvolveshidingthedetailimageandletting
thethumbnailstakeupthewidthofthepage.Whentheuserclicksathumbnail,youwill
makethedetailimagereappearandreturnthethumbnailstotheirprevioussize.
TheothertwoeffectswilluseCSStocreatevisualanimationsforthethumbnailsandthe
detailimage(Figure7.1).
Figure7.1Ottergramwithtransitioneffects
HidingandShowingtheDetailImage
Ottergram’susersmaywanttobeabletoscrollthroughthethumbnailswithoutthedetail
imagebeingonthepage(Figure7.2).
Figure7.2Detailimagevisibleandhidden
Tomakethishappen,youneedtobeabletoapplystylestoyour.thumbnail-listand
.detail-image-containerbasedonaconditionthatwillturnonandoffasthewebsiteis
inuse.Youcoulddothisbycreatingnewclassselectors,like.thumbnail-list-no-
detailand.hidden-detail-image-container,andaddthoseclassestothetarget
elementswithJavaScript.Thetroublewiththisapproachisthatitwouldbeinefficient.
Theeventthatwillcausethedetailimagetohidewillsimultaneouslycausethethumbnail
listtorepositionitself.Itisasingleevent.Addingclassestoyour<ul>and<div>
elementsseparatelydoesnotreflectthis.
AbetterapproachistouseJavaScripttoaddasingleclassselectorthataffectsthelayout
asawhole.Then,youcantargetthe.thumbnail-listand.detail-image-container
whentheyaredescendentsofthenewselector.
Youaregoingtodynamicallyaddaclassnametothe<body>elementtohidethedetail
imageandenlargethethumbnails,andthendynamicallyremovetheclassnametoreturn
toyourcurrentstyles(Figure7.3).
Figure7.3Restylingdescendantswithclasschangetoancestor
Thistechniqueissimilarintwowaystotheoneyouusedwiththemediaqueries.
First,itinvolvesstylesthatareactivatedwhenanancestormeetsaparticularcondition.
Withmediaqueries,thatancestoristheviewportandtheconditionisaminimumwidth.
Inthisnewcode,theancestorwillbeanyelementyouselectthatthetargetelements
share,andtheconditionwillbethattheancestorhasaparticularclassname.
Thesecondsimilarityisthatyoumustplacetheconditionalstylesaftertheother
declarationsfortheaffectedelementsinyourstylesheetbecausetheseconditionalstyles
needtooverridethepreviousdeclarationswhentheyareactive.
Youwillproceedinthreesteps:
1. InyourCSS,definethestylesthatcreatethevisualeffectyouaretryingtoget.
Also,testyourstylesintheDevTools.
2. WriteJavaScriptfunctionstoaddandremoveaclassnameforthe<body>
element.
3. AddaneventlistenertotriggeryourJavaScriptfunction.
Creatingstylestohidethedetailimage
Tohidethe.detail-image-container,youwilladdadeclarationthatsetsdisplay:
noneforthiselement.display:nonetellsthebrowserthattheelementshouldnotbe
rendered.
Theclassyouwillbeaddingdynamicallytothe<body>willbecalledhidden-detail.
Therefore,youonlywanttoapplydisplay:noneto.detail-image-containerwhenit
isadescendentof.hidden-detail.
Addthestyletohidethedetailimageinstyles.css:
...
.detail-image-title{
...
}
.hidden-detail.detail-image-container{
display:none;
}
@mediaalland(min-width:768px){
...
}
Now,givesomethoughttowhatyour.thumbnail-listwilllooklike.Basedonthe
currentstyles,itwillbeacolumnalongtheleftsideofwiderscreensandahorizontalrow
atthetopofnarrowerscreens.Acenteredcolumnwouldbebetterwhenthedetailimageis
hidden,regardlessofthescreensize.
Addstylestothe.thumbnail-listand.thumbnail-iteminstyles.csswhenthey
aredescendentsof.hidden-detail.
...
.hidden-detail.detail-image-container{
display:none;
}
.hidden-detail.thumbnail-list{
flex-direction:column;
align-items:center;
}
.hidden-detail.thumbnail-item{
max-width:80%;
}
@mediaalland(min-width:768px){
...
}
Now,the.thumbnail-listwillalwaysbedisplayedasacolumnwhilethe.detail-
image-containerishidden.
Youhavealsoaddedadeclarationsettingthewidthofthe.thumbnail-itemelementsto
max-width:80%whenthedetailimageishidden.Thisoverridesthemax-widthstylesset
elsewhereforthe.thumbnail-itemssothattheywillbecomethefocusofthepage.
Whenthe.detail-image-container,.thumbnail-list,and.thumbnail-itemelements
arenestedanywhereinsideofanelementwiththeclasshidden-detail,thesenewstyles
willbeactivated.
Notethatyouaddedthesebeforeyourmediaqueries.Asyoualreadyknow,theorderof
yourCSScodematters,withstylesthatappearlaterinthefileoverridingthosethatcame
before.Ingeneral,forthesameselector,thebrowserusesthestylesithasseenmost
recently.Inthiscase,however,yournewstylesuseselectorsthataremorespecificthan
theonesthatappearinyourmediaqueries,andspecificitytrumpsrecency.
Generally,itisbesttokeepyourmediaqueriesattheendofthefile.Yourmediaqueries
willusuallyreusethesameselectorsfromexistingstyles,soputtingthemattheend
makessurethatyourmediaqueriesoverwritethoseexistingstyles.Also,itmakesyour
mediaquerieseasiertolocate,becausetheyarealwaysattheendofthefile.
Saveyourfile.BeforeyouwritetheJavaScriptthatdependsonthestylesyouhaveadded,
itiswisetotestthem.Startbrowser-sync(usingbrowser-syncstart--server--
browser"GoogleChrome"--files"*.html,stylesheets/*.css,scripts/*.js")
andopentheDevTools.Intheelementspanel,Control-click(right-click)the<body>
elementandchooseAddAttributefromthemenuthatappears(Figure7.4).
Figure7.4ChoosingtheAddAttributemenuitem
TheDevToolsprovidesaspaceforyoutostarttypinginsidethe<body>tag.Enter
class="hidden-detail"andpressReturn(Figure7.5).
Figure7.5Addingthehidden-detailclassattribute
Afteryouaddthehidden-detailclasstothe<body>intheDevTools,thedetailimage
disappearsandthethumbnailsbecomemuchlarger–justasyouintended(Figure7.6).
Figure7.6Layoutchangeafterapplyinghidden-detailclass
WritingtheJavaScripttohidethedetailimage
Next,youwillwritetheJavaScriptthatwilltogglethe.hidden-detailclassforthe
<body>element.
Inmain.js,addavariablenamedHIDDEN_DETAIL_CLASS.
varDETAIL_IMAGE_SELECTOR='[data-image-role="target"]';
varDETAIL_TITLE_SELECTOR='[data-image-role="title"]';
varTHUMBNAIL_LINK_SELECTOR='[data-image-role="trigger"]';
varHIDDEN_DETAIL_CLASS='hidden-detail';
...
Now,writeanewfunctioninmain.jsnamedhideDetails.Itsjobistoaddaclass
nametothe<body>element.YouwillusetheclassList.addDOMmethodto
manipulatetheclassname.
...
functiongetThumbnailsArray(){
...
}
functionhideDetails(){
'usestrict';
document.body.classList.add(HIDDEN_DETAIL_CLASS);
}
functioninitializeEvents(){
...
}
...
Youaccessedthe<body>elementusingthedocument.bodyproperty.ThisDOMelement
correspondstothe<body>taginyourmarkup.LikeallDOMelements,itgivesyoua
convenientwaytomanipulateitsclassnames.
Youalsocalledtheaddmethodondocument.bodytoaddthehidden-detailclasstothe
<body>.
Listeningforthekeypressevent
Nowyouneedawaytotriggerthedetailimagetohide.Asbefore,youwilluseanevent
listener,butthistimeyoureventlistenerwilllistenforakeypressinsteadofaclick.
Weusetheterm“keypress”generallytomeanpressingandreleasingakey,butthat
simpleprocessactuallytriggersmultipleevents.Whenthekeyisfirstdepressed,the
keydowneventissent.Ifitisacharacterkey(asopposedtoamodifierkeylikeShift)then
thekeypresseventisalsosent.Whenthekeyisreleased,thekeyupeventissent.
ForOttergram,thesedifferencesareminimal.Youaregoingtousethekeyupevent.
Inmain.js,addafunctionnamedaddKeyPressHandlerthatcalls
document.body.addEventListener,passingitthestring'keyup'andan
anonymousfunctionthatdeclaresaparameternamedevent.Insidethebodyofthis
anonymousfunction,makesuretopreventDefaultfortheevent,andthen
console.logtheeventskeyCode.
...
functionhideDetails(){
...
}
functionaddKeyPressHandler(){
'usestrict';
document.body.addEventListener('keyup',function(event){
event.preventDefault();
console.log(event.keyCode);
});
}
functioninitializeEvents(){
...
}
...
AllofthekeypresseventshaveapropertycalledkeyCodethatcorrespondstothekey
thattriggeredtheevent.ThekeyCodeisaninteger,like13forReturn,32forthespace
bar,and38fortheuparrow.
UpdatetheinitializeEventsfunctioninmain.jssothatitcalls
addKeyPressHandler.Youneedtodothissothatthe<body>elementcanlistenfor
keyboardeventswhenthepageloads.
...
functioninitializeEvents(){
'usestrict';
varthumbnails=getThumbnailsArray();
thumbnails.forEach(addThumbClickHandler);
addKeyPressHandler();
}
initializeEvents();
Saveandswitchbacktothebrowser.Makesuretheconsoleisvisible,thenclickonthe
pagetomakesurethatthefocusisnotontheDevTools–otherwise,theeventlistenerwill
notbetriggered.Nowpresssomekeysonyourkeyboard.Youwillseenumbersprintedto
theconsole(Figure7.7).
Figure7.7LoggingthekeyCodetotheconsole
YouwanttohidethedetailimagewhentheEsckeyispressed,notjustanykey.Ifyou
presstheEsckey,youwillseethatthecorrespondingevent.keyCodevalueis27.You
willusethattomakeyoureventlistenermorespecific.
Addavariabletothetopofmain.jsfortheEsckey’svalue.
varDETAIL_IMAGE_SELECTOR='[data-image-role="target"]';
varDETAIL_TITLE_SELECTOR='[data-image-role="title"]';
varTHUMBNAIL_LINK_SELECTOR='[data-image-role="trigger"]';
varHIDDEN_DETAIL_CLASS='hidden-detail';
varESC_KEY=27;
...
Now,updateyourkeyupeventlistenertocallhideDetailswhenthevalueof
event.keyCodematchesthevalueofESC_KEY.
...
functionaddKeyPressHandler(){
'usestrict';
document.body.addEventListener('keyup',function(event){
event.preventDefault();
console.log(event.keyCode);
if(event.keyCode===ESC_KEY){
hideDetails();
}
});
}
...
Youusedthestrictequalityoperator(===)tocomparethevaluesofevent.keyCode
andESC_KEY.Whenthesevaluearethesame,youcallhideDetails.
Youcouldhaveusedthelooseequalityoperator(==)tocomparethevaluesinstead,butit
isusuallybesttousethestrictequalityoperator.Themajordifferencebetweenthe
equalityoperatorsisthatthelooseequalityoperatorwillautomaticallyconvertfromone
typeofvaluetoanother.Thestrictequalityoperatorwillnotdotheconversion.Withstrict
equality,ifthetypesarenotthesame,thentheresultofthecomparisonisalwaysfalse.
Manyfront-enddevelopersrefertothisautomatictypeconversionastypecoercion.Itis
performedwhenvaluesneedtobecompared(whenusinganequalityoperator),added
together(inthecaseofnumbers),orconcatenated(aswithstrings).
Becauseofthisautomaticconversion,thereisnosyntaxerrorifyoutrytoaddthestring
"27"withthenumber42–thoughtheresultmightnotbewhatyouexpect(Figure7.8).
Figure7.8JavaScriptwillautomaticallyconvertbetweentypes
Thisisveryimportantwhenworkingwithuser-provideddata,whichyouwilldoin
Chapter10.
Savemain.jsandtestyournewfunctionalityinthebrowser(Figure7.9).
Figure7.9Poof!PressingEschidesthedetailimageandtitle
Showingthedetailimageagain
Thereisonesmallbutimportantpiecetoadd:makingthedetailimagevisibleagain.This
willbetriggeredwhenathumbnailisclicked.
YouusedclassList.addtoaddaclassnametothe<body>element.Youwilluse
classList.removetoremovethatclassnamewhenathumbnailisclicked.Adda
newfunctionnamedshowDetailstomain.js.
...
functionhideDetails(){
...
}
functionshowDetails(){
'usestrict';
document.body.classList.remove(HIDDEN_DETAIL_CLASS);
}
functionaddKeyPressHandler(){
...
}
...
NowaddacalltoshowDetailsinyouraddThumbClickHandlerfunction–no
needtoaddaneweventlistener.
...
functionaddThumbClickHandler(thumb){
'usestrict';
thumb.addEventListener('click',function(event){
event.preventDefault();
setDetailsFromThumb(thumb);
showDetails();
});
}
...
Savemain.jsandswitchtoyourbrowser.Tryoutyournewfunctionality:Hidethe
detailimage,thenclickonathumbnailtobringitback(Figure7.10).Theotterslooklike
theyapprove,don’tthey?
Figure7.10Eschidesdetails;clickshowsdetails
Now,Ottergramcandynamicallyadaptitslayoutbasedontheviewport,usingmedia
queries,aswellasinresponsetouserinput.
Atthemoment,thelayoutchangeshappenabruptly.Inthenextsection,youwillsmooth
thatoutusingCSStransitions.
StateChangeswithCSSTransitions
CSStransitionscreateagradualchangefromonevisualstatetoanother,whichisjust
whatyouneedtomakeOttergram’sshow/hideeffectmorepolished.
WhenyoucreateaCSStransition,youaretellingthebrowser,“Iwouldlikethiselement’s
stylestochangetothesenewproperties,andIwouldlikeforthatchangetotakeexactlyas
longasItellyou.”
Onecommonexampleisthefly-outmenuseenonmanysites,suchasthesmall-screen
versionofbignerdranch.com.Inabrowserwithanarrowviewport,clickingthe
menuiconmakesthenavigationmenuappearfromthetop–butitdoesnotappearallat
once.Instead,itslidesdownfromtheheader,visuallyanimatingfromtheinitialstate
(hidden)totheendstate(visible)(Figure7.11).Clickingthemenuiconagaincausesthe
navigationmenutoslidebackupuntilitishiddenagain.
Figure7.11Fly-outnavigationonbignerdranch.com
Beforeyoucreatethetransitioneffectforshowingandhidingthedetailimage,youwill
buildasimplertransitionforyourthumbnails.
Ingeneral,youshouldcreatetransitionsinthreesteps:
1. Decidewhattheendstateshouldbe.OnegoodapproachistoaddtheCSS
declarationsfortheendstatetothetargetelement.Thisallowsyoutoseethemin
thebrowserandmakesurethattheylookthewayyouintend.
2. Movethedeclarationsfromthetargetelement’sexistingdeclarationblocktoa
newCSSdeclarationblock.Youmaywanttouseanewclassfortheselectorfor
thenewblock.
3. Addatransitiondeclarationtothetargetelement.Thetransitionproperty
tellsthebrowserthatitwillneedtovisuallyanimatethechangesfromthecurrent
CSSvaluestotheend-stateCSSvaluesandthatthetransitionshouldtakeplace
overaspecificperiodoftime.
Workingwiththetransformproperty
Yourfirsttransitionwillincreasethesizeofathumbnailwhenyouhoveroveritwiththe
cursor(Figure7.12).However,youwillnotdirectlychangethewidthorheightstyles.
Youwillusethetransformproperty,whichcanaltertheshape,size,rotation,andlocation
ofanelementwithoutinterruptingtheflowoftheelementsaroundit.
Figure7.12Athumbnailwithzoomeffect
Thetargetelementforthistransitionisthe.thumbnail-item.Youwillbeginbyaddinga
transformdeclarationdirectlytothe.thumbnail-itemelement.
Afteryouhavetesteditanddeterminedthatitisworkingthewayyouwant,youwill
movethetransformationtoanew.thumbnail-item:hoverdeclarationblock.Finally,you
willaddatransitiondeclarationto.thumbnail-item.
Instyles.css,beginbyaddingatransformdeclarationto.thumbnail-item.
...
.thumbnail-item{
display:inline-block;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
transform:scale(2.2);
}
...
transform:scale(2.2)tellsthebrowserthattheelementshouldbedrawnat220%ofits
originalsize.Therearemanyvaluesthatcanbeusedwithtransform,includingadvanced
3Deffects.TheMDNhasgoodcoverageofthematdeveloper.mozilla.org/en-
US/docs/Web/CSS/transform.
Saveandviewthechangesinyourbrowser(Figure7.13).
Figure7.13Dramaticallylargeotterthumbnails
Youcanseethatthethumbnailsarenowmuchlargerthanbefore.Infact,theyaretoo
large.Changethevaluesothattheyareonlyalittlebitlarger:
...
.thumbnail-item{
display:inline-block;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
transform:scale(2.2);
transform:scale(1.2);
}
...
Afteryousave,youshouldseethattheotterthumbnailsareonlyslightlylargerthantheir
originalsize(Figure7.14).
Figure7.14Reasonablylargeotterthumbnails
Thisscaleforthethumbnailslooksgood,soyoucanmoveontothenextstep.
AddingaCSStransition
Nowitistimetomovetheend-statestyletoanewstyledeclarationandsetupthe
transitionforthe.thumbnail-itemelement.
Whentheuserhoversthemousecursoroverathumbnail,thatthumbnailshouldincrease
itsscaleby120%.Addadeclarationblocktostyles.cssthatusesthemodifier
:hovertodesignatestylesthatshouldonlybeappliedwhentheuserhoversoverthe
element.
...
.thumbnail-item{
display:inline-block;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
transform:scale(1.2);
}
.thumbnail-item:hover{
transform:scale(1.2);
}
...
Thepropernameforthismodifierispseudo-class.Thepsuedo-class:hovermatchesan
elementwhentheuserholdsthemousecursoroverit.Thereareanumberofpseudo-class
keywordsthatdescribethevariousstatesanelementcanbein.Youwillencountersome
whenyouworkwithformslaterinthisbook,andyoucansearchtheMDNtolearnmore.
Next,makethischangehappenasatransitionbyaddingatransitiondeclarationto
.thumbnail-iteminstyles.css.Youneedtospecifythepropertytoanimateandhow
longtheanimationshouldtake.
...
.thumbnail-item{
display:inline-block;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
transition:transform133ms;
}
.thumbnail-item:hover{
transform:scale(1.2);
}
...
Yousetatransitionforthetransformproperty.Thistellsthebrowserthatitwillneed
toanimatethechange,butonlyforthetransformproperty.Youalsospecifiedthatthe
transitionshouldtakeplaceoveraperiodof133milliseconds.
Saveandgiveyournewtransitionatry.Youshouldseethateachthumbnailenlargeswhen
youhoveroverit.Whenyoumoveyourmouseaway,thetransitionrunsinreverse,and
thethumbnailreturnstoitsoriginalsize(Figure7.15).
Figure7.15Transitionoccurswhenhovering,reversesonmouseout
TheDevToolsgiveyouahandywaytotestpseudo-classstates.Gototheelementspanel
andexpandthetagsuntiloneofthe<li>tagsisdisplayed.Clickthetagsothatitis
highlightedandyouwillseeanellipsistotheleft.Clicktheellipsis,andinthecontextual
menuthatisrevealedchoose:hoverfromthelistofpseudo-classes(Figure7.16).
Figure7.16Togglingapseudo-classintheelementspanel
Anorangecircleappearstotheleftofthe<li>tagintheelementspanel,tellingyouthat
oneofthepseudo-classeshasbeenactivatedviatheDevTools.Thecorresponding
thumbnailwillremaininthe:hoverstate,evenifyoumouseoveritandthenmouseaway
fromit.
Openthecontextualmenuagain,byclickingtheorangecircle,anddisablethe:hover
statebeforeyoucontinue.
Yourtransitionisnice,butthereisasmallbug.Currently,thehovereffectcausespartsof
thethumbnailtobecutoff.Thisisbecausethetransformappliedtothe.thumbnail-
itemdoesnotcauseitsparenttoadjustitssize.Thesolutionistoaddabitofpaddingto
the.thumbnail-list.Changetheverticalpaddingfor.thumbnail-listin
styles.css.
...
.thumbnail-list{
flex:01auto;
order:2;
display:flex;
justify-content:space-between;
list-style:none;
padding:0;
padding:20px0;
white-space:nowrap;
overflow-x:auto;
}
...
Youusedtheshorthandforthepaddingproperty.Thefirstvalue,20px,appliestothetop
andbottompadding,whilethesecondvalueappliestotheleftandrightpadding.Makea
similaradjustmentinsideyour@mediaquery,butaddanextrapaddingof35pxtotheleft
andright.
...
@mediaalland(min-width:768px){
.main-content{
...
}
.thumbnail-list{
flex-direction:column;
order:0;
margin-left:20px;
padding:035px;
}
...
Saveandchecktheresultsinyourbrowser.Thisproducesanicereffectforthethumbnails
(Figure7.17).
Figure7.17Extraroomforthehovereffectinportraitandlandscape
Usingatimingfunction
Yourhovereffectislookinggood!Butitlacksthatvisualpopthatwouldmakeitreally
special.WithCSStransitions,youcannotonlyspecifyhowmuchtimeatransitionshould
take,butalsomakeittransitionatdifferentspeedsduringthattime.
Thereareseveraltimingfunctionsthatyoucanusewithtransitions.Bydefault,thelinear
timingfunctionisused,whichmakesthetransitionanimateatasingle,constantrate.The
othersaremoreinteresting,andgivethetransitionthefeelingofspeedinguporslowing
down.
Updateyourtransitioninstyles.csssothatitusestheease-in-outtimingfunction.
Thiswillmaketherateofthetransitionsloweratthebeginningandendandfasterinthe
middle.
...
.thumbnail-item{
display:inline-block;
min-width:120px;
max-width:120px;
border:1pxsolidrgb(100%,100%,100%);
border:1pxsolidrgba(100%,100%,100%,0.8);
transition:transform133msease-in-out;
}
...
Saveandthenhoveroveroneofyourthumbnails.Theeffectissubtle,butnoticeable.
Thereareanumberoftimingfunctionsavailable.SeethelistontheMDNat
developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-
function.
Yourtransitionusesthesamedurationvalueandtimingfunctionforboththetransition
totheendstateandthetransitionfromtheendstate.Thatdoesnothavetobethecase–
youcanusedifferentvaluesdependingonthedirectionofthetransition.Ifyouspecifya
transitionpropertyonboththebeginning-statedeclarationandtheend-statedeclaration,
thebrowserusesthevalueofthedeclarationitismovingtoward.
Itmightbeeasiertoseethisinaction.Foraquickdemonstration,addatransition
declarationto.thumbnail-item:hoverinstyles.css.(Youwilldeleteitaftertryingit
outinthebrowser.)
...
.thumbnail-item:hover{
transform:scale(1.2);
transition:transform1000msease-in;
}
...
Saveandagainhoveroveroneofthethumbnailsinthebrowser.Thescalingeffectwillbe
veryslow,takingafullsecondtocomplete.Thisisbecauseitisusingthevaluedeclared
for.thumbnail-item:hover.Now,moveyourmouseoffofthethumbnail.Thistime,the
transitiontakes133milliseconds,thevaluedeclaredfor.thumbnail-item.
Removethetransitiondeclarationfrom.thumbnail-item:hoverbeforeyoucontinue.
...
.thumbnail-item:hover{
transform:scale(1.2);
transition:transform1000msease-in;
}
...
Transitiononclasschange
Yoursecondtransitionwillmakethe.detail-image-framelooklikeitiszoomingin
fromveryfaraway.
Insteadofusingapseudo-classselectortotriggeratransition,thistimeyouwilladdand
removeclassnameswithJavaScripttotriggeratransition.Why?Becausethereisno
pseudo-classthatcorrespondstoaclickevent.UsingJavaScriptgivesyoumuchmore
controloverhowandwhentheseUIchangesaretriggered.
Also,youwillsetdifferentdurationtimesforthebeginningandendofthetransition.The
endresultwillbethatwhenyouclickathumbnailthecorrespondingotterimagewillbe
usedforthedetailimage.Itwillimmediatelybesizeddowntoatinydotinthecenterof
thedetailarea,thenitwilltransitiontoitsfullsize(Figure7.18).
Figure7.18Clickingathumbnailscalesitfromverysmalltofullsize
Startbyaddingastyledeclarationforanewclassnamedis-tinyinstyles.css.
...
.detail-image-frame{
...
}
.is-tiny{
transform:scale(0.001);
transition:transform0ms;
}
.detail-image{
...
Youaddedtwostylesfor.is-tiny.Thefirstscalestheelementdowntoasmallfraction
ofitsoriginalsize.Thesecondspecifiesthatanytransitionforthetransformproperty
shouldlast0milliseconds,applyingthestylechangeimmediately.Putanotherway,going
towardthe.is-tinyclassstyles,thedetailimagewilleffectivelyhavenotransition.
Becauseitlastsfor0milliseconds,thereisnoneedtospecifyatimingfunction.
Next,youwilladdanothertransitiondeclarationwitha333millisecondduration.This
valuewillbeusedwhentransitioningawayfromthe.is-tinyclass,makingthedetail
imagegrowtonormalsizeoveraperiodofathirdofasecond.Addthistransition
declarationtothe.detail-image-frameinstyles.css.
...
.detail-image-frame{
position:relative;
text-align:center;
transition:transform333ms;
}
...
Savestyles.cssbeforeyoumoveon.
TriggeringtransitionswithJavaScript
Nowthatyourtransitionstylesareinplace,youneedtotriggerthemwithJavaScript.To
giveyourJavaScriptahook,addadataattributetothe.detail-image-frameelementin
index.html.
...