Chapter 1: Introduction to CSS & Layout to Be Dangerous | Learn Enough to Be Dangerous
You have to make a choice. Choose...wisely.

Get occasional notifications about things like product discounts, blog posts, and new or updated tutorials. Unsubscribe at any time.

Quick Checkout
or Pay by Credit Card
Error processing your payment
  • You didn't choose whether or not to be added to the mailing list
Confirm
$0.00

Payments and credit card details are securely managed and protected by Learn Enough's payment processor, Stripe. More information on their site:

CART
Total
$0.00

Your Cart is Empty

$30
$300
$300
$XY
$XY
1234
Get Single Tutorial
MORE INFO

Learn Enough CSS & Layout to Be Dangerous is available as an ebook, an offline video series, and as a structured, self-paced online course. The course includes full online access to the book content, streaming videos, progress tracking, exercises, and community exercise answers.

All Access Subscription
MORE INFO

The Learn Enough All Access Subscription includes the entire Learn Enough introductory sequence and the full Ruby on Rails Tutorial. More than 2500 pages of book content and 53 hours of video that teach you to code from total beginner up to professional-grade web development.

Sign up for the course and get access to the full tutorial and streaming screencasts!

Learn Enough CSS Layout to Be Dangerous A tutorial introduction to CSS and page layout Lee Donahoe and Michael Hartl

An introduction to CSS and page layout, including static site generation with Jekyll

Learn Enough CSS & Layout to Be Dangerous

A tutorial introduction to CSS and page layout

Lee Donahoe and Michael Hartl

Contents

About the authors

Learn Enough cofounder Lee Donahoe is an entrepreneur, designer, and front-end developer. In addition to doing the design for Learn Enough, Softcover, and the Ruby on Rails Tutorial, he is also a cofounder and front-end developer for Coveralls, a leading test coverage analysis service, and is tech cofounder of Buck Mason, a men’s clothing company once featured on ABC’s Shark Tank. Lee is a graduate of USC, where he majored in Economics and studied Interactive Multimedia & Technologies.

Michael Hartl is the creator of the Ruby on Rails Tutorial, one of the leading introductions to web development, and is cofounder and principal author at Learn Enough. Previously, he was a physics instructor at the California Institute of Technology (Caltech), where he received a Lifetime Achievement Award for Excellence in Teaching. He is a graduate of Harvard College, has a Ph.D. in Physics from Caltech, and is an alumnus of the Y Combinator entrepreneur program.

Chapter 1 Introduction to CSS

Welcome to Learn Enough CSS & Layout to Be Dangerous!

CSS—short for Cascading Style Sheets—is the design language of the World Wide Web. CSS lets developers and designers define what a web page looks like and how it behaves, including how elements are positioned in the browser. Every website that you visit (with some incredibly rare exceptions) uses CSS to make the user experience and interface look inviting, which means that learning the basics of CSS is an essential part of becoming a web developer or designer. It’s also useful for anyone who interacts with developers and designers, which these days seems like practically everyone.

Most CSS tutorials teach the subject in isolation, showing you how to make individual changes to things like text color or font size, without showing you how to put everything together as an integrated whole. This approach is a lot like trying to teach a foreign language by having students read the dictionary. You might learn lots of words, but you would end up with little to no context or ability to have a real conversation (Figure 1.1).1

In contrast, Learn Enough CSS & Layout to Be Dangerous is specifically designed to show you how CSS works in the context of a real website.

images/figures/spanish
Figure 1.1: You’re not going to learn Spanish from the dictionary alone.

It’s especially hard to find tutorials that cover how to develop the layout of the page—that is, how one positions elements on the page and determines what content goes where. It’s because this subject is so important—and yet so neglected—that we called this tutorial Learn Enough CSS & Layout to Be Dangerous, rather than simply Learn Enough CSS to Be Dangerous.

Why is layout so often ignored? It’s partially because the layout aspects of CSS can be rather complicated, but it’s also because doing layout right calls for more than plain HTML and CSS. Making a real, industrial-grade website requires using a templating system to assemble the various parts—there are simply too many repeated and custom elements (such as headers, footers, dynamically generated names and dates, etc.) to build such sites by hand (Figure 1.2).

images/figures/page
Figure 1.2: Most modern websites have many repeated and custom elements.

As a result, even learning enough CSS to be dangerous—that is, enough to accomplish your goals without taking the time to become a complete expert—is far more extensive than most people realize. You need to learn not only the basic CSS rules, but also more advanced rules governing page layout, together with a tool to assemble all the parts into a combined whole.

Learn Enough CSS & Layout to Be Dangerous is designed to fill this need. It fits into the Learn Enough introductory sequence immediately after Learn Enough HTML to Be Dangerous, but it’s also suitable for more experienced developers who want to strengthen their knowledge of web design.2 Among other things, this means that Learn Enough CSS & Layout to Be Dangerous is both a possible prerequisite and also an excellent follow-on to the Ruby on Rails Tutorial.

As a result of building on the ideas developed in previous Learn Enough tutorials (Box 1.1), Learn Enough CSS & Layout to Be Dangerous is also unusual in that we will be deploying our sample CSS site to the live Web, all while following professional-grade development practices. Because of this integrated approach, Learn Enough CSS & Layout to Be Dangerous puts everything together in a way you probably haven’t seen before, even if you’ve previously studied CSS.

Box 1.1. Prerequisites.

This tutorial assumes that you know how to use a Unix command line, are comfortable using a text editor, are familiar with using Git for version control, and understand the basic structure of an HTML page. If you’d like an introduction or a refresher on any of these subjects, we suggest reading one or more of the corresponding Learn Enough tutorials:

  1. Learn Enough Command Line to Be Dangerous
  2. Learn Enough Text Editor to Be Dangerous
  3. Learn Enough Git to Be Dangerous
  4. Learn Enough HTML to Be Dangerous

You’ll also probably find it helpful to set up your computer as a proper development environment, as covered in Learn Enough Dev Environment to Be Dangerous, although this step can be deferred until Chapter 5.

1.1 You’re a front-end developer

CSS isn’t the kind of language that’s useful to learn in little half-steps—the part that people find difficult is dealing with handling styling when you are deep into creating an honest-to-goodness website with many levels of complexity. The real skill comes in knowing how to plan for a multi-page site that uses a bunch of different snippets of code3 placed into a flexible layout that organizes content and data in a useful way.

There are already many sites (like the Mozilla Developer Network CSS Reference) that exhaustively document every CSS property, so going over each and every option from the specification would just be a duplication of effort. Instead, Learn Enough CSS & Layout to Be Dangerous is designed to complement such reference works by showing you how CSS applies to the design of a real website. The resulting narrative explanation gives you the context necessary to understand and apply CSS documentation—especially when combined with a little technical sophistication (Box 1.2).

Box 1.2. Technical sophistication

One of the principal themes of the Learn Enough tutorials is the development of technical sophistication, the ability to figure out and solve technical problems.

This tutorial includes many opportunities to apply technical sophistication. For example, many of the code listings require you to orient yourself in a CSS file and figure out where to put the new style rules introduced by the listing. Another important technique is learning to comment out CSS rules and then refreshing the browser to see what they do. We’ll also occasionally add CSS rules that are purely for demonstration purposes; technical sophistication is the skill you need to figure out that such demo code can safely be deleted, especially if a future listing omits it.

Later chapters, particularly after Chapter 5, also require that you successfully configure a development environment and run a templating system to build a professional-grade website. A huge number of things can go wrong when getting these to work; if you get stuck, there’s no substitute for Googling around and determination—both of which are key aspects of technical sophistication.

The important thing at this point in your progress as a developer is to start learning how styling and layout concepts work together, how HTML and CSS combine to make a layout that is actually useful, and how to use some sort of system that allows you to avoid repeating sections of the site or styling on multiple pages (Box 1.3). Doing otherwise would make you an expert at changing text color and size, but you’d have no chance of applying the knowledge you’ve gained to a real-world scenario. In fact, by learning CSS in a holistic way, you’ll not just be getting an introduction to styling—this tutorial is also going to be your first introduction to the world of front-end development (Figure 1.3).4

images/figures/owl
Figure 1.3: Yer a wizard front-end developer, Harry.
Box 1.3. Staying DRY

If you’ve been poking around the Internet in places where developers talk shop, you might have noticed someone mention staying DRY, with “dry” in all caps. They aren’t talking about relative moisture levels. What they are talking about is a core principle in programming: Don’t Repeat Yourself.

The idea behind DRY is that good coding should include as few instances of unnecessary repetition as humanly possible, simply because you have the same code in a bunch of places, then every time you want to make a change you’ll have to update all the different spots in the application where that code is repeated. For example, if you wanted to change a link to the navigation bar of a hand-built site, you’d have to make the same change on every page. On a two-page site this wouldn’t be a big deal, but for a bigger website it would be a nightmare.

Programmers are a special sort of lazy—especially when it comes to doing something repetitive that could be done more efficiently with a little bit of extra programming. To make it easier to be lazy, enterprising programmers spend countless hours creating systems that allow other developers not to have to repeat themselves. We all benefit from developers who at some point decided they were going to work really hard now so they could work less hard in the future.

Templating software, like the system we will be using starting in Chapter 5, allows us not to repeat ourselves by collecting repeated code into individual files, and then including these code snippets onto any page where they’re needed.

The result is that we can write something like the navigation menu for a site once, put it in its own little file, and then include that file every place where the navigation needs to appear. If we want to change the navigation later on, we need to edit only that single file, and the changes will automatically be applied to every page that includes it. We’ll learn how to do this in Section 5.6.

1.1.1 So, what is front-end development?

When someone says that they are a front-end developer, that means that they work on the parts of a site that people see and interact with. That includes things like HTML, CSS, and JavaScript. You’ll also hear people talk about user interface (UI) design (the way things look) and user experience (UX) design (the way that the interface and different pages function to move users through the site to a goal).

The complement to front-end development is back-end development, which involves the architecture of data, how it is stored, and how it is delivered. Later Learn Enough tutorials (starting with Learn Enough Ruby to Be Dangerous) cover the basics of back-end development, culminating in the Ruby on Rails Tutorial, which teaches how to develop a full web application with a database, users, login and authentication, and more.

So, how do we turn an HTML caterpillar into a front-end developer butterfly (Figure 1.4)?

images/figures/butterfly
Figure 1.4: It’s a whole lot easier to read Learn Enough CSS & Layout to Be Dangerous than to pupate.

We’ll start by building on the styling introduced in Learn Enough HTML to Be Dangerous. In the final sections of that tutorial, we showed how to add styling directly to elements on a page, while also briefly covering how to factor that styling into a stylesheet. In this tutorial, we’ll expand greatly on this theme.

Throughout the rest of this chapter, we’ll learn the basics of CSS declarations and values by starting with a few super-simple elements on a sample page, with a particular focus on applying the DRY principle (Box 1.3). We’ll end with a first introduction to the essential technique of CSS selectors to target particular page elements for styling.

In Chapter 2, we’ll discuss aspects of selectors that are important to get right at the beginning of a project, with a focus on managing complexity and maintaining flexibility by choosing good names for things (including an introduction to CSS color conventions).

Chapter 3 introduces two of the most important kinds of CSS values: colors and sizes. These lay an essential foundation for Chapter 4 on the box model, which determines how different elements fit together on the page.

In Chapter 5 and Chapter 6, we’ll take the page that we’ve been working on and factor it into a layout using a static site generator (which includes a templating system) called Jekyll to build professional-grade websites that are easy to maintain and update.

In Chapter 7, we’ll learn how to make flexible page layouts using flexbox, adding layouts for a photo gallery page (to be filled in in Learn Enough JavaScript to Be Dangerous) and a blog with posts. In Chapter 8, we’ll add the blog itself, showing how to use Jekyll to make a professional-grade blog without black-box solutions like Wordpress or Tumblr.

Because a large and growing amount of web traffic comes from mobile devices, in Chapter 9 we’ll cover the basics of using CSS and media queries to make mobile-friendly sites without violating the DRY principle (Box 1.3).

As a concluding step in developing the main sample application, in Chapter 10 we’ll add the kinds of little details (like custom fonts and meta tags) that make a site feel complete. The result will be an industrial-strength, nicely styled site deployed to the live Web.

Finally, as a special bonus, we’ll introduce a more recent and advanced layout technique known as CSS grid in Chapter 11. The result is a largely self-contained discussion of how to use grid to accomplish some of the same effects mentioned in previous chapters, as well as some effects specific to grid.

Let’s go!

1.2 CSS overview and history

CSS takes the form of plain text declarations inserted into an HTML or CSS file using a text editor. A typical series of CSS declarations might look like Listing 1.1. (You are not expected to understand these styles at this point.)

Listing 1.1: Typical CSS declarations.
body {
  color: black;
}

p {
  font-size: 1em;
}

p.highlighted {
  font-size: 1.5em;
  background: yellow;
}

The “Cascading” part of Cascading Style Sheets refers to the way the defined styles flow, or “cascade”, down from element to element on a page based on a few factors like which declaration came first, whether an element is the child of a parent element that has styles applied to it, or the strength of the declaration (more on this in Section 2.3). This inheritance of style (from the top levels to elements below) happens so that we as developers can avoid having to define how every single element should look. For example, if we changed the color in the body tag in Listing 1.1, that change would cascade down and change the color attribute on every interior element as well.

The “Style Sheet” part of the name (sometimes written as the single word stylesheet) refers to how CSS allows developers to collect all the style declarations in a separate section of the page (called an internal stylesheet), or place them into an external file (called, you guessed it, an external stylesheet). External stylesheets are loaded onto the page as a link in the head section of the HTML. (We’ll learn how to do this ourselves in Chapter 5.) The result is that we end up separating the code that defines how something looks (or is positioned) from the actual content—all of which makes for simpler and more maintainable code.

1.2.1 CSS always be changing

One important thing to note about CSS is that, like HTML, it’s constantly evolving to better serve the needs of web designers and developers. In fact, in many ways CSS is evolving even faster than HTML (Figure 1.5).5

images/figures/goldblum
Figure 1.5: CSS… uh, finds a way.

Even though future additions are added to the official CSS specification all the time, they aren’t evenly distributed—when new additions to CSS are proposed, the adoption of those new concepts happens on a browser-by-browser basis. A style that might work in Google Chrome might be totally unsupported by Mozilla Firefox or Microsoft Internet Explorer (or IE’s latest incarnation, Microsoft Edge). Or it’s possible that a given style might be supported, but only if you use a special temporary name to declare the style, a feature that lets developers target only the browsers that support the style they want to use (Box 1.4).

Box 1.4. Vendor Prefixing

Because it takes a while for an addition to the language to go from a suggested new specification (or spec) to an officially included part of CSS, new features aren’t accepted by all browsers at the same time. Most browser makers aren’t interested in waiting around for the spec to be officially updated, though—they want their software to push the envelope and do really cool stuff. So vendors take these CSS spec proposals and implement their own versions of the spec.

To get around the potential confusion that could happen if things work differently from browser to browser, the browser vendors typically add a prefix to the experimental styles, such as -webkit-, -moz-, and -ms- (respectively for WebKit, Mozilla, and Microsoft browsers). This allows the applied style to target specific browsers in case the support differs.

For instance, the CSS transition declaration (covered in Section 7.4) was implemented in most browsers before it was a part of the official spec, and to use it you would have needed to declare the styling like the following examples with vendor prefixes:

  -webkit-transition: all 0.1s linear;
  -moz-transition: all 0.1s linear;
  -ms-transition: all 0.1s linear;
  transition: all 0.1s linear;

The first rule here specifically targets browsers that use the WebKit layout engine (which includes Safari and Chrome), while the second targets browsers using Mozilla’s Gecko engine (principally Firefox), and the third targets Microsoft browsers (Internet Explorer and Edge). Finally, the fourth rule is an unprefixed declaration—in this case, just transition by itself—which is included so that when support becomes official we won’t have to go back into our code and add it in. (The transition style is supported by all major browsers today, so if you see the prefixed versions in code that you are working on, you can safely delete them.)

Luckily, at this point the most common styling definitions are essentially the same across different browsers,6 and we aren’t going to cover anything in this tutorial that has questionable browser support. At some point, though, you’ll probably find yourself wanting to use a more cutting-edge style, and when that happens we recommend using a tool like CanIUse to figure out how well-supported the style is. Don’t ever feel self-conscious about using reference sites like that—the fast-changing nature of the language and the spotty browser support make it a necessary tool even for people who have been doing this for years.

1.2.2 How did CSS develop?

In the beginning, content on the Internet was simply plain text. Then, as methods for organizing content started to come into existence (such as HTML around 1990), a number of methods sprang up to affect the appearance and layout of the data.

At first, many styling solutions that affected how the page looked would be set by individual users’ browser preferences rather than by the creator of the page. As the complexity of the web increased, it became increasingly obvious that there should be a way for the owner of a site to at least suggest how a page should look, rather than leaving the appearance up to each individual browser.

Lots of interesting suggestions were put forward that never got widely adopted, usually because the proposed styling was overly complicated or used a totally non-intuitive structure.

  • Robert Raisch developed RRP, which used arcane two-character style declarations and was fairly unreadable.
  • Pei-Yuan Wei created the ViolaWWW browser and a styling system called PWP, which introduced nesting styles and external stylesheets, but it was only released for Unix operating systems and never really caught on.
  • FOSI was created for an HTML precursor called SGML, and it worked by adding complicated tags on the page around content (not good).
  • DSSSL allowed for complex declarations and was more of a programming language with styling attached, but it had a complicated syntax that made it overly complex for styling.

In short, there was a real Cambrian Explosion of proposed standards to make the web pretty, and while some of these systems ended up contributing elements to what became CSS, none of them are direct ancestors (Figure 1.6).7

images/figures/cambrian
Figure 1.6: There were a lot of precursors to CSS… not all of them successful.

About five years after the introduction of HTML, Håkon Lie (working with Bert Bos) put forward a styling system proposal in December of 1996 called CHSS (Cascading HTML Style Sheets). As you might expect, the original proposal has some details that are no longer present in the language, but in his doctoral thesis Håkon Lie simplified the specification into something that more closely resembles modern CSS. Eventually, the concept was adopted by the World Wide Web Consortium (W3C) as the system for styling web content.

Although it represented a big step forward, creating a specification is only half the battle—browsers have to support the standard for it to be of any use to end-user. No browser even partially supported CSS until 1997, and there wasn’t full support of the standard in any one browser until March of 2000 (Figure 1.7)8—partially because browser makers still had their own ideas for how to accomplish styling, and partially because many browsers supported non-standard HTML tags (we’re looking at you, Internet Explorer…).

images/figures/2000
Figure 1.7: After the party for the new millennium… we got CSS. Hooray?

Each browser handled CSS in its own idiosyncratic way for a long time, and anyone who has been working in front-end development for a while can tell you how maddeningly difficult it was to style a website so that it looked the same across browsers. Microsoft’s Internet Explorer was by far the biggest problem (Figure 1.8) and we can only imagine the number of people who gave up on the world of web design and development thanks to horrific CSS support in early versions of IE.9

images/figures/ie6
Figure 1.8: You can’t fully understand hate until you try to design for IE6.

The differences between implementations of CSS in different browsers remained significant until just a few years ago, with the rise to dominance of the WebKit browsers (Google Chrome and Apple Safari) and Gecko-powered Mozilla Firefox. So when reading this tutorial, just keep in mind that styling the web was a complete and utter mess until very recently—about 15 years after the initial release of the CSS spec in 1997.

1.2.3 The bog of eternal subjectivity

One last bit of meta-information before we jump in and start styling: deciding how to actually implement CSS on a given page can be a confusing mess. Whereas the previous Learn Enough tutorials (Box 1.1) were a little more prescriptive in nature, with many cases where there was only one right way to do things, we are now going to be venturing into places where there is often no right answer. When designing websites with CSS, many solutions to a problem typically exist, which means subjective judgment is the rule rather than the exception (Figure 1.9).10

Helping you navigate this mess is where we come in.

images/figures/bog-of-subjectivity
Figure 1.9: Smell baaaad!

Oh, and to make this all a little more fun, you may recall from Box 1.4 that every browser implements some parts of the CSS standard in its own slightly different manner, so you can never be absolutely certain that something will look the same to different users if they are using different browsers… to say nothing of how something will look on different screen sizes and resolutions for different operating systems (Chapter 9).

You have to get used to the idea that no site is going to be exactly the same when viewed by different people. You’ll learn to design (or implement other people’s designs) in a way that allows room for CSS’s inherent ambiguity. Unlike the tightly constrained world of print design, getting things to look exactly the same in every browser and on every operating system is just something you have to give up worrying about.

Additionally, when talking about which CSS rules to use when styling a site or creating a layout, best practices tend to move in fads, or are influenced by the subjective opinion of the developers who worked on a project before you. For example, as discussed in Section 1.5, elements on the page frequently need to be assigned classes or ids, and the way that names are picked is entirely up to the person writing the code. As you might guess (if you know many developers or designers), people have lots of strong opinions on how you should be naming things—a classic holy war situation (Figure 1.10).11

images/figures/holywar1
Figure 1.10: HOLY WAAAAAAARS!

The most important thing is to be consistent. If you start a project and do things one way, make sure to keep following the same conventions for the life of the project. Or, if you decide to make a drastic change, spend the next couple of days updating all your old code, for the sake of future developers (including yourself). Keep an eye out in this tutorial for “Style Note” boxes that have tips on what the current best practices are for different uses of CSS.

1.3 Sample site setup

Now that we’ve got an overview of the purpose and origins of CSS, it’s time to start looking at some concrete examples. The initial styling rules will necessarily be simple, so it’s important to have patience while we lay this crucial foundation for the working website (with layout) that we’ll be developing starting in Chapter 5.

We’ll start by creating a new project in the repos folder using the same basic mkdir command covered in Learn Enough HTML to Be Dangerous (Listing 1.2).12

Listing 1.2: Adding the folder for our sample project.
$ cd                                   # cd to the home directory
$ mkdir -p repos/<username>.github.io  # Make site directory
$ cd repos/<username>.github.io        # cd into new directory

Note that we’ve used a special directory name that corresponds to the main GitHub Pages site for your account:

<username>.github.io

In Listing 1.2, <username> should be replaced with your GitHub username, so the full URL should look something like mhartl.github.io.

GitHub Pages actually supports serving sites out of subdirectories, like mhartl.github.io/sample_css, but unfortunately this solution fails if you have additional subdirectories in your site, such as mhartl.github.io/sample_css/gallery. The reason is that if you include files and images in one subdirectory (e.g., sample_css), there’s no natural way to include the same files and images in further subdirectories (e.g., sample_css/gallery). Since our sample site will eventually have exactly this kind of structure (Section 6.4), we’ve opted to use the root Pages domain. An even better solution is to use a custom domain, which lets you host your GitHub Pages site at a URL like www.example.com; see the free tutorial Learn Enough Custom Domains to Be Dangerous to learn how to do it.

To get our site started, we’ll also create an index.html file using the touch command (as discussed in Learn Enough HTML to Be Dangerous), as shown in Listing 1.3.

Listing 1.3: Adding a blank index.html.
$ touch index.html    # Create an empty index file

Inside the new folder, use your favorite text editor to open the newly created index.html file and paste in the markup shown in Listing 1.4. For convenience, the contents of Listing 1.4 and all other code listings in this tutorial are available online at the following URL:

https://github.com/learnenough/learn_enough_css_code_listings

You should recognize Listing 1.4 as a very basic HTML page—if this doesn’t look familiar at all, we recommend reviewing Learn Enough HTML to Be Dangerous at this time.

Listing 1.4: The initial HTML for our site. index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Test Page: Don't Panic</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>I'm an h1</h1>
    <ul>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
    </ul>
    <h2>I'm an h2</h2>
    <div style="border: 1px solid black;">
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div style="border: 1px solid black;">
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div style="border: 1px solid black;">
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div style="border: 1px solid black;">
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
  </body>
</html>

When you open that HTML document in your browser (Box 1.5), you’ll see a series of three red links, some headers, and a series of green links in boxes (Figure 1.11). This will be our initial test page.

Note: Due to various slight differences between browsers, browser window sizes, etc., your results may not always match the screenshots exactly, so small discrepancies are not a cause for concern. As we’ll emphasize throughout this tutorial, it’s important to focus on achieving good-enough results without chasing the unreachable goal of pixel-perfection.

images/figures/index-start
Figure 1.11: This is the beginning of something great, unassuming though it may seem.
Box 1.5. Opening HTML files

Depending on your exact setup, there are several ways you might open the HTML file shown in Listing 1.4. The most straightforward way at this stage is to use your native system, which is the main method discussed in Learn Enough HTML to Be Dangerous. On macOS, our favorite way to do this is with the open command, which opens the file using whatever the default program is for that file (e.g., for an HTML file it might use Safari or Chrome, for a PDF it might use Preview, etc.):

  $ open index.html        # macOS only

The similar xdg-open command works on many Linux systems:

  $ xdg-open index.html    # Linux only

You should be aware that using your native system will likely prove increasingly challenging as this tutorial progresses. The reason is that Jekyll, the static site generator we’ll be using starting in Section 5.2, requires setting up your native system as a proper development environment, equipped with programming languages and other software needed to develop websites and dynamic web applications.

Our bet is that, if you’re reading this tutorial, you’re up to the challenge. This means taking the time to follow the steps in Learn Enough Dev Environment to Be Dangerous for your native system (either now or in Chapter 5).

There is one catch which might apply to some readers: there’s no great solution if you’re using Microsoft Windows. Indeed, one perennial challenge when teaching good development practices is the general difficulty of developing programs on Windows operating systems. As described in Learn Enough Dev Environment to Be Dangerous, for Windows users we recommend using either a cloud IDE or a Linux virtual machine. (In fact, the two cases are fundamentally the same, as the cloud IDE we recommend, Cloud9, runs Linux.)

The cloud IDE offers an especially convenient choice for getting up and running quickly, though one downside is that you need to be online to use it. If you do end up using the cloud IDE, opening an HTML file is as simple as clicking “Run” and then clicking the resulting URL to open it (Figure 1.12). (There are actually a couple of other methods that also work. Figuring out this sort of thing on your own is a perfect example of technical sophistication (Box 1.2).)

Eventually, though, it’s a good idea to master your native system (especially if that system is Unix-based, e.g., macOS or Linux). Now’s an excellent time to take that step.

images/figures/open_html_cloud9
Figure 1.12: Opening an HTML file using the cloud IDE.

As in Learn Enough Git to Be Dangerous and Learn Enough HTML to Be Dangerous, we’ll deploy our new website immediately to production, which is a good habit to cultivate. First, you’ll need to create a new project at GitHub, using the steps shown in Learn Enough HTML to Be Dangerous, which in this case looks like Figure 1.13.

images/figures/new_repo
Figure 1.13: Creating a new GitHub repo.

Once you’ve finished the steps needed to create the repository, initialize and deploy it using the commands shown in Listing 1.5. (Because videos are relatively hard to update, the screencasts that accompany this book use master, which was the default branch name for the first 15+ years of Git’s existence, but the text has been updated to use main, which is the current preferred default. See the Learn Enough blog post “Default Git Branch Name with Learn Enough and the Rails Tutorial” for more information.)

Listing 1.5: Deploying the initial site to GitHub Pages.
$ git init
$ git add -A
$ git commit -m "Initialize repo"
$ git remote add origin <repo url>
$ git push -u origin main

If you find the sequence of commands in Listing 1.5 challenging instead of familiar, it’s probably a good idea to review Learn Enough Git to Be Dangerous and Starting the project from Learn Enough HTML to Be Dangerous. (Confirming that the deployment succeeded is left as an exercise (Section 1.3.1).)

Although we’ll add in the occasional Git commit/deployment in this tutorial, in general these will be up to you. Having learned the material in Learn Enough Git to Be Dangerous and Learn Enough HTML to Be Dangerous (or already being familiar with it), now is a good time to practice making such decisions on your own.

1.3.1 Exercises

  1. By visiting the URL <username>.github.io/index.html, confirm that the deployment to GitHub Pages succeeded. Is it necessary to include index.html in the URL?

1.4 Start stylin’

As discussed in Section 1.2, CSS is a way of defining how elements on an HTML page look and are positioned, with styling that flows (“cascades”) down from element to element based on factors like which declaration came first, whether an element is the child of a parent element that has styles applied to it, or the specificity of the declaration.

So what do “parent”, “children”, and “specificity” mean in the context of a web page and how it gets styled?

The idea is that every element on the page is contained inside of another element, which in turn can contain other elements—like Russian nesting dolls (Figure 1.14).13

images/figures/russian_dolls
Figure 1.14: Russian dolls are designed to nest one inside the other.

We can visualize the parent and child structure of the elements on a typical page using the diagram in Figure 1.15.

images/figures/parent-child
Figure 1.15: Relationships always cascade down.

The hierarchical tag structure shown in Figure 1.15 is known as the Document Object Model, or DOM for short.14 Each new level in the DOM is a child of the level above it. In other words, the html tag is the parent of the entire page, the body tag is a child of the html tag, and so on. The body tag then has its own children, which are the h1 and h2 elements, the unordered list ul, and the div elements. In CSS, styling rules flow down from parents to children unless another style interrupts and takes priority.

Our first application of these ideas will be to the repetitive inline styles that exist in our current example page. For example, several div elements share identical inline border styling, as seen in Listing 1.6.15

Listing 1.6: Repeated inline styles violate the DRY principle. index.html
.
.
.
<div style="border: 1px solid black;">
<div style="border: 1px solid black;">
<div style="border: 1px solid black;">
.
.
.

Now that you know about the DRY principle (Box 1.3), all that redundant styling should be causing a mild case of programmer’s itch, and the only cure is to eliminate the duplication. The technique we’ll use is called refactoring, which involves changing the form of the code without changing its function. In other words, after making the changes in this section, the appearance in the browser should remain the same.

To make the example code cleaner, we are going to use a method mentioned in Section 1.2: an internal style sheet. To implement this, we need to use a new HTML element, the style tag (Listing 1.7). This style block will hold all our style declarations, but by design the style tag isn’t visible on rendered pages, and thus won’t be visible in a user’s browser.

Listing 1.7: The initial empty style block for our page. index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Test Page: Don't Panic</title>
    <meta charset="utf-8">
    <style>

    </style>
  </head>
  .
  .
  .

A style block like this can actually be placed anywhere on the page, but the conventional placement is inside the page’s head tag. (The best practice is actually to put the CSS rules in a separate file, a task we’ll undertake in Section 5.5.)

Now let’s get rid of the repetition in Listing 1.6 by adding in our first CSS declaration, as shown in Listing 1.8.16

Listing 1.8: Adding our first CSS style. index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Test Page: Don't Panic</title>
    <meta charset="utf-8">
    <style>
      div {
        border: 1px solid black;
      }
    </style>
  </head>
  .
  .
  .

Figure 1.16 shows the anatomy of the CSS rule from Listing 1.8: the div part of the statement, which is outside the curly braces, is called the CSS selector (in this case targeting only div HTML elements). Then there is a declaration made up of a property (border) and a value (1px solid black) separated from the property by a colon. Finally, there is a semicolon at the end of the line that ends the style. (Just a warning: a lot of these terms get mixed up in regular usage. For example, people will sometimes refer to the whole thing, including the selector, as the declaration.)

images/figures/names
Figure 1.16: What’s in a name?

Although the spacing shown in Listing 1.8 is typical, CSS is similar to HTML in that whitespace is ignored by the browser. For the sake of any humans viewing your markup, though, it’s a good idea to follow certain formatting conventions (Box 1.6).

Box 1.6. Style Note: Formatting styles

The styling statement from Listing 1.8 can also be written with everything on one line, like this:

  div {border: 1px solid black}

While that might look nice and tidy at first, you should probably avoid writing CSS that way, as it would make for unreadable code as you start to add more styles. It is far easier to read a list of style declarations like this:

  button {
    background-color: gray;
    border: 1px solid black;
    color: white;
    cursor: pointer;
    display: inline-block;
    font-family: "proxima-nova", "Proxima Nova",
                 sans-serif;
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 0.15em;
    padding: 10px 15px;
    text-decoration: none;
    text-transform: uppercase;
    transition: all 0.1s linear;
  }

than it is to read this:

  button { background-color: gray; border: 1px solid
  black; color: white; cursor: pointer; display:
  inline-block; font-family: "proxima-nova",
  "Proxima Nova",
  sans-serif; font-size: 12px; font-weight: bold;
  letter-spacing: 0.15em; padding: 10px 15px;
  text-decoration: none; text-transform: uppercase;
  transition: all 0.1s linear}

Now just imagine trying to find specific properties on a page with hundreds of styles where every declaration looks like that… “Nightmare” wouldn’t even begin to describe your development experience.

A second point about formatting is that you’ll notice that the style properties are all in alphabetical order. It might seem annoying to keep your properties alphabetized, but if you do you’ll find that over time you will find things much faster than if the ordering is haphazard. Fortunately, your text editor of choice likely has an alphabetize feature. For example, in Sublime Text you can select multiple lines and hit a function key (F5 on Mac, F9 on Windows) to automatically rearrange things in alphabetic order! Other editors frequently have packages that do the same.

After adding the CSS in Listing 1.8, delete all the style="border: 1px solid black;" attributes from the four div tags. Your test page’s code should now look like Listing 1.9.

Listing 1.9: How the entire page should now look. index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Test Page: Don't Panic</title>
    <meta charset="utf-8">
    <style>
      div {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <h1>I'm an h1</h1>
    <ul>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
      <li>
        <a href="https://example.com/" style="color: red;">Link</a>
      </li>
    </ul>
    <h2>I'm an h2</h2>
    <div>
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div>
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div>
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
    <div>
      <a href="https://example.com/" style="color: green;">I'm a link</a>
    </div>
  </body>
</html>

Save the changes, refresh the page in your browser… and BAM! Everything should look the same. (If not, double-check your work to see if you can get your results to match.)

So what happened here? The declaration that we added in Listing 1.8 is a CSS statement that tells the browser it needs to apply a 1-pixel wide solid black border to all of the divs in the body of the html. (We’ll learn more about pixels in Section 3.3.) The result is a simplification of the code without any change in the page’s appearance.

Now that we’ve seen how to consolidate a bunch of inline styles into a single CSS declaration, let’s do the same thing for the links that are colored red via inline styles inside of the lis. Your new sample page should look like Listing 1.10.

As before, the appearance shouldn’t change after refreshing the browser.

At this point, we’ve definitely made progress in the fight against inline style redundancy, but what about those links that are colored green at the bottom using inline styling? One way to clean up the inline styles would be to use CSS classes, which we’ll start covering in Section 1.5, but for now let’s see if we can do it with just generic CSS selectors.

Because the links in question are contained inside of divs, and the other links on the page are not, we can use the nesting inheritance of CSS to define a style that changes only the color of links inside of divs. We can accomplish this by adding the declaration from Listing 1.11 to the style block, and then remove the inline styles from the links on the page.

Your entire test page should now look like Listing 1.12.

The page is a lot cleaner now, isn’t it? Separating the styling from the content makes the page’s code much easier to read, but maybe you can already see the problem with the way that we’ve targeted the styles…

The problem is: if we were to add new divs anywhere on the page, and they happened to have links inside them, those links would be green even if that isn’t what we want. The reason why is that the selector we used in that declaration is way too generic. In Section 1.5, we’ll take a look at how to add styling with far greater specificity using CSS ids and classes.

1.4.1 Exercises

  1. Using what we learned about targeting links inside of other objects, change the color of the links inside of the lis.
  2. Add a border around the lis using the same styling as we used to add the borders around the divs.

1.5 CSS selectors

Between Learn Enough HTML to Be Dangerous and the beginning of this tutorial, we have so far used only rudimentary targeting techniques for styles. In Learn Enough HTML to Be Dangerous, we learned how to add styles directly to elements, but this approach is brittle and inefficient. In this tutorial, so far we’ve used CSS that is separated from the content, but we have used only generic selectors like div or a. The problem with generic element selectors is that they apply to all the elements on the page. So, how can we apply styling to specific elements rather than to every single one?

There are two methods, one that targets only one element per page—the id (or “identification”) selector17—and one able to target multiple elements—the class selector. Let’s edit our example HTML to add this kind of targeting to our page.

Ids and classes are always applied only to the opening tag of an element, and they always have the same format. We’ll use the div tag for concreteness:

<div id="foo" class="bar">
  .
  .
  .
</div>

We see here that both ids and classes consist of key/value pairs, where each value is a string that serves as a label for the id or class. In this case, the key id has value "foo" and the key class has value "bar".

Although CSS offers a great deal of flexibility in choosing id and class names, there are a few restrictions and usage suggestions:

  • Use only one id per element.
  • No numbers are allowed at the beginning of the name (e.g., name1 is valid, but 1name isn’t).
  • Dashes (-), underscores _, and CamelCase can be used to join multiple words (so foo-bar-baz, foo_bar_baz, and FooBarBaz are all valid names).
  • Spaces are invalid in id names, and are used to separate multiple names in the case of classes (so id="foo bar" is illegal, while class="foo bar baz" places three separate classes on an element).
  • Be consistent (e.g., if using dashes as separators, use them everywhere—don’t mix them with underscores).

To see how this works in practice, let’s add some ids and classes to our sample page. On the first opening div tag that comes right after the h2, add id="exec-bio", and then add class="bio-box" to all of the divs in that section, as shown in Listing 1.13).

Listing 1.13: Adding CSS classes and an id to the sample page. index.html
<!DOCTYPE html>
<html>
  .
  .
  .
  <body>
    .
    .
    .
    <h2>I'm an h2</h2>
    <div id="exec-bio" class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
  </body>
</html>

(This use of a class is good CSS practice, but we generally don’t recommend using an id in this context; we include it here mainly for demonstration purposes. We’ll discuss this issue in more detail in Section 2.2.)

Next, let’s update our CSS block to target these new selectors. To target an id in CSS, you put a # (usually read “hash”) in front of the name, and to target a class you add a . (usually read “dot”). For example, to change the background color of the #exec-bio id, we can use the following CSS rule:

#exec-bio {
  background-color: lightgray;
}

(Here lightgray represents (surprise!) a light gray,18 which is an example of a CSS color name. We’ll cover the details of color naming in Section 3.1.) Similarly, to apply a rule to the .bio-box class,19 we can use the following CSS:

.bio-box {
  border: 1px solid black;
}

As we’ll see in a moment, this rule keeps the thin black border added in Listing 1.9, but in such a way that it doesn’t apply to all the divs on the site.

Finally, we can target the anchor tags inside the bio boxes using the combination of the class name and the tag name, like this:

.bio-box a {
  color: green;
}

This turns the a tags green, but only if they’re inside an element with class "bio-box". This class-based approach gives us much finer-grained control than the method used in Listing 1.11.

Adding these three rules to the style block (while removing the rules we no longer need) leads to the markup shown in Listing 1.14.

Listing 1.14: Adding CSS rules to target the classes and id. index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Test Page: Don't Panic</title>
    <meta charset="utf-8">
    <style>
      a {
        color: red;
      }
      #exec-bio {
        background-color: lightgray;
      }
      .bio-box {
        border: 1px solid black;
      }
      .bio-box a {
        color: green;
      }
    </style>
  </head>
  <body>
    .
    .
    .
    <h2>I'm an h2</h2>
    <div id="exec-bio" class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
    <div class="bio-box">
      <a href="https://example.com/">I'm a link</a>
    </div>
  </body>
</html>

After saving your changes and refreshing the browser, you should see that the boxes at the bottom have the same border as before, but now the one with the CSS id now has a light gray background (Figure 1.17).

images/figures/selectors
Figure 1.17: Elements targeted with classes and ids.

Congrats! You’ve just used ids and classes to target styles at specific elements, and have leveled up your CSS knowledge. Now that you’ve learned how to make declarations, and how to use ids and classes, we can now start getting into the nitty gritty of how CSS works.

1.5.1 Exercises

  1. Try adding a new CSS id to the style section (you pick the name) that sets the background color of an element to orange, and then add that id to one of the links on the page.
  2. Add a new class to the style section (you pick the name again) that changes the background color to azure, and add that class name as a second class on the .bio-boxes. You’ll notice that one box is different from the rest, something that we’ll discuss in Section 2.3.
  3. Commit your changes from this chapter and deploy the result to GitHub Pages. Confirm that the deployed site renders correctly. (It may take a minute or two for the cache to clear, so keep refreshing until the result is what you expect.)

Join the Mailing List

Get occasional notifications about things like product discounts, blog posts, and new or updated tutorials. Unsubscribe at any time.