Getting started
CSS is a domain-specific, declarative programming language. Domain-specific means that it is a specialized language that solves a specific problem. It is a declarative language because it tells the browser what to do, rather than how to do it.
Syntax
Each CSS style is called a rule, and each rule uses the following format:
selector {
property: property-value;
}
The property: property-value;
is called a declaration, and the declarations with the curly braces are called a ruleset. You can omit the semicolon (;
) from the last declaration in the ruleset. Invalid declarations are ignored.
Adding CSS to HTML
You can add CSS to a file with the following methods:
- Inline
- Add the CSS to the HTML tag.
- Embed
- Add the CSS to the page within the
<style>
tag, which is nested in the<head>
tag. - External
- Link a stylesheet to the HTML with the
<link>
tag.
In nearly all cases, you add CSS to a project with an external stylesheet.
External CSS
External CSS groups styles together in an external .css
stylesheet. Link the stylesheet in the <head>
tag of the website. Name the stylesheet styles.css
:
<head>
<link rel="stylesheet" href="styles.css">
</head>
The <link>
element uses the following attributes:
rel
: Describes the relationship between the HTML document and what you are linking to it.href
: Stands for hypertext reference and indicates where to find the document that we want to include.
Devtools
For each element, devtools lists styles by specificity. Styles at the top override those below them, and they are crossed out. The ruleset location in the stylesheet is to the right of the style.
Cascading stylesheets
There are 3 differnt stylesheets that cascade—allow stylesheets to overwrite or inherit from one another—when we apply styles to HTML:
- User-agent stylesheet: Stylesheet internal to your web browser (i.e. Google Chrome). These include:
- blue, underlined links
- discs for lis
- margins
- font size
- Author stylesheet: Stylesheet developed and applied by a developer to HTML with a link tag.
- User stylesheet: Custom user-provided stylesheets, which are usually created and applied to overcome accessibility issues.
The following list describes the order that styles cascade, in order of precedence:
- User stylesheet with
!important
declaration. - Author stylesheet with
!important
declaration. - User stylesheet.
- Author stylesheet.
- User agent stylesheet.
Cascade determines how rule conflicts are resolved. When there is a conflict, the cascade uses the following hierarchy to resolve it:
- Stylesheet origin: Where the stylesheet comes from
- Inline styles: Whether the style is applied to an HTML element directly.
- Layer (New): Which layer is the style defined in? Uses the last layer.
- Selector specificity: Which selector has highest specificity.
- Scope proximity (New): Use declaration with innermost scope.
- Source order: Declaration that comes latest in source order.
CSS reset
When you start a project, you want to make sure that you have a consistent baseline across browsers—you do not want user agent stylesheets to impact your CSS.
To create this baseline, you apply a CSS reset that undoes the browser’s default styles. To apply a CSS reset, you can create a reset.css
stylesheet to add to the project, and link it before your author stylesheet to ensure it is applied before your custom styles:
<head>
<link rel="stylesheet" href="reset.css">
<link rel="stylesheet" href="styles.css">
</head>
In production, you want to add CSS resets with one of the following methods:
- Copy the reset styles to the beginning of your stylesheet.
- Use a reset CDN. After the user loads your page (or another page that uses the same CDN) once, they will cache the styles.
Specificity
When multiple styles are applied to one element, the browser must determine which style to apply. When a declaration “wins” the cascade, it is called the cascaded value.
- If a selector has more IDs, it wins
- If 1 is a tie, the selector with the most classes wins
- If 2 is a tie, the selector with the most tag names wins
Pseudo-class selectors and attribute selectors have the same specificity as a class selector:
/* pseudo-class */
link:hover {...}
/* attribute */
[type=input] {...}
Universal selector and combinators do not impact specificity scores.
Specficity notation
Use the following format to indicate specificity:
/* ID, class, tags */
/* 0, 1, 3 */
body header.page-header h1 {...}
Reducing specificity
You can use the :where()
pseudo-class to reduce specificity (it has 0 specificity). :where(.nav)
is equivalent to .nav
, but has a specificity of 0.
Special values
These values manipulate the cascade and allow you to undo styles that you set elsewhere in the stylesheet. This is helpful for something like flexbox, whose properties have multiple keyword values, and remembering the original values is difficult:
inherit
: Causes the element to inherit the value from its parent. When you want to use inheritance when a cascading value is preventing it. This is helpful when you need to control a value in one place. For example, the background color is controlled only in the parent element.initial
: Resets to the default value for the property (not the element) when there are applied styles that you want to undo. This overrides all styles from both author and user-agent stylesheets. For example, you can setbackground-color
toinitial
instead oftransparent
, bc that is its default value. Other common uses:border: initial;
(default isnone
)width: initial;
(default isauto
)
unset
: When applied to an inherited property, it sets the value toinherit
, when applied to non-inherited property, it sets it toinitial
. This overrides all styles from both author and user-agent stylesheets.revert
: Overrides your author-styles but preserves the user-agent styles.
Common rules
- Don’t use IDs in selectors
- Don’t use
!important
Inherited styles
CSS applies the following general rules to determine inherited styles:
- Theme-related styles, such as color and font size, are generally inherited
- Layout considerations are generally not inherited.
Anything defined in a rule overrides an inherited value.
If there is no cascaded value for an element, it might inherit a value. A common inherited value is applying font-family
to the body
element so you do not have to apply it to each element in the body
. Here is a non-comprehensive list:
- color
- font
- font-family
- font-size
- font-weight
- font-variant
- font-style
- line-height
- letter-spacing
- text-align
- text-indent
- text-transform
- white-space
- word-spacing.
- list-style
- list-style-type
- list-style-position
- list-style-image
Specificity values
When browsers evaluate competing styles, they assign the following values and apply the style with the highest score:
- 100: ID selectors (
#id-name
) - 10: Class selectors (
.class-name
), attribute selectors ([type="submit"]
), and psuedo-classes (::
) - 1: Type selectors (
button
) - 0: Universal selector (
*
)
CSS selectors
Type
Targets the HTML element by name.
h1
, p
, li
Class
Targets the HTML element by associated class
attributes:
// index.html
<h1 class="class1 class2 class3">Heading</h1>
// stylesheet
.class1 {...}
ID
Unique attribute that is generally used for Javascript. Each ID is unique to the web page.
// index.html
<div id="id-name"></div>
// stylesheet
#id-name {...}
You should avoid applying styles with an ID attribute.
Combinators
Combinators combine multiple selectors, which allows more complex CSS without overusing class or ID names. You apply styles using relationships between elements.
Descendant (space)
Targets all HTML elements within a parent. The target descendant element does not have to be an immediate child:
<parent> <descendant> { <declaration> }
article p { font-size: 2rem; }
Child (>
)
Targets the immediate child elements of a particular selector:
<ul class="list"> // parent
<li></li> // child
<ul> // grandchild
<li></li> // great-grandchild
<li></li>
<li></li>
</ul>
<li></li> // child
<li></li>
</ul>
To apply styles, use the >
operator to select the child elements. Note that color is an inherited property, so you have to use the descendant selector to revert the styles on the grandchild
elements:
.list > li { color: red }
.list > li ul { color: initial }
Adjacent (+
)
Style sibling elements at the same level, directly after another:
header + p { font-size: 2rem }
The adjacent combinator is useful when displaying errors in HTML forms.
General sibling (~
)
Targets all elements that are siblings after the element targeted by the selector. The second element does not need to immediately follow the first, like the adjacent sibling combinator.
The following example targets all sibling <img>
tags that is preceded by a <header>
element. In other words, the browser locates the <header>
element, then applies the styles to all <img>
elements after that element:
header ~ img { ... }
Pseudo elements
These selectors target a state or parts of an element that might not exist yet.
Pseudo-class
A pseudo-class is added to a selector to target a specific state of the element. This is common for elements that the user interacts with, such as links, buttons, and forms.
To define styles for a pseudo-class, use a colon (:
). The following example styles link elements according to state:
/* href is not in browser history */
a:link {
color: #000
}
/* href is in browser histor */
a:visited {
color: #111
}
/* cusor is over element */
a:hover {
color: #222
}
/* element that receives keyboard events by default */
a:focus {
color: #333
}
Pseudo-elements
Allow you to style a specific part of an element. To define styles for a pseudo-element, use a double-colon (::
). You can use a single colon, but that is for backward compatibility only.
For example, the following rule styles only the first letter of a paragraph that is adjacent to the header element:
header + p::first-letter {
color: red;
}
Attribute selectors
This selector targets HTML elements that have a specific attribute with the same value. This is commonly used to style links and forms.
The following example places the word “pre” before the tag in square braces:
[lang="en"]::before {
content: "pre"
}
Universal selector
The universal selector (*
) applies to all HTML elements. It has a specificity of 0, so you can override it easily.
For example, the following rule changes the font-family to sans-serif for all h1
child elements:
h1 > * {
font-family: sans-serif;
}
Shorthand
Shorthand lets you replace multiple CSS properties with one property. A common example is padding
, which merges the following into a single property:
padding-top
padding-right
padding-bottom
padding-left
You can combine all of the above properties with the padding
property, listing the values clockwise from the top or combining top and bottom:
h1 {
padding: top right bottom left
}
h1 {
padding: top-bottom left-right
}
Some common examples:
/* try not to use font shorthand bc it is easy to omit values and use initial values */
font: font-style font-weight font-size line-height font-family;
background: background-color background-image background-size background-repeat background-position background-origin background-chip background-attachment;
border: border-width border-style border-color;
border-width: top right bottom left;
Be aware of shorthands that silently override other styles. When you omit values for shorthand values, it sets the omitted values to their
initial
value.
When you add only 3 values, it applies to the top, right, then bottom, and the left value takes.
Generally better to have more padding on sides of buttons, less on top.
The following properties specify horizontal left/right values, then top/bottom. This is because they represent a Cartesian grid, which uses x, y ordering:
- background-position
- box-shadow
- text-shadow
Tip: Property that specifies two measurements from a corner, think “Cartesian grid.” Property that specifies measurements for each side all the way around an element, think “clock.”
Progressive enhancement
This means that your stylesheet can apply styles that are not supported by some browsers. As user browsers upgrade, the features become available (future-compatible).
Use a new feature with the @supports
feature query. This allows you to use a feature that is possibly not supported, but you must provide a supported fallback style, too.
.coffees {
margin: 20px 0;
}
/* fallback styles */
.coffees > a {
display: inline-block;
min-width: 300px;
padding: 10px 15px;
margin-right: 10px;
margin-bottom: 10px;
color: black;
background-color: transparent;
border: 1px solid gray;
border-radius: 5px;
}
/* feature query */
@supports (display: grid) {
.coffees {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
.coffees > a {
margin: unset;
min-width: unset;
}
}
Example usage:
/* Only apply rules in the feature query block if the queried declaration isn’t supported */
@supports not(<declaration>)
/* Apply rules if either queried declaration is supported */
@supports (<declaration>) or (<declaration>)
/* Apply rules only if both queried declarations are supported */
@supports (<declaration>) and (<declaration>)
/* Apply rules only if the given selector is understood by the browser (for example, @supports selector(:user-invalid)) */
@supports selector(<selector>)