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 .
Page Count: 576
Download | |
Open PDF In Browser | View PDF |
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 constructor’s 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 frontend 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 fiveday 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. You can play with your eReader’s 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 plugin. 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). A linter 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 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. Chrome 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 frontend 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-devbook 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 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. sudo 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, rightclick 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. (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. Node.js 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. 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. browser-sync 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. is Microsoft’s open source text editor, made specifically for developing web applications. It can be downloaded from code.visualstudio.com (Figure 1.28). Visual Studio Code 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 catvideos.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 animatedbackground.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 browser’s 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 user’s 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 frontend-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 betweenand – 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:ottergram and emmet have together saved you some typing and helped you build well-formed initial HTML. Atom Let’s examine your code. The first line, , 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: 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 tag. 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 tag in Ottergram, , 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 ottergram
tags enclose the tag shown above (and the tags enclose the
!). 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. ottergram ... The 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 thetag. In the list, you will include five list items using
alt="Barry the Otter"> alt="Robin the Otter"> alt="Maurice the Otter"> alt="Lesley the Otter"> alt="Barbara the Otter"> ... 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 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 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 , 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 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, 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 anglebracket, like . 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 Atom’s 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 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. Chrome 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 displays the DevTools to the right by default. Your screen will look something like Figure 2.17. Chrome 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 Release Notable Features Number Year 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 browser’s 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.com favicon.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 missing favicon.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 to normalize.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 tag and paste in the address. (In the code below, the has been broken into two lines to fit on the page. You can leave yours on a single line.)- tags, and in each list item you will include some text surrounded by 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 Atom’s 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.
ottergram ottergram
The tags nested inside each
- Barry
- Robin
- Maurice
- Lesley
- Barbara
- 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 tags so that they follow the spans.) ...
- Robin
- Maurice
- Lesley
- Barbara
ottergram ... Make sure that you add the tag for normalize.css before the 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: ... ... 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 selector’s specificity. For example, you can write selectors based on attributes – such as the thumbnail-title class attribute you just added to the 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 elements), specificity also determines the selector’s 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 correspondingtag. 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 .thumbnailtitle 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 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 body font 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 body’s 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 ul’s font-size has overridden the body’s (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 body’s 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 .thumbnailtitle 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 textdecoration 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. ...
ottergram
ottergram
... 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-image’s 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-item’s 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 body’s background color is defined with integers and the .thumbnail-item’s 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 at css-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 body’s 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-list’s 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 stylesheets folder 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 Atom’s snippets documentation at flightmanual.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.css’s 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 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
- elements. What background color will your
- 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:
- 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
- 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 user’s 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: ...
- Barbara
Stayin' AliveYou added awith a detail-image-container class. Ais 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 theyou added an tag to display the large version of the otter image. You also added a , which wraps around the title text for the detail image. You gave the and 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 container’s 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 fiveelements in index.html. This will give you lots of content to scroll through. To do this, simply select all of the lines between and
, copy them, and paste the result just above the . 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 Atom’s 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 container’s width. Why not just set the .thumbnail-image to width: 120px? You want the .thumbnailimage 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 .thumbnailitem 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 and elements to height: 100% in styles.css. The element is the root element of your DOM tree, with the as a child element drawn inside of it. Setting the height 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 should have a height of 100% and stores that information. When it reads the next styling rule for the , 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 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 ) 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 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 has three flex items: the, the .thumbnail-list, and the .detailimage-container. No matter what happens during the development (and use) of Ottergram, the 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-imagecontainer 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-imagecontainer in their own flex container. To do this, you will wrap them in a 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 element the class main-header, then wrap the .thumbnail-list ( ) and the .detail-image-container (
) in aelement with the class main-content. ... ottergram
... .main-header and .main-content are now the two flex items inside the . By wrapping the .thumbnail-list and .detail-image-container in the .main-content element, you are now free to declare a height for the ...
Stayin' Alive, leaving the rest of the ’s vertical space for the .main-content to occupy. That way, the space inside of can be distributed to .thumbnail-list and .detail-image-container without affecting the header. .main-content 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-content’s 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 ’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-content’s flex items so that the .thumbnail-list takes the default amount of space and .detailimage-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-content’s declaration block, adding flex properties to .thumbnaillist’s declaration block, and writing a new declaration block for the .detail-imagecontainer 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-item’s 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 .detailimage-title. In index.html, begin by adding a with the class name detail-image-frame: ...Save index.html. Now, in styles.css, add a declaration block for .detail-imageframe 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 justifycontent: 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-imagecontainer (Figure 4.20). Figure 4.20 After centering .detail-image-frame inside .detail-imagecontainer 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 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 container’s top edge and its left edge is 200px from its container’s 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 A text-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 browser’s 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 browser’s 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 tag to tell all browsers to display Ottergram at the best size for the device’s physical screen. In index.html, add a 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.Stayin' AliveOttergram ... 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 viewport The area equal to the browser’s window. It serves as the element’s container. Device desktop, laptop layout A virtual screen, larger than the actual device screen, used for viewport calculating the page layout. mobile visual The zoomable area that a user can see on a device’s screen. viewport Zooming has no effect on the page layout. mobile ideal The optimal dimensions for a specific browser on a specific viewport 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 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 */ } is followed by the media type all. 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. @media 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-list’s 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-list’s 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-byflexbox), 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