Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"}
])
Upon completing this lesson, a student should be able to answer the following questions.
- What are the parts of an HTML element?
- What are the parts of a CSS rule?
- How do we select elements to apply a CSS rule to?
Hyper Text Markup Language (HTML) is used to structure a web page and its content.
HTML defines many HTML elements. For example, the following is an HTML paragraph element.
<p>hello world</p>
An HTML element generally includes an opening tag, content, and closing tag.
Here is a brief overview of HTML by Fireship.
YouTube.new("https://www.youtube.com/watch?v=ok-plXXHlWw")
Cascading Style Sheets (CSS) is the language used to style HTML web pages.
CSS rules apply in the order they are defined (hence, cascading). Each CSS rule has a selector to target HTML elements and semi-colon separated declarations of styles to apply.
For example, the following is a CSS rule that would apply to all paragraph tags to make them green and bold.
p {
color: green;
font-weight: bold;
}
The CSS above would style the paragraph tag like so.
Hello, world!
Here's a breakdown of our CSS rule.
Here's another great overview video by Fireship.
YouTube.new("https://www.youtube.com/watch?v=OEV8gMkCHXQ")
We can create .html
files and open them in the browser. For example, create a file hello.html
with the following content.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
Open this file in the browser and see the following web page.
HTML documents are a nested series of HTML elements. See the Anatomy of an HTML document for a complete breakdown.
The <head>
element contains metadata about the document, such as the CSS styles. We can add a <style>
element inside of the <head>
element to write our CSS for the document. The <body>
element contains the web page's content.
Replace the hello.html
file with the following content.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
<style>
p {
color: green;
font-weight: bold;
}
</style>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
Now when we reload the browser, we should see the same web page but with bold green text.
Rather than defining our styles in a <style>
tag, we can use external .css
stylesheet files using the <link>
tag.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<p>Hello World!</p>
</body>
</html>
A styles.css
file in the same folder as hello.html
contains the CSS.
p {
color: green;
font-weight: bold;
}
A .css
file can include another .css
file using @import
. Importing files helps organize CSS files on larger projects.
/* in styles.css */
@import 'otherstyles.css';
otherstyles.css
would be another stylesheet in the same folder as styles.css
.
CSS selectors describe which HTML elements to apply the CSS rule to.
We've already seen we can select all matching elements using the element tag name.
p {
color: green;
}
The type selector applies styles to all elements with a matching node name, so p
matches all <p>
tags.
<p>all paragraph tags will be green</p>
By far, the most commonly used selector is a class. We define a CSS class selecting using a .
followed by the class name.
.green-text {
color: green;
}
The .green-text
class will apply to all elements with the green-text
class attribute. Attributes are key-value pairs that contain additional information about the element.
<p class="green-text">This text will be green.</p>
<p class="green-text">This text will also be green.</p>
IDs work similarly to class, however, the id
attribute should be unique for each element.
We define a CSS id using a #
followed by the id name.
#first-paragraph {
color: green
}
The #first-paragraph
id will then apply to the element with the first-paragraph
id attribute.
<p id="first-paragraph">This text will be green and bold.</p>
Keep in mind that browsers do not enforce unique IDs. However, it is conventional and strongly encouraged.
We select all direct children of an element using a >
symbol between selectors.
.parent > .child {
color: green;
}
The >
selects all elements with the .child
class that are direct children of the .parent
class.
<div class="parent">
<p class="child">This text will be green.</p>
<p>This text will NOT be green.</p>
</div>
We select can all descendants of an element using a space between selectors.
.parent .descendant {
color: green;
}
The space selects all elements with the .child
class inside the.parent
class element.
<div class="parent">
<section>
<p class="descendant"> This text will be green. </p>
<section>
</div>
The *
symbol allows us to select all elements.
* {
color: green
}
All elements, regardless of type, will be selected.
<p>This text will be green.</p>
<h1>This text will also be green.</h1>
See the MDN CSS Selectors documentation for a complete guide on CSS selectors.
There is a fun website CSS Diner where you can practice using CSS selectors.
Play the CSS Diner game to familiarize yourself with selectors until you feel satisfied with your ability. We recommend you play up to the first eleven levels.
There are a massive number of HTML elements. We recommend the MDN HTML Element reference for a complete list.
HTML and CSS are deep topics, and as an Elixir-focused course, we aim to cover the most commonly used HTML elements and CSS rules.
Heading elements represent six levels of section headings. Often, you will use headings in descending order to create headings and subheadings.
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
We've already seen the <p>
tag for paragraph content. Each paragraph tag is automatically on a new line.
<p>Paragraph</p>
We can also use the <span>
tag to group inner text content (perhaps for styling) without creating a new line of text.
<p>Outer content. <span>Inner content</span></p>
The ordered list <ol>
and list item <li>
tags create numbered lists.
<ol>
<li>a</li>
<li>b</li>
<li>c</li>
</ol>
The above HTML displays the following.
- a
- b
- c
If we want to use non-numbered lists with dashes, we can use the unordered list <ul>
tag instead.
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
The above HTML displays the following.
- a
- b
- c
To create nested lists, we can nest ordered and unordered lists inside one another.
<ul>
<li>a</li>
<ol>
<li>b</li>
<ul>
<li>c</li>
</ul>
</ol>
</ul>
The above HTML displays the following.
- 1
- 1.1
- 1.1.1
The <img>
tag embeds image content into a web page.
Images must include a src
attribute for the local file or URL of the image to embed.
Images may include an alt
attribute. The alt
attribute is a text description of the image used as a fallback if the image does not load and for screen readers.
Here are two <img>
tag examples.
<img src="https://picsum.photos/200" alt="a random lorem ipsum image"></img>
<img src="broken url" alt="image purposefully not loaded"></img>
The first <img>
tag above loads an image from https://picsum.photos/200.
The second displays the alt
text when it fails to load.
Images can use a self-closing tag <img/>
, so they do not require an opening and closing tag. <img></img>
.
<img src="https://picsum.photos/200" alt="a random lorem ipsum image" />
<img src="broken url" alt="image purposefully not loaded" />
The <a>
anchor tag creates a link to another resource using the href
attribute as the URL for the resource.
<a href="https://www.google.com/search?q=cat+pictures">Cat Pictures Link</a>
The anchor tag above displays the following.
Cat Pictures LinkWe can organize information into rows and columns using tables. Each table starts with a table tag <table>
. The table row <tr>
and table data <td>
tags can then create each row of data in the table.
<table>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
</table>
We can use the table head <thead>
, table body <tbody>
, and table footer <tfooter>
components to define the header, body, and footer sections of the table. The table header <th>
element defines a styled header cell rather than the default table data <td>
cell.
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
</tbody>
<tfooter>
<tr>
<td>Footer 1</td>
<td>Footer 2</td>
<td>Footer 3</td>
</tr>
</tfooter>
</table>
The colspan
attribute allows each cell take up a specified number of columns.
<table>
<thead>
<tr>
<th colspan="3">Full Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
</tbody>
</table>
For a full guide to HTML tables, see the MDN Table documentation.
We can use the <div>
tag when we need to group content.
<div>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
The division tag is very generic and minimal. It does not convey any meaning about the content and is typically used to group content together for styling.
It's a common issue to overused div tags. Instead, ideally, we should use semantic tags instead of divs where possible.
HTML includes several semantic tags that group content and describe their meaning.
We recommend this tutorial by The Net Ninja for an overview of semantic tags.
YouTube.new("https://www.youtube.com/watch?v=kGW8Al_cga4")
Cascading Style Sheets apply rules in the order they are defined. Therefore, multiple CSS rules can apply to the same element, and declarations in one rule can override another.
In the example below, the second rule overrides the first.
p {
color: red;
}
p {
color: blue;
}
So all paragraph tags will be blue, not red.
<p>This text will be blue, not red.</p>
Multiple non-conflicting rules can still apply to the same element. In the example below, the paragraph tag would be bold and green.
p {
color: green;
}
p {
font-weight: bold;
}
CSS prioritizes different selectors over one another. We refer to this prioritization as specificity. The greater the specificity, the higher the priority of the rule.
For example, a class selector will always override a type selector and ignore cascading order.
.my-class {
color: blue
}
<!-- this rule will not apply -->
p {
color: red;
}
So the following paragraph tag would be blue, not red.
<p class="my-class">This text will be blue.</p>
See the Specificity documentation for more on how to determine specificity.
For a more hands-on guide, we recommend this video by whatsdev.
YouTube.new("https://www.youtube.com/watch?v=ndM8b-hnSwM")
We can also use the !important
flag to prioritize a CSS declaration. We should be careful when using this flag, as it can make our CSS difficult to reason about.
.my-class {
color: red
}
p {
color: blue !important;
}
Many browsers allow you to inspect the HTML and CSS in a web page. The inspector is incredibly useful for understanding how projects work under the hood.
We will use Google Chrome for our examples, but similar functionality is available in Firefox and other browsers.
Consider downloading Google Chrome to follow along with inspector examples.
We can open the inspector by right-clicking on any element in a web page and selecting Inspect. We can view the Elements that make up the web page and the Styles for those elements.
Replace hello.html
with following content.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
<style>
p {
color: green;
font-weight: bold;
}
</style>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
Open hello.html
in your browser, right-click and select inspect on the paragraph tag.
The Elements tab contains the HTML of the web page. Click the arrow to expand the <body>
tag if it is not already open.
Select the paragraph tag and view the Styles tab. From here, you can see the styles applied to the element.
The CSS box model is a box that wraps every HTML Element which we use for positioning and layout.
Every HTML Element has content containing text or child elements, internal padding, a border, and external margin.
flowchart
subgraph Margin
subgraph Border
subgraph Padding
Content
end
end
end
We generally use px
(pixels) or percent %
for CSS measurements. For a full list of CSS units see the MDN CSS Values and Units documentation.
We can set the size of the padding and margin properties. A single unit sets the top, right, bottom, and left margin values.
p {
padding: 10px;
margin: 10px;
}
Alternatively, we can add up to four units in the order of top, right, bottom, and left.
p {
/*top right bottom left*/
padding: 10px 20px 30px 40px;
}
Missing units will mirror the opposite value. Below, the top and bottom padding are 10px
, and the right and left padding are 5px
.
p {
padding: 10px 5px;
}
We can also individually set the top, right, bottom, and left margin or padding.
p {
padding-top: 10px;
padding-right: 20px;
padding-bottom: 30px;
padding-left: 40px;
margin-top: 10px;
margin-right: 20px;
margin-bottom: 30px;
margin-left: 40px;
}
A border has border-width
, border-color
, and border-style
values.
p {
border-style: solid;
border-width: 5px;
border-color: black;
}
Or we can use the border
property to set all three at once.
p {
border: 5px solid black;
}
See the MDN Border documentation for further customization.
We can set the content height
and width
properties.
p {
height: 100px;
width: 100px;
}
The total height and width of an element will be an addition of the margin, padding, border, and content. For example, the following class would be 140px
in height and width because (10 * 2) + (10 * 2) + 100 = 140
.
.class {
height: 100px;
width: 100px;
padding: 10px;
border: 10px solid black;
}
Alternatively, we can set the box-sizing
property to border-box
to include the border and padding in the element's total height and width. The content height and width are then automatically computed.
Now the element's total height and width, including padding and border, will be 100px
.
.class {
box-sizing: border-box;
height: 100px;
width: 100px;
padding: 10px;
border: 10px solid black;
}
Replace hello.html
with the following content.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
<style>
.box-model-example {
width: 100px;
height: 100px;
padding: 10px;
margin: 10px;
border: solid black 10px;
}
</style>
</head>
<body>
<p class="box-model-example">Content</p>
</body>
</html>
We can view the box model of any HTML elements using the inspector. For example, inspect the <p>
and go to the Computed section to see the computed box model.
Hover your cursor over the <p>
tag in the Elements section to see the box model highlighted on the page.
You can also hover your cursor over the box model in the Computed section to highlight the content, padding, border, and margin individually.
Notice that while we set the margin to be 10px
on all sides, the horizontal margin takes up the entire page. That's because, by default, the <div>
element is a block element, which we will cover in the next section.
The display property determines how to display elements on the page. Elements have different default display properties.
For example, <div>
is a block element. Block elements start on a new line and take up the whole width of the line.
Alternatively,<span>
is an inline element. Inline elements exist on the same line as the previous element.
Inline elements ignore height and width values. Instead of inline, we can use inline-block values to display an element on the same line, but apply width and height values.
Generally, you can accomplish the most common CSS behaviors with block, inline, and inline-block elements. However, there is a massive list of alternative display properties. See the MDN Display documentation for a full list of display values.
Alter the .box-model-example
class to use an inline div element instead of a block div element.
The ...
represents the rest of the CSS styles in .box-model-example
.
.box-model-example {
display: inline;
...
}
Use the inspector to view the computed box model. Notice the height and width do not apply to inline elements.
Alter the display property again to use the inline-block value.
.box-model-example {
display: inline-block;
...
}
Use the inspector to view the computed box model. Notice the margin no longer takes up the entire line width.
The position property defines how an element positions itself on the page.
By default, HTML elements have a static position property where they flow normally on the page.
p {
position: static;
}
There are other useful positioning properties such as relative, absolute, fixed and sticky. We recommend the MDN Position documentation for a full guide.
We also recommend this video by Web Dev Simplified.
YouTube.new("https://www.youtube.com/watch?v=jx5jmI0UlXU")
CSS provides many tools for the layout of elements.
We can use margin: auto;
to center a block element horizontally inside its container. The element must have a smaller width than its parent container as this automatically adds left and right margin based on the remaining space in the parent container.
.center {
margin: auto;
width: 100px;
}
We can use position: absolute;
to right align or left align an element to its parent container.
.right {
position: absolute;
right: 0;
}
.left {
position: absolute;
left: 0;
}
We can left, right, and center align text using the text-align
property.
.right {
text-align: right;
}
.center {
text-align: center;
}
.left {
text-align: left;
}
Certain CSS declarations accept a color name as a value. For example, we've used to color
property to set the color of some text content.
p {
color: red;
}
We're also able to set the background color of an element.
p {
background-color: red;
}
For a full list of valid color names, see the MDN Color Keywords documentation.
We can also use the RGB (red, green, blue), RGBA (red, green, blue, alpha), HEX (hexadecimal value), or HSL (hue, light, saturation) representations for colors.
Here's the color yellow in a variety of formats.
<!-- color keyword -->
p {
color: yellow;
}
<!-- RGB -->
p {
color: rgb(255, 255, 0);
}
<!-- RGBA -->
p {
color: rgba(255, 255, 0, 1);
}
<!-- HEX code -->
p {
color: #FFFF00;
}
<!-- HSL -->
p {
color: hsl(60, 100%, 50%);
}
We recommend using a browser extension that finds the color code for a color on a web page, such as Color Zilla.
It's also handy to use a color selector such as the Chrome Color Selector for picking colors and getting their code representation.
We've already used the font-weight
property, which can set the font-weight using a number or named weight.
/* Keyword values */
font-weight: normal;
font-weight: bold;
/* Keyword values relative to the parent */
font-weight: lighter;
font-weight: bolder;
/* Numeric keyword values */
font-weight: 100;
font-weight: 200;
font-weight: 300;
font-weight: 400;// normal
font-weight: 500;
font-weight: 600;
font-weight: 700;// bold
font-weight: 800;
font-weight: 900;
/* https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#syntax */
We can also set the font-size
. We can set the font size using px
. However, pixels are a static value, which can cause issues depending on the screen size.
p {
font-size: 20px;
}
Instead, we recommend using a relative unit such as em
. 1em
is equal to the current font size. The default font size on browsers is 16px
, and users can change their font size if desired.
p {
font-size: 1.875em;
}
h1 {
font-size: 3em;
}
We can change the font family of an element.
There are many generic font families such as serif
, sans-serif
, monospace
, and cursive
.
p {
font-family: serif
}
We can also use any fonts installed on the user's computer. If the font doesn't exist, it will use any comma-separated fallback fonts.
p {
font-family: Verdana, Arial, sans-serif;
}
Some fonts, such as Arial and Verdana, are web-safe because most users should have them installed. However, we often want to use custom fonts.
We can install custom fonts using Google Fonts or other similar services.
For example, we could use the League Gothic font from Google Fonts. Google Fonts contains the <link>
tag instructions for installing the font in an HTML document.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello!</title>
<!-- The following installs the league gothic font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=League+Gothic&display=swap" rel="stylesheet">
<style>
p {
font-family: 'League Gothic', sans-serif;
}
</style>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
Install and use a custom font from Google Fonts in your hello.html
file. You may choose any freely available font you wish.
Flex and Grid are two very powerful ways to create responsive layouts with CSS. As we are focused on Elixir development they are beyond the scope of this course. However, they will be very important if you want to create layouts that work on multiple device sizes.
To learn more about Flexbox, we recommend you start with these two quick primers by Fireship.
YouTube.new("https://www.youtube.com/watch?v=K74l26pE4YA&ab_channel=Fireship")
YouTube.new("https://www.youtube.com/watch?v=uuOXPWCh-6o&ab_channel=Fireship")
Armed with the fundamentals of HTML and CSS, we're ready to build functional and great-looking websites. However, HTML and CSS are both massive topics, and there is still much more to learn.
Consider the following resources as you continue your HTML and CSS learning journey.
For experimenting with HTML and CSS, we recommend sites such as CodePen that make it easy to prototype HTML and CSS designs rapidly.
DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.
Run git status
to ensure there are no undesirable changes.
Then run the following in your command line from the curriculum
folder to commit your progress.
$ git add .
$ git commit -m "finish HTML & CSS reading"
$ git push
We're proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.
We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.