Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
The HTML and CSS Workshop

You're reading from   The HTML and CSS Workshop Learn to build your own websites and kickstart your career as a web designer or developer

Arrow left icon
Product type Paperback
Published in Nov 2019
Publisher Packt
ISBN-13 9781838824532
Length 700 pages
Edition 1st Edition
Languages
Concepts
Arrow right icon
Authors (4):
Arrow left icon
Matt Park Matt Park
Author Profile Icon Matt Park
Matt Park
Brett Jephson Brett Jephson
Author Profile Icon Brett Jephson
Brett Jephson
Marian Zburlea Marian Zburlea
Author Profile Icon Marian Zburlea
Marian Zburlea
Lewis Coulson Lewis Coulson
Author Profile Icon Lewis Coulson
Lewis Coulson
Arrow right icon
View More author details
Toc

Table of Contents (15) Chapters Close

Preface 1. Introduction to HTML and CSS 2. Structure and Layout FREE CHAPTER 3. Text and Typography 4. Forms 5. Themes, Colors, and Polish 6. Responsive Web Design and Media Queries 7. Media – Audio, Video, and Canvas 8. Animations 9. Accessibility 10. Preprocessors and Tooling 11. Maintainable CSS 12. Web Components 13. The Future of HTML and CSS Appendix

Structuring an HTML Document

A requirement of HTML5 is that all HTML documents are structured with a root element, the html element, and two child elements, the head element, and the body element.

HTML

The html element is the root element of an HTML document. In an HTML document, the only thing that appears outside the html element is the doctype declaration, which appears above the html element. Before we put any content on our web page, the code looks like this:

<!doctype html>
<html lang="en"></html>

The html element is the top-level element and all other elements must be a descendant of it. The html element has two children – one head element and a body element, which must follow the head element.

It is strongly recommended that you add a lang attribute to your html element to allow the browser, screen readers, and other technologies, such as translation tools, to better understand the text content of your web page.

Head

The head element contains metadata. It stores information about the HTML document that is used by machines – browsers, web crawlers, and search engines – to process the document. This section of an HTML document is not rendered for human users to read.

The minimum content the head element can have is a title element. Within a web page, the code would look like this:

<!doctype html>
<html lang="en">
    <head>
        <title>Page Title</title>
    </head>
</html>

Body

An HTML element is expected to have one body element and it is expected to be the second child of the html element following the head element.

Our minimal HTML document would therefore have the following code:

<!doctype html>
<html lang="en">
    <head>
        <title>Page Title</title>
    </head>
    <body>
    </body>
</html>

The body element represents the content of the document. Not everything in the body will necessarily be rendered in the browser, but all human-readable content should be hosted in the body element. This includes headers and footers, articles, and navigation.

You will learn more about the elements that can be the content of the body element throughout the following chapters.

Our First Web Page

In our first example, we will create a very simple web page. This will help us to understand the structure of an HTML document and where we put different types of content.

Exercise 1.01: Creating a Web Page

In this exercise, we will create our first web page. This is the foundation upon which the future chapters will build.

Note

Before beginning the exercises in the book, please make sure you have followed the instructions given in the Preface regarding installing VSCode and the extension Open In Default Browser.

The steps are as follows:

  1. To start, we want to create a new folder, named Chapter01, in a directory of your choice. Then open that folder in Visual Studio Code (File > Open Folder…).
  2. Next, we will create a new plain text file by clicking File > New File. Then, save it in HTML format, by clicking File > Save As... and enter the File name: Exercise 1.01.html. Finally, click on Save.
  3. In Exercise 1.01.html, we start by writing the doctype declaration for HTML5:
    <!DOCTYPE html>
  4. Next, we add an HTML tag (the root element of the HTML document):
    <html lang="en">
    </html>
  5. In between the opening and closing tags of the html element, we add a head tag. This is where we can put metadata content. For now, the head tag will contain a title:
    <head>
        <title>HTML and CSS</title>
    </head>
  6. Below the head tag and above the closing html tag, we can then add a body tag. This is where we will put the majority of our content. For now, we will render a heading and a paragraph:
    <body>
        <h1>HTML and CSS</h1>
        <p>How to create a modern, responsive website with HTML and CSS</p>
    </body>

If you now right-click on the filename in VSCode on the left-hand side of the screen and select Open In Default Browser, you will see the following web page in your browser:

Figure 1.10: The web page as displayed in the Chrome web browser

Figure 1.10: The web page as displayed in the Chrome web browser

Metadata

The head element is home to most machine-read information in an HTML document. We will look at some commonly used metadata elements and how they enhance a web page and how they can optimize a web page for search engines and modern browsers.

The following elements are considered metadata content: base, link, meta, noscript, script, style, and title.

We've already added a title element in the previous exercise. This is the name of your web page and it appears in the tab of most modern browsers as well as in a search engine's results as the heading for the web page's listing.

The link element lets us determine the relationships between our document and external resources. A common use for this element is to link to an external style sheet. We will look at that use case in the section on CSS later in this chapter. There are several other uses for the link element. These include linking to icons and informing the browser to preload assets.

The base element lets you set a base URL. This will be used as the base for all relative URLs in the HTML document. For example, we could set the base href and then link to a style sheet with a relative URL:

<base href="http://www.example.com">
<link rel="stylesheet" href="/style.css">

This would result in our browser trying to download a style sheet from http://www.example.com/style.css.

The meta element acts as a catch-all for other metadata not represented by the other metadata content elements. For example, we can use the meta element to provide a description or information about the author of the web page.

Another use for the meta element is to provide information about the HTML document, such as the character encoding used. This can be very important as text characters will render differently or not at all if not set correctly. For example, we normally set the character encoding to UTF-8:

<meta charset="utf-8">

This character encoding declaration tells the browser the character set of the document. UTF-8 is the default and is recommended. This gives information to the browser but does not ensure the document conforms to the character encoding. It is also necessary to save the document with the correct character encoding. Again, UTF-8 is often the default but this varies with different text editors.

It is important that the character encoding declaration appears early in the document as most browsers will try to determine the character encoding from the first 1,024 bytes of a file. The noindex attribute value is set for the web pages that need not be indexed, whereas the nofollow attribute is set for preventing the web crawler from following links.

Another meta element that is very useful for working with mobile browsers and different display sizes is the viewport element:

<meta name="viewport" content="width=device-width, initial-scale=1">

The viewport element is not standard but is widely supported by browsers and will help a browser define the size of the web page and the scale to which it is zoomed on smaller display sizes. The units of viewport height and viewport width are vh and vw respectively; for example, 1vh = 1% of the viewport height. We will dive deeper into the viewport element and other aspects of responsive web development in Chapter 6, Responsive Web Design and Media Queries.

The script element lets us embed code in our HTML document. Typically, the code is JavaScript code, which will execute when the browser finishes parsing the content of the script element.

The noscript element allows us to provide a fallback for browsers without scripting capabilities or where those capabilities are switched off by the user.

We will look at the style element in more detail when we look at CSS later in this chapter.

These elements won't appear on the web page as content the user sees in the browser. What they do is give web developers a lot of power to tell a browser how to handle the HTML document and how it relates to its environment. The web is a complex environment and we can describe our web page for other interested parties (such as search engines and web crawlers) using metadata.

Exercise 1.02: Adding Metadata

In this exercise, we will add metadata to a web page to make it stand out in search engine results. The page will be a recipe page for a cookery website called Cook School. We want the page's metadata to reflect both the importance of the individual recipe and the larger website so it will appear in relevant searches.

To achieve this, we will add metadata – a title, a description, and some information for search engine robots. On the web, this information could then help users find a blog post online via a search engine.

Here are the steps we will follow:

  1. Open the Chapter01 folder in VSCode (File > Open Folder…) and create a new plain text file by clicking File > New File. Then, save it in HTML format by clicking File > Save As...and enter the File name: Exercise 1.02.html. Next, we will start with a basic HTML document:
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <!-- Metadata will go in the head -->
        </head>
        <body>
            <!-- Cupcake recipe will go in the body -->
        </body>
    </html>
  2. Let's add a title for the recipe page that will be relevant to users who have navigated to the page or who are looking at a search engine results page. We will add this to the head element:
    <title>Cook School - Amazing Homemade Cupcakes</title>
  3. Just after the opening <head> element, we will add a metadata element, <meta>, to let the browser know which character encoding to use:
    <meta charset="utf-8">
  4. Next, we are going to add a description meta element below the title element:
    <meta name="description" content="Learn to bake delicious, homemade cupcakes with this great recipe from Cook School.">
  5. We will add another meta element. This time, it is the robots meta element, which is used to make search engine crawling and indexing behave in a certain way. For example, if you didn't want a page to be indexed by a search engine, you could set the value to noindex. We will set a value of nofollow, which means a web crawler will not follow links from the page:
    <meta name="robots" content="nofollow">

    If you don't set this tag, the default value will be index and follow. This is normally what you want but you might not want a search engine to follow links in comments or index a particular page.

  6. The viewport meta element, which is very useful for working with mobile browsers and different display sizes, is added just below the title element in the head element:
    <meta name="viewport" content="width=device-width, initial-scale=1">
  7. To finish, let's add some content to the body element that correlates with the metadata we've added:
    <h1>Cook School</h1>
    <article>
        <h2>Amazing Homemade Cupcakes</h2>
        <p>Here are the steps to serving up amazing cupcakes:</p>
        <ol>
             <li>Buy cupcakes from a shop</li>
             <li>Remove packaging</li>
             <li>Pretend you baked them</li>
         </ol>
    </article>

If you now right-click on the filename in VSCode on the left-hand side of the screen and select Open In Default Browser, you will see the following web page in your browser:

Figure 1.11: The web page as displayed in the Chrome web browser

Figure 1.11: The web page as displayed in the Chrome web browser

The important thing in the relationship between content and metadata is that they should make sense together. There is no point in adding keywords or writing a description of cars if the article is about cupcakes. The metadata should describe and relate to your actual content.

There are many search engines out there and they all do things a bit differently, and often with their own bespoke meta elements. If you would like to know more about how Google's search engine understands the meta tags from your web page's source code, some information is available at https://packt.live/35fRZ0F.

Mistakes in HTML

Most browsers do their best to render a web page even if the HTML does not comply perfectly with the W3C's HTML5 standard. One area where HTML5 differs from the previous versions, including XHTML, is that the standard gives detailed instructions for browser developers on how to handle mistakes and issues in an HTML5 document. HTML5 tries to standardize how browsers handle problems and there is a lot of flexibility built into the standard (such as optional omitted end tags).

With that said, there are still many ways that an HTML document might be wrong due to typos, omitted tags, or the incorrect use of tags. Let's look at a few potential mistakes.

A common problem is a missing or mistyped closing tag. Here, we can see an example: in the following snippet of HTML, we have a paragraph with two anchor elements, both of which are pointing at different pages of the Packt website:

<p>
    Learn about <a href="https://www.packtpub.com/web-development">web     development</a>. Try out some of the <a     href="https://www.packtpub.com/free-learning">Free learning on the     Packt site.
</p>
<p>
    Lorem ipsum...
</p>

There is one problem with this code. The second link does not have a closing tag and so the anchor element never closes. This makes the rest of the paragraph and the next paragraph in the document the same anchor tag. Anything beneath the opening anchor tag (<a>) until another closing anchor tag (</a>) would become an active link due to this mistake.

We can see the result in the following figure where the link text runs on to the second paragraph:

Figure 1.12: Missing closing tag on an anchor element

Figure 1.12: Missing closing tag on an anchor element

Some issues are not to do with syntax error but are regarding the semantic constraints of HTML5. In other words, an element might have a specific role or meaning and having more than one instance might not make sense.

For example, the main element describes the main content of an HTML document. There should never be more than one main element visible on a web page at any one time.

The following code would not be valid:

<body>
     <main id="main1"><!-- main content here … --></main>
     <main id="main2"><!-- more main content here ... --></main>
</body>

However, if we were to hide one of the instances of the main element and only render that one when we hide the other, we would be using the main element in a way that is acceptable. The browser could still determine what the main content of our web page is. For example, the following code would be valid:

<body>
     <main id="main1"><!-- main content here … --></main>
     <main id="main2" hidden><!-- more main content here ... --></main>
</body>

Look carefully and you will see that we have added the hidden attribute to the second instance of the main element. This means there is only one visible main element in the web page.

You will learn more about main and other structural elements in the next chapter.

Sometimes, mistakes are caused by not knowing the specification. Take, for example, Boolean attributes such as the disabled attribute. We can apply this attribute to some interactive elements such as form inputs and buttons.

A button element creates a clickable button UI on a web page. We can use this element to trigger form submissions or to change the web page. We can use the disabled attribute with this element to stop it from submitting or taking any action.

If we add the disabled attribute like this, <button disabled="false">Click me!</button>, we might expect this element to be enabled. We've set the disabled attribute to false, after all. However, the specification for the disabled attribute says that the state of the element is decided by whether the attribute is present or not and the value is not regarded. To enable the element, you must remove the disabled attribute.

Because of the ways most modern browsers try to correct problems in HTML5 documents, it might not be immediately obvious what the benefits of making your HTML document valid are. However, it is good to keep in mind that, while developing for the web, you could have an audience on a variety of browsers – not all of them the most modern. Equally, it is still very easy to make mistakes that will cause obvious rendering issues. The best way to solve these is to make sure your document is valid and therefore working as expected.

There are tools available to help you check that your web page is valid. In the forthcoming exercise, we will look at how we can use an online tool to validate a web page.

Validating HTML

Mistakes in HTML5 can cause our web pages to render in ways we are not expecting. They can also cause problems for screen reader technologies that rely on the semantic meaning of HTML elements. Thankfully, there are some really useful tools out there to automate the validation of our HTML document and to keep us from making costly mistakes.

In this section, we will introduce the W3C's Markup Validation Service, an online tool that will validate a web page for us. We will then try out the tool with the help of exercises.

W3C's Markup Validation Service is an online tool that lets us validate a web page. The tool is available at https://packt.live/323qgOI. Navigating to that URL, we will see the tool as in the following figure:

Figure 1.13: The W3C's Markup Validation Service

Figure 1.13: The W3C's Markup Validation Service

There are several options available, depending on how you wish to provide the validator a web page to validate. The options are:

  • Validate by URI – choose a publicly accessible URL you wish to validate
  • Validate by File Upload – validate a file uploaded from your computer
  • Validate by Direct Input – copy and paste code to validate

As well as these input options, you have some more advanced options under the More Options heading, as seen in the following figure:

Figure 1.14: The More Options panel of the W3C's Markup Validation Service

Figure 1.14: The More Options panel of the W3C's Markup Validation Service

With these options, you can:

  • Set the character encoding and document type
  • Group error messages
  • Show source code
  • Set the level of output (verbose)

Once you hit the Check button on the validator, it will run the tool and your results will appear in the results panel. You will either see a message telling you your document is valid or you will see a list of errors describing where the document is invalid and possible reasons.

We will see examples of both these results in the next two exercises.

Exercise 1.03: Validation

In this exercise, we will validate a web page using the W3C's Markup Validation Service. The steps are as follows:

  1. For this exercise, we need a web page to validate. Create a new file within the Chapter01 folder by clicking File > New File. Then, save it in HTML format, by clicking File > Save As...and enter the File name: Exercise 1.03.html. Copy the following content into the file:
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Valid HTML document</title>
            <meta name="viewport" content="width=device-width,           initial-scale=1">
        </head>
        <body>
            <h1>Valid HTML document</h1>
            <p>This document is valid HTML5.</p>
            <!-- 
                This document will not throw errors in 
                W3C's Markup Validation Service 
            -->
        </body>
    </html>
  2. In a browser, navigate to https://packt.live/323qgOI. This will take you to the W3C's online Markup Validation Service.
  3. You can validate web pages by URI, file upload, or copy and paste. We will use the file upload method. Click the Validate by File Upload tab.
  4. Click the Choose file button to select the Exercise 1.03.html file.
  5. Click the Check button.

If all went well, we should see a results page similar to that shown in the following figure, where there is green highlighted text saying Document checking completed. No errors or warnings to show. This means we have a valid HTML document:

Figure 1.15: W3C's Markup Validation Service results page with no errors

Figure 1.15: W3C's Markup Validation Service results page with no errors

Exercise 1.04: Validation Errors

Now we will see what happens if the HTML document does not validate. Here are the steps:

  1. Firstly, we need a web page with some errors in its source code. Create a new file under Chapter01 folder by clicking File > New File. Then, save it in HTML format, by clicking File > Save As... and enter the File name: Exercise 1.04.html.
  2. In Exercise 1.04.html, we will add the following content:
    <html lang="en">
        <head>
        </head>
        <body>
            <p>Hello world!</p>
            <title>My first web page</title>
        </body>
    </html>

    This HTML document has some problems that should cause validation errors when this page is run through the W3C's validation service.

  3. Repeat the steps from Exercise 1.03, Validation, uploading the Exercise 1.04.html file in place of the valid file.

    The results should look like the following figure. Each error is flagged with a line number. In our case, there should be three errors because the doctype is missing, a <title> element is expected in the <head> element of the document, and <title> is not allowed as a child of the <body> element.

    The error messages can point out issues with the content model, such as the <title> element missing in a <head> element, as well as issues where an opening tag does not have a corresponding closing tag:

Figure 1.16: Validation errors in the W3C's Markup Validation Service

Figure 1.16: Validation errors in the W3C's Markup Validation Service

The HTML5 standard is pretty robust and tries to handle things such as omitted closing tags, but it is still possible to cause errors with typos or missed tags, and so the validator is a very useful tool. A valid HTML document is likely to be better optimized for performance, cause fewer bugs in JavaScript or CSS, and be easier for web crawlers, search engines, and browsers to understand.

Activity 1.01: Video Store Page Template

We've been tasked with creating a website for an online on-demand film store called Films On Demand. We don't have designs yet but want to set up web page boilerplate that we can use for all the pages on the site.

We will use comments as placeholders to know what needs to change for each page that is built on top of the boilerplate template. For visible content in the body element, we will use lorem ipsum to get an idea of how content will flow.

The following figure shows the expected output for this activity:

Figure 1.17: Expected output for the video store page template

Figure 1.17: Expected output for the video store page template

The steps are as follows:

  1. Create a file named Activity 1.01.html.
  2. We want the page to be a valid HTML5 document. So, we will need to add the following:

    The correct doctype definition.

    Elements to structure the document: the html element, the head element, and the body element.

    A title element that combines the Films on Demand brand with some specifics about the current page.

    Metadata to describe the site – we'll set this to Buy films from our great selection. Watch movies on demand.

    Metadata for the page character set and a viewport tag to help make the site render better on mobile browsers.

  3. We want to add placeholders for a heading (an h1 element) for the page, which we will populate with lorem ipsum and a paragraph for the content flow, which we will also populate with the following lorem ipsum text:

    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis scelerisque mauris. Curabitur aliquam ligula in erat placerat finibus. Mauris leo neque, malesuada et augue at, consectetur rhoncus libero. Suspendisse vitae dictum dolor. Vestibulum hendrerit iaculis ipsum, ac ornare ligula. Vestibulum efficitur mattis urna vitae ultrices. Nunc condimentum blandit tellus ut mattis. Morbi eget gravida leo. Mauris ornare lorem a mattis ultricies. Nullam convallis tincidunt nunc, eget rhoncus nulla tincidunt sed.

    Nulla consequat tellus lectus, in porta nulla facilisis eu. Donec bibendum nisi felis, sit amet cursus nisl suscipit ut. Pellentesque bibendum id libero at cursus. Donec ac viverra tellus. Proin sed dolor quis justo convallis auctor sit amet nec orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."

    Note

    The solution for this activity can be found via this link.

CSS

Cascading Style Sheets (CSS) is a style sheet language used to describe the presentation of a web page. The language is designed to separate concerns. It allows the design, layout, and presentation of a web page to be defined separately from content semantics and structure. This separation helps keeps source code readable and it is important because a designer can update styles separately from a developer who is creating the page structure or a web editor who is changing content on a page.

A set of CSS rules in a style sheet determines how an HTML document is displayed to the user. It can determine whether elements in the document are rendered at all, whether they appear in some context but not others, how they are laid out on the web page, whether they are rendered in a different order to the order in which they appear within a document, and their aesthetic appearance.

We will begin by looking at the syntax of CSS.

Syntax

A CSS declaration is made of two parts: a property and a value. The property is the name for some aspect of style you want to change; the value is what you want to set it to.

Here is an example of a CSS declaration:

color: red;

The property is color and the value is red. In CSS, color is the property name for the foreground color value of an element. That essentially means the color of the text and any text decoration (such as underline or strikethrough). It also sets a currentcolor value.

For this declaration to have any effect on an HTML document, it must be applied to one or more elements in the document. We do this with a selector. For example, you can select all the <p> elements in a web page with the p selector. So, if you wanted to make the color of all text in all paragraph elements red, you would use the following CSS ruleset:

p {
  color: red;
}

The result of this CSS ruleset applied to an HTML document can be seen in the following figure:

Figure 1.18: Result of a CSS rule applied to <p> elements in HTML

Figure 1.18: Result of a CSS rule applied to <p> elements in HTML

The curly braces represent a declaration block and that means more than one CSS declaration can be added to this block. If you wanted to make the text in all paragraph elements red, bold, and underlined, you could do that with the following ruleset:

p {
  color: red;
  font-weight: bold;
  text-decoration: underline;
}

The result of this CSS ruleset applied to an HTML document can be seen in the following figure:

Figure 1.19: Several CSS declarations applied to <p> elements in HTML

Figure 1.19: Several CSS declarations applied to <p> elements in HTML

Multiple selectors can share a CSS ruleset. We can target these with a comma-separated list. For example, to apply the color red to p elements, h1 elements, and h2 elements, we could use the following ruleset:

p, h1, h2 {
  color: red;
}

Multiple CSS rulesets form a style sheet. The order of these CSS rules in a style sheet is very important as this is partly how the cascade or specificity of a rule is determined. A more specific rule will be ranked higher than a less specific rule and a higher-ranked rule will be the style shown to the end user. We will look at cascade and specificity later in this chapter:

Figure 1.20: A CSS ruleset explained

Figure 1.20: A CSS ruleset explained

Adding Styles to a Web Page

There are several ways to add your styles to a web page:

  • You can use inline styles, which are applied directly to an element in the HTML document using the style attribute. The value of the style attribute is a CSS declaration block, meaning you can apply a semicolon-separated list of CSS declarations to the element.
  • You can use a style element to add style information to an HTML document. The style element can be a child of either the head element or body element of a document. The head element tends to be preferable as the styles will be applied to your page more quickly.
  • You can provide a style sheet as an external resource using the link element. One of the rationalities behind style sheets is the separation of concerns, which is why this approach is often recommended.

We will try out each of these methods in the following exercises.

Exercise 1.05: Adding Styles

In this exercise, we will be styling web pages by adding styles within the HTML document itself.

Here are the steps:

  1. Open the Chapter01 folder in VSCode (File > Open Folder…) and we will create a new plain text file by clicking File > New File. Then, save it in HTML format, by clicking File > Save As... and enter the File name: Exercise 1.05.html and start with the following web page:
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Adding styles</title>
        </head>
        <body>
            <h1>Adding styles</h1>
            <p>First paragraph</p>
            <p>Second paragraph</p>
        </body>
    </html>

    Without any styles, this web page would look like the following:

    Figure 1.21: The unstyled web page

    Figure 1.21: The unstyled web page

  2. We've decided to use a nicer font and make some of the text red. To do this, we will add a style element to the head element. We can add the following code under the title element:
    <style>
     h1 {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 24px;
        margin: 0;
        padding-bottom: 6px;
     }
     p {
        color: red;
     }
    </style>

    The results of this code change are that we should now have styles applied to the h1 element and to both of the p elements, all of which will have red text. The result will look similar to the following figure:

    Figure 1.22: The web page with styles applied

    Figure 1.22: The web page with styles applied

  3. Finally, we will give the first paragraph element a different style by overriding the style set in the head element. Let's add an inline style to the first paragraph, setting the color to blue and adding a line-through text decoration as follows:
            <p style="color: blue; text-decoration: line-          through">First paragraph</p>

If you now right-click on the filename in VSCode on the left-hand side of the screen and select Open In Default Browser, you will see the following web page in your browser:

Figure 1.23: The web page with inline style applied

Figure 1.23: The web page with inline style applied

Something to note is that the inline style, applied to the first paragraph, takes precedence over the more general CSS rule applied to all p elements in the style element in the head element of the document. We will look at specificity and the rules of the cascade later in this chapter, but first, let's try moving these style rules into an external file.

Exercise 1.06: Styles in an External File

In this exercise, we will separate the concerns of presentation and structure of Exercise 1.05, Adding Styles, by moving all the styles to an external file.

The steps are as follows:

  1. Open the Chapter01 folder in VSCode (File > Open Folder…) and create a new plain text file by clicking File > New File. Then, save it in HTML format, by clicking File > Save As... and enter the File name: Exercise 1.06.html.
  2. Add the same web page as in Exercise 1.05, Adding Styles, to the file:
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Adding styles</title>
        </head>
        <body>
            <h1>Adding styles</h1>
            <p>First paragraph</p>
            <p>Second paragraph</p>
        </body>
    </html>
  3. We will add a link element to reference a .css file below the title element:
    <link href="styles/Exercise_1.06.css" rel="stylesheet">
  4. Create a styles directory in the same directory as Exercise 1.06.html. Next, create a file named Exercise_1.06.css within the styles directory.
  5. Now, add the following styles to Exercise_1.06.css:
    h1 {
      font-family: Arial, Helvetica, sans-serif;
      font-size: 24px;
      margin: 0;
      padding-bottom: 6px;
    }
    p {
      color: red;
    }
  6. To get the equivalent styles that we had at the end of Exercise 1.05, Adding Styles, without using an inline style, we have to have a specific way of targeting the first p element. We will use the :first-of-type pseudo-class. You will learn more about CSS selectors later in this chapter. For now, add this CSS rule to the bottom of Exercise_1.06.css:
    p:first-of-type {
      color: blue;
      text-decoration: line-through;
    }

The result will be as seen in Figure 1.23 – the same result as in Exercise 1.05, Adding Styles. The difference is that we have removed all references to styles from the HTML document into their own external resources. We have successfully separated concerns.

Both these methods add styles to the HTML document when it loads. Similar to the HTML DOM, we can manipulate CSS programmatically with JavaScript. This is because the styles are also represented as an object model called the CSSOM.

CSSOM

The CSS Object Model (CSSOM) is similar to the HTML DOM, which we described earlier. The CSSOM is an in-memory representation of the styles in the document as they are computed on elements. It is a tree-structure with nodes that mirror those in the HTML DOM, and the objects associated have a list of style properties where all CSS rules have been applied.

The CSSOM represents all the styles that have been created in the document as objects with properties that we can change with JavaScript. We can access these styles and change the values of style properties.

We mostly access these styles via the style property of a DOM element, as here:

const boldElement = document.querySelector('.aBoldElement');
boldElement.style.fontWeight = 'bold';

In JavaScript, we can also access the CSSOM with the getComputedStyle method on the window object; for example:

const boldElement = document.querySelector('.aBoldElement');
window.getComputedStyle(boldElement);

This will return a computed styles object for an element with the aBoldElement class attribute. This method returns a read-only styles object with all computed styles for the element.

In the next section, we will look at the different CSS selectors we can use to apply our styles to a web page.

CSS Selectors

To target elements in the HTML document with CSS, we use selectors. There are a lot of options available to help you select a wide range of elements or very specific elements in certain states.

Selectors are a powerful tool and we will look at them in some detail as the different options available can help with both web page performance and making your CSS more maintainable.

For example, you can use a selector to target the first letter of a heading, like you might expect to see in a medieval book:

h1::first-letter { 
  font-size: 5rem; 
}

Or you could use a selector to invert the colors of every odd paragraph in an article:

p {
  color: white;
  background-color: black;
}
p:nth-of-type(odd) { 
  color: black;
  background-color: white;
}

We will explore a variety of the options available to us when creating selectors.

Element, ID, and Class

Three commonly used selectors are:

  • Element type: For example, to select all p elements in an HTML document, we use the p selector in a CSS ruleset. Other examples are h1, ul, and div.
  • A class attribute: The class selector starts with a dot. For example, given the HTML snippet <h1 class="heading">Heading</h1>, you could target that element with the .heading selector. Other examples are .post and .sub-heading.
  • An id attribute: The id selector starts with a hash symbol. For example, given the HTML snippet <div id="login"> <!-- login content --> </div>, you could target this element with the #login selector. Other examples include #page-footer and #site-logo.

The Universal Selector (*)

To select all elements throughout an HTML document, you can use the universal selector, which is the asterisk symbol (*). Here is an example snippet of CSS that is often added to web pages; a value is set on the html element and then inherited by all descendant elements:

html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}

Using the inherit keyword and the universal selector, we can pass a value on to all the descendants of the html element. This snippet will universally apply the border-box model to all elements and their pseudo-elements (that's the reason for :before and :after). You'll learn more about the box model and layout in the next chapter.

Attribute Selectors

Attribute selectors let you select elements based on the presence of an attribute or based on the value of an attribute. The syntax is square brackets, [], with the suitable attribute inside. There are several variations that you can use to make matches:

  • [attribute] will select all elements with an attribute present; for example, [href] will select all elements with an href attribute.
  • [attribute=value] will select all elements with an attribute with an exact value; for example, [lang="en"] will select all elements with a lang attribute set to en.
  • [attribute^=value] will select all elements with an attribute with a value that begins with the matching value; for example, [href^="https://"] will select all elements with an href attribute beginning with https://, which links to a secure URL.
  • [attribute$=value] will select elements with an attribute with a value that ends with the matching value; for example, [href$=".com"] will select all elements with an href attribute that ends with .com.
  • [attribute*=value] will select elements with an attribute with a value that has a match somewhere in the string; for example, [href*="co.uk"] will select all elements with an href attribute matching .co.uk. http://www.example.co.uk?test=true would be a match, as would https://www.example.co.uk.

Pseudo-classes

To select an element when it is in a particular state, we have several pseudo-classes defined. The syntax of a pseudo-class is a colon, :, followed by a keyword.

There are a great number of pseudo-classes, but most developers' first experience of them is when styling links. A link has several states associated with it:

  • When an anchor element has an href attribute, it will have the :link pseudo-class applied to it.
  • When a user hovers over the link, the :hover pseudo-class is applied to it.
  • When the link has been visited, it has the :visited pseudo-class applied to it.
  • When the link is being clicked, it has the :active pseudo-class applied to it.

Here is an example of applying styling to the various pseudo-class states of an anchor element:

a:link, a:visited {
    color: deepskyblue;
    text-decoration: none;
}
a:hover, a:active {
    color: hotpink;
    text-decoration: dashed underline;
}

In the following figure, we can see the first link with the :link or :visited styles applied and the second link with the :hover or :active styles applied:

Figure 1.24: Link with and without the hover state

Figure 1.24: Link with and without the hover state

The cascade can cause some issues with styling links. The order in which you specify your CSS rules for each state of the link is important. If, for example, we applied the a:hover rule before the a:link rule in the previous example, we would not see the hover effect. A mnemonic exists for remembering the order: love-hate. The l is for :link, the v is for :visited, the h is for :hover, and the a is for :active.

Some other useful pseudo-classes for selecting elements in a particular interactive state include :checked, :disabled, and :focus.

There are several pseudo-classes that help us select a pattern of children nested under an element. These include :first-child, :last-child, :nth-child, :nth-last-child, :first-of-type, :last-of-type, :nth-of-type, and :nth-last-of-type.

For example, we can use :nth-child with an unordered list to give a different style to list items based on their position in the list:

<style>
  ul {
    font-family: Arial, Helvetica, sans-serif;
    margin: 0;
    padding: 0;
  }
  li {
    display: block;
    padding: 16px;
  }
  li:nth-child(3n-1) {
    background: skyblue;
    color: white;
    font-weight: bold;  
  }
  li:nth-child(3n) {
    background: deepskyblue;
    color: white;
    font-weight: bolder;
  }
</style>
<!-- unordered list in HTML document -->
<ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
    <li>Item 6</li>
    <li>Item 7</li>
</ul>

The following figure shows the result. The :nth-child pseudo-class gives you a lot of flexibility because you can use keywords such as odd and even or functional notation such as 3n - 1:

Figure 1.25: Using the :nth-child pseudo-class

Figure 1.25: Using the :nth-child pseudo-class

Pseudo-elements

Pseudo-element selectors are preceded by two colons (::) and they are used to select part of an element. The available pseudo-elements include ::after, ::before, ::first-letter, ::first-line, ::selection, and ::backdrop.

These pseudo-elements give us a handle we can use to add stylistic elements without adding to the HTML document. This can be a good thing if the pseudo-element has no semantic value and is purely presentational, but it should be used with care.

Combining Selectors

What makes CSS selectors particularly powerful is that we can combine them in several ways to refine our selections. For example, we can select a subset of li elements in an HTML document that also has a .primary class selector with li.primary.

We also have several options, sometimes called combinators, for making selections based on the relationships of elements:

  • To select all the li elements that are descendants of a ul element, we could use ul li.
  • To select all the li elements that are direct children of a ul element with the primary class, we might use ul.primary > li. This would select only the direct children of ul.primary and not any li elements that are nested.
  • To select an li element that is the next sibling of li elements with the selected class, we could use li.selected + li.
  • To select all of the li elements that are the next siblings of li elements with the selected class, we could use li.selected ~ li.

The following figure shows the difference between using li.selected + li and li.selected ~ li:

Figure 1.26: Selecting the next adjacent sibling compared to selecting all of the next siblings

Figure 1.26: Selecting the next adjacent sibling compared to selecting all of the next siblings

Let's try out some of the selectors we've learned about in an exercise.

Exercise 1.07: Selecting Elements

In this exercise, we will differentiate list items by styling the odd items. We will use a class selector to style a selected item and a next-siblings combinator to style the elements after the selected item.

The steps are as follows:

  1. Open the Chapter01 folder in VSCode (File > Open Folder…) and we will create a new plain text file by clicking File > New File. Then, save it in HTML format, by clicking File > Save As... and enter the File name: Exercise 1.07.html. Now, copy the following simple web page with a ul list element and nine list items:
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Selectors</title>
        </head>
        <body>
            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
                <li>Item 3</li>
                <li>Item 4</li>
                <li>Item 5</li>
                <li>Item 6</li>
                <li>Item 7</li>
                <li>Item 8</li>
                <li>Item 9</li>
           </ul>
        </body>
    </html>
  2. So that we can style a selected item differently, we will add a selected class to the fifth list item:
                <li class="selected">Item 5</li>
  3. Next, we will add a style element to the head element with the following CSS:
        <head>
            <meta charset="utf-8">
            <title>Selectors</title>
            <style>
              ul {
                  font-family: Arial, Helvetica, sans-serif;
                  margin: 0;
                  padding: 0;
               }
               li {
                   display: block;
                   padding: 16px;
                }
           </style>
           </head>

    This will remove some of the default styling of the unordered list in the browser. It will remove margins and padding on the list and set the font style to Arial (with Helvetica and sans-serif as a fallback).

  4. Next, we will style the odd list items with the :nth-child pseudo-class. We can use the odd keyword for this. With this style, any odd list item will have a blue background and white text:
    li:nth-child(odd) {
         background-color: deepskyblue;
         color: white;
         font-weight: bold;
    }

    This gives us the stripy effect that we can see in the following figure:

    Figure 1.27: Stripy list using :nth-child(odd)

    Figure 1.27: Stripy list using :nth-child(odd)

  5. We can style the selected class selector:
    li.selected {
         background-color: hotpink;
    }

    This overrides the striped effect for the selected item as seen in the following figure:

    Figure 1.28: Stripy list with a selected item

    Figure 1.28: Stripy list with a selected item

  6. Finally, we will style the odd list items after the selected item using the all-next-siblings combinator:
    li.selected ~ li:nth-child(odd) {
         background-color: orange;
    }

If you now right-click on the filename in VSCode on the left-hand side of the screen and select Open In Default Browser, you will see the following web page in your browser:

Figure 1.29: Combining selectors to style a list

Figure 1.29: Combining selectors to style a list

Style sheets can have a large number of style rules and combinations of selectors. It is good to understand why one rule takes precedence over another one. This is where CSS specificity comes in.

CSS Specificity

If we have two CSS declarations that have an effect on the same style property of an element, how do we know which of those declarations will take precedent?

There are several factors that decide the ranking of a CSS declaration and whether it is the style the browser will apply. The term for these factors is specificity.

A style attribute that adds inline styles to an element has the highest specificity value. An ID selector has a greater specificity value than a class selector and a class selector or attribute selector has a greater specificity value than an element type. We can calculate the specificity value by giving points to each of these specificity values.

The most common way of representing this is as a comma-separated list of integers, where the leftmost integer represents the highest specificity. In other words, the leftmost value is the inline style attribute; next is an ID selector; next is a class selector, pseudo-class, or attribute selector; and the rightmost value is an element.

An inline style would have the value 1, 0, 0, 0. An ID selector would have the value 0, 1, 0, 0. A class selector would have the value 0, 0, 1, 0, and an h1 element selector would have the value 0, 0, 0, 1.

Let's look at a few examples with more complex selectors:

  • li.selected a[href] has two element selectors (li and a), a class selector (.selected) and an attribute selector ([href]), so its specificity value would be 0, 0, 2, 2:
Figure 1.30: Calculating the specificity of li.selected a[href]

Figure 1.30: Calculating the specificity of li.selected a[href]

  • #newItem #mainHeading span.smallPrint has two ID selectors, a class selector (.smallPrint), and a span element, so its specificity value would be 0, 2, 1, 1:
Figure 1.31: Calculating the specificity of #newItem #mainHeading span.smallPrint

Figure 1.31: Calculating the specificity of #newItem #mainHeading span.smallPrint

Comparing the two selectors, we can see that the selector in the second example is more specific than the selector in the first example.

The Special Case of !important

The !important value can be appended to the value of any CSS declaration. It is a special keyword that can be applied to selectors to override the specificity value. It trumps any other specificity value. In terms of specificity value, it would add another column to become the value 1, 0, 0, 0, 0. It would even take precedence over an inline style.

For example, we might want to create a style rule that is reusable and lets us hide content on a web page. Something like this:

.hide {
  display: none;
}

If we apply this class to an element, we want that element to be hidden and to not be rendered on the web page. We might use this to later reveal the element using JavaScript. However, consider the following example:

<style>
 div.media {
  display: block;
  width: 100%;
  float: left;
 }
 .hide {
  display: none;
 }
</style>
<div class="media hide">
 ...Some content
</div>

We might expect our div element to be hidden because the .hide class appears second in the style sheet. However, if we apply the specificity calculations we've learned about, we can see that div.media scores 0, 0, 1, 1 and .hide only scores 0, 0, 1, 0. The div.media rule for the display property with block value will override the none value of the .hide class. We can't really use this instance of the .hide class as we don't know whether it will have any effect.

Now consider the same .hide class but using the !important keyword:

.hide {
  display: none !important;
}

Adding the !important keyword will make this .hide class much more reusable and useful as we can pretty much guarantee that it will hide content as we desire.

We've learned a lot about CSS in this part of the chapter. Let's apply some of this knowledge to an activity.

Activity 1.02: Styling the Video Store Template Page

In the previous activity, we were tasked with creating boilerplate HTML for a web page for the Films On Demand website. In this activity, we are going to add some style to that template page.

The following figure shows the expected output for this activity:

Figure 1.32: Expected output for styling the video store template page

Figure 1.32: Expected output for styling the video store template page

The steps are as follows:

  1. We will start with the template from Activity 1.01, Video Store Page Template, which we will save as Activity 1.02.html:
    <!DOCTYPE html>
    <html lang="en">
        <head>
           <meta charset="utf-8">
           <title>Films on Demand - <!-- Title for page goes here --        ></title>
           <meta name="description" content="Buy films from our great          selection. Watch movies on demand.">
           <meta name="viewport" content="width=device-width,          initial-scale=1">
        </head>
        <body>
              <h1>Lorem ipsum</h1>
              <p>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.           Nullam quis scelerisque mauris. Curabitur aliquam ligula           in erat placerat finibus. Mauris leo neque, malesuada et           augue at, consectetur rhoncus libero. Suspendisse vitae           dictum dolor. Vestibulum hendrerit iaculis ipsum, ac           ornare ligula. Vestibulum efficitur mattis urna vitae           ultrices. Nunc condimentum blandit tellus ut mattis.          Morbi eget gravida leo. Mauris ornare lorem a mattis           ultricies. Nullam convallis tincidunt nunc, eget           rhoncus nulla tincidunt sed. Nulla consequat tellus           lectus, in porta nulla facilisis eu. Donec bibendum           nisi felis, sit amet cursus nisl suscipit ut.           Pellentesque bibendum id libero at cursus. Donec ac           viverra tellus. Proin sed dolor quis justo convallis           auctor sit amet nec orci. Orci varius natoque           penatibus et magnis dis parturient montes, nascetur           ridiculus mus.
              </p>
        </body>
    </html>
  2. We are going to link to an external CSS file. One of the difficulties with styling web pages is handling differences between browsers. We are going to do this by adding a file to normalize our default styles. We will use the open source normalize.css for this. Download the file from https://packt.live/3fijzzn. Add the file to a styles folder and link to it from the Activity 1.02.html web page.
  3. We are going to add a style element to the head element of Activity 1.02.html. In the style element, we want to set some styles used across all pages. We want to do the following:

    Set box-sizing to border-box for all elements using the universal selector (*).

    Add a font family with the Arial, Helvetica, sans-serif values and a font size of 16px to the whole page.

    Add the background color #eeeae4 for the whole page. To do this, we will add a div element wrapper with the pageWrapper ID, where we will set the background color and padding of 16px, and a full-page class, where we will set the minimum height to 100vh (100% of the viewport height).

    Add an h1 element selector that sets the margin to 0 and adds padding of 16px to the bottom of the h1 element.

    Note

    The solution for this activity can be found via this link.

We've learned a lot about HTML and CSS in this chapter. In the next section, we will learn a little bit about the Chrome developer tools and how we can use them to better understand our web page.

Dev Tools

Most browsers come with some tools to help web developers create and change web pages. One of the most useful of these tools is the built-in developer tools that come with the Chrome browser.

You can access the developer tools on any web page with the Command + Option + I keyboard shortcut (on Mac) and F12 or Control + Shift + I (on Linux and Windows).

On opening the developer tools, you should see something similar to the following figure:

Figure 1.33: Chrome developer tools (Elements tab)

Figure 1.33: Chrome developer tools (Elements tab)

There are a lot of options available in the developer tools. We will not cover all of them here but will focus on the top bar and the Elements tab in this chapter.

The Top Bar

The top bar gives you access to several options and tools, including access to all the other sections of the developer tools via the tabs:

Figure 1.34: Chrome DevTools top bar

Figure 1.34: Chrome DevTools top bar

The top bar has the following tools and options:

  • Select tool – You can use this tool to select an element from within the web page.
  • Devices Devices toolbar – Changes the view so you can select the view size of various devices.
  • Tabs – We can access various tools from the top bar menu such as Console, Elements, Sources, Network, and Performance. We will focus on the Elements tab.
  • Configuration Configuration – Gives you access to various settings for the developer tools.
  • Close Close – Closes the developer tools.

While developing the HTML and CSS for a web page, one of the tabs we use the most is the Elements tab.

The Elements Tab

The Elements tab has two areas – the left-hand panel shows the current HTML DOM and the right-hand panel shows details about the selected element.

You can use the left-hand panel to select an element from the HTML DOM and you can also edit an element to change its attributes:

Figure 1.35: Selectable HTML DOM in the left-hand panel of the Elements tab

Figure 1.35: Selectable HTML DOM in the left-hand panel of the Elements tab

Once you have an element selected, you can see a lot of information about the element in the right-hand panel. This information is divided into tabs and the first tab shows the styles:

Figure 1.36: The Styles tab of the right-hand panel of the Elements tab

Figure 1.36: The Styles tab of the right-hand panel of the Elements tab

Essentially, the Styles tab shows a representation of the CSSOM. You can look at the styles associated with the element, including the cascade of styles, showing you where a style is inherited from and where it has been set but overridden. The topmost element is the most specific. You can also use this tab to edit the styles of an element and to check different states, such as the hover state.

The Computed tab shows styles as they have been computed for the element.

There are also tabs to show you the event listeners and properties associated with an element.

Having had a glimpse at the power of Chrome's developer tools, let's finally consider how the browser works with HTML and CSS technologies to render a web page.

How a Web Page Renders

How does a web page render in the browser? We've learned a lot about HTML and CSS in this chapter, but let's see how these technologies are put together by the browser to render our web page.

The following figure shows a flowchart of the process, which is further explained below:

Figure 1.37: Flow chart of the web page render process

Figure 1.37: Flow chart of the web page render process

To summarize the process:

  1. The user starts by navigating to a URL, possibly via a hyperlink or by typing the URL into the address bar of their browser.
  2. The browser will make a GET request to the disk or a network. It will read the raw bytes from that location and convert them to characters (based on character encoding such as UTF-8).
  3. The browser then parses these characters according to the HTML standard to find the tokens that are familiar as HTML elements, such as <html> and <body>.
  4. Another parse is then made to take these tokens and construct objects with their properties and based on the rules appropriate to that token. At this point, the objects are defined.
  5. Finally, the browser can define the relationships between these objects and construct the HTML DOM for the web page.
  6. At this point, we have a DOM but not a rendered web page. The next task is to construct the CSSOM. Again, the browser will load any style sheet resources it needs to, which were found while parsing the document. It will then construct the styles associated with nodes in the tree structure, which gives us the CSSOM.
  7. With the information gathered in the DOM and the CSSOM, the browser can create a render tree. The render tree is constructed by combining information from the CSSOM and the HTML DOM. Nodes in the HTML DOM that will not be rendered (for instance, those with the display: none; style) are excluded from the render tree. Those that are rendered are enriched with their computed style rules.
  8. Now the browser has all the information it needs, it can begin to calculate the positions of elements in the rendered viewport. This is called the layout stage. The browser lays elements out based on their size and position within the browser viewport. This stage is often also called reflow. It means the browser must recalculate the positions of elements in the viewport when elements are added to or removed from the page or when the viewport size is changed.
  9. Finally, the browser will rasterize or paint each element on the page, depending on their styles, shadows, and filters to render the page the user will see.

That is a brief and simplified summary of the rendering of a web page. Think about how many resources might be loaded on a relatively complicated website and with JavaScript running events and we can see that much of this process happens frequently and not in such a linear manner. We can start to see the complexities of what a browser is doing when it renders your web page.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime