CSS Overview
Selectors, Integration, Inheritance, Cascading
R. Scott Granneman r Jans Carton
© 2009 R. Scott Granneman
Last updated 2021-08-16
You are free to use this work, with certain restrictions.
2.8 For full licensing information, please see the last slide/page.
Notes & URLs for this presentation can be found…
» underneath the link to this slide show on
granneman.com
» at files.granneman.com/presentations/webdev/CSS-
Overview.txt
History
CSS 1: December 1996
CSS 2: May 1998
CSS 2.1: July 2007
CSS 3: June 1999–Now
CSS 4: 2012–Now
CSS 1 & 2 each were one big document
CSS 3 (& 4) is not one large single spec
Instead, it’s divided into many separate documents
called modules
Currently 50+ modules!
Different modules have different statuses
www.w3.org/Style/CSS/current-work
W3C CSS Working Group: Colors & Status Codes
Why CSS?
95.5% of all websites use CSS
Why?
As of September 2020
Separation of Concerns
Divide computer program into separate concerns, each
focusing on a specific resource
Meaning: HTML
Presentation: CSS
Behavior: JavaScript
Separate content (HTML) from presentation (CSS)
Site-wide consistency: control how all content looks
using only 1 (or a few) CSS file/s
Apply different styles to same content in different
media:
» desktop web browser
» mobile web browser
» auditory
» print
» & more!
Adherence to standards
🎉 🎊 🥳 👯🕺
It’s fun!
Integrating
CSS
4 ways to connect your HTML with your CSS
1. Inline styles
2. Embedded styles
3. Linking to external styles
4. @import
Inline
Uses the style global attribute
Quick & easy to create, but difficult & time-consuming
to manage
Must repeat over and over
Can’t change the style according to the media, so styles
apply to all media
Doesn’t separate content & presentation
So why use it?
Testing (use the Inspector instead)
Use inline styles for unique instances (very rare!)
High specificity: overrides conflicting declaration (only when
absolutely necessary!)
JavaScript often uses inline styles to apply styles dynamically
HTML email
Embedded
Styles inserted inside <style> … </style>
Most often in the <head>, but can be found anywhere in
the <body>
Embedded styles are great for one page …
… but they rapidly become difficult to manage on
multiple pages
So why use it?
Resource inlining: embedding reduces outbound
requests (so does inline CSS)
Portability: You have a widget that may get embedded
into another webpage on another site
To style the widget, you include embedded styles with it
inside <style> … </style>
Linking
HTML 4.01
<head>
<link rel="stylesheet" type="text/css"
href="/css/main.css">
</head>
HTML 5
<head>
<link rel="stylesheet" href="/css/main.css">
</head>
Start with a basic project 1
Create a css folder 2
Create /css/main.css 3
Link to /css/main.css 4
What should you name your CSS file?
It doesn’t matter
main.css
typography.css
client.css
search.css
navigation.css
Where should you place your CSS file?
In your website’s root directory, (almost) always create
these directories:
css (or styles)
fonts
images (or media)
js (or scripts)
A CSS file is made up of rulesets & comments
/* Common */
blockquote, p, td {
font-family: Verdana, sans-serif;
font-size: 1em;
}
#footer {
font-size: .9em;
}
.emphasis {
font-weight: bold;
}
You can link to more than one style sheet, but you
should try to keep those links to a minimum
If you have more than one webpage, you really ought to
use an external style sheet
You can now change the look & behavior of an entire
site by changing only one document!
✏ SIDE NOTE
You might see advice telling you to add this as the 1st
line of your style sheet so the browser knows that
main.css is encoded as UTF-8:
@charset "utf-8";
This is not correct & can be ignored
✏ SIDE NOTE
In CSS 2.1, browsers try to figure out if main.css is
UTF-8 using this order (& stop at the 1st match):
1. Unicode byte-order character at beginning of main.css
2. Value given by charset attribute of Content-Type:
HTTP header or equivalent in protocol used to serve
the style sheet
3. @charset CSS at-rule
4. Value of the charset attribute of <link> in the HTML;
now obsolete in HTML5 & not to be used
5. Assume the document is UTF-8 (!)
✏ SIDE NOTE
“However, there is no actual at-rule named @charset.
When a stylesheet is actually parsed, any occurrences
of an @charset rule must be treated as an
unrecognized rule, and thus dropped as invalid when
the stylesheet is grammar-checked.
Note: In CSS 2.1, @charset was a valid rule. Some
legacy specs may still refer to a @charset rule, and
explicitly talk about its presence in the stylesheet.” —
W3C, 2019
✏ SIDE NOTE
In CSS Syntax Module Level 3 (W3C Candidate
Recommendation, 16 July 2019), this is the order:
1. Value given by charset attribute of Content-Type:
HTTP header or equivalent in protocol used to serve
the style sheet
2. Unicode byte-order character at beginning of
main.css
3. Environment encoding (which should not be used)
4. Assume the document is UTF-8
✏ SIDE NOTE
So, as long as you have Visual Studio Code or another
editor set to save all files as UTF-8 automatically (which
is the default, as it should be!), you are covered
@import
💡PRO TIP
If you have used @import with a CSS preprocessor like
Sass or Less, @import here is different & will cause a
server call
@import allows you to include external stylesheets in
your CSS; in other words, it allows you to link to
another CSS file from within a CSS file (yes, this is a
little weird)
@import must always come 1st, ahead of any other CSS
import.css included via @import
Put @import 1st so it can be overridden
Don’t use it unless you absolutely need to use it, as it
can slow down your page loads*
* Unless you are using a build system like SCSS; more on that in CSS - Preprocessors
✏ SIDE NOTE
Delay User Perception
0–100 ms Instant
100–300 ms Small perceptible delay
300–1,000 ms Machine is working
1,000+ ms Likely mental context switch
10,000+ ms Task abandoned
The Browser
Processing
Pipeline
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
To understand CSS, you have to understand
» the DOM (Document Object Model)
» the CSSOM (CSS Object Model)
» the browser processing pipeline
The DOM
“A conceptual model is a representation of a system,
made of the composition of concepts which are used to
help people know, understand, or simulate a subject
the model represents.” —Wikipedia
We often illustrate conceptual models of both tangible
& intangible things so we can better understand them
Maslow’s
Hierarchy of
Needs
Bloom’s
Taxonomy of
educational
learning
objectives
U.S. Army
adaptation of
Data
Information
Knowledge
Wisdom
Pyramid
Atomic nucleus
composed of
neutrons (blue)
& protons (red)
Carbon atom,
with electron
cloud around
nucleus
Different models for a
water molecule (an
electrically neutral
group of 2 or more
atoms held together
by chemical bonds)
3D schematic
representation
of a sucrose
(sugar) mole-
cule, with atoms
of carbon
(black), oxygen
(red), & hydro-
gen (white)
Animal cell,
made up of
molecules,
which contain
millions or even
trillions of
atoms
Cells, ducts, &
blood vessels in
part of a
mammalian
liver lobule
Major systemic arteries in
the human body
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
Before a webpage appears in a viewport, the rendering
engine downloads the HTML & parses it to figure out
how to display the webpage on screen
During this process, the rendering engine creates the
DOM tree
“A Web page is a document. This document can be
either displayed in the browser window, or as the
HTML source. But it is the same document in both
cases.
The Document Object Model (DOM) provides another
way to represent, store and manipulate that same
document. The DOM is a fully object-oriented
representation of the web page, and it can be
modified with … JavaScript.” —Mozilla Developer
Network
What’s the DOM?
A JavaScript developer will say, “It’s a JavaScript
interface so that I can manipulate the page”
A CSS developer will say, “It’s a set of boxes to style”
An HTML developer will say, “It’s hierarchy & meaning”
They are all correct!
When is the DOM different than your HTML?
If you have mistakes in your HTML, the rendering
engine “fixes” them when it generates the DOM
Source Code
DOM as rendered by browser Inspector
Source Code
No <tbody>
<tbody> added
Rendered DOM
<table> <table>
<tr> <tbody>
<td>Foo</td> <tr>
<td>Bar</td> <td>Foo</td>
</tr> <td>Bar</td>
<tr> </tr>
<td>Baz</td> <tr>
<td>Qux</td> <td>Baz</td>
</tr> <td>Qux</td>
</table> </tr>
</tbody>
</table>
Source code DOM tree
DOM tree
as org chart
Each box you see
here is a DOM node
DOM tree as nested boxes, each one a node
DOM tree as HTML elements,
each one a node, with <html>
<html> as the document root
<head> … </head>
<body>
<header> … </header>
<main>
<h1>The Call of Cthulhu</h1>
<p>Ph’nglui Cthulhu R’lyeh!</p>
</main>
<footer> … </footer>
</body>
</html>
Firefox up to version 47 had a cool feature called 3D
View that let you “rotate and re-orient the 3D
presentation of the DOM hierarchy of your page to see
it from different angles”
The CSSOM
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
The CSSOM is built by the rendering engine using
specified stylesheet rules from:
» built-in rules that come with the browser
» rules added by user
» rules created by CSS authors (developers)
Bringing It All
Together
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
JavaScript can change the DOM & the CSSOM
The combination of the DOM, CSSOM, & JavaScript
means that webpages are dynamic because
JavaScript can:
» add, change, & remove any DOM elements &
attributes
» change any CSSOM styles
» react to all existing events
» create new events
As of July 2020, there are 69 Web APIs
Ambient Light Events • Background Tasks • Battery • Beacon • Bluetooth •
Broadcast Channel • CSS Counter Styles • CSS Font Loading • CSSOM •
Canvas • Channel Messaging • Console • Credential Management • DOM •
Encoding • Encrypted Media Extensions • Fetch • File System • Frame Timing
• Fullscreen • Gamepad • Geolocation • HTML Drag and Drop • High
Resolution Time • History • Image Capture • IndexedDB • Intersection
Observer • Long Tasks • Media Capabilities • Media Capture and Streams •
Media Session • Media Source Extensions • MediaStream Recording •
Navigation Timing • Network Information • Page Visibility • Payment
Request • Performance • Performance Timeline • Permissions • Pointer
Events • Pointer Lock • Proximity Events • Push • Resize Observer • Resource
Timing • Server Sent Events • Service Workers • Storage • Storage Access •
Streams • Touch Events • URL • Vibration • Visual Viewport • Web
Animations • Web Audio • Web Authentication • Web Crypto • Web
Notifications • Web Storage • Web Workers • WebGL • WebRTC • WebVR •
WebVTT • WebXR Device • Websockets
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
The rendering engine matches HTML element objects
with CSS rule objects to generate the Render Tree
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
The rendering engine uses the Render Tree to layout
boxes in the viewport
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
The rendering engine displays (paints) all the content
of the page in the viewport, from back to front
Events
HTML DOM
JavaScript Render Tree Layout Paint
CSS CSSOM
JavaScript events can further change the DOM & the CSSOM
The big takeaway: when you’re working with CSS, you
are manipulating objects that will be rendered as boxes
Basic
Selectors
A CSS selector declares which DOM objects should
have particular styles applied to them
The browser’s rendering engine…
» parses the CSS & HTML
» matches selectors to the appropriate DOM objects
» applies the CSS style to the rendered DOM objects
HTML CSS
<h1 align="center"> h1 {text-align: center;}
Entire thing is a tag Entire thing is a style rule
h1 is an element h1 is a selector
align is an attribute text-align is a property
center is a value center is a value
align="center" is an text-align: center is a
attribute-value pair declaration
Everything inside { & } is a
declaration block
CSS 1: 10 different selectors (including selectors,
combinators, pseudo-classes, & pseudo-elements)
CSS 2: 13
CSS 3: 21
CSS 4: 26 (so far!)
70 in total
1. Simple selectors 3. Complex selectors with
combinators
» Universal
» Type » Descendant
» Class » Child
» ID » Adjacent sibling
» Pseudo-classes » General sibling
» Pseudo-elements
» Attribute 4. Selector list
2. Compound selectors
Simple Selectors
A simple selector describes a single condition on an
element
If the condition is true, the element is selected
* (universal): Is this an element?
element: Is this the specific type of element?
.class: Does this element have this class on it?
#ID: Does this element have this ID on it?
Universal
*
Selects every HTML element
(Though later CSS rules can override these
declarations)
Type
element
Selects every matching HTML element (e.g., <p>, <ul>,
or <h3>)
AKA Element Selectors
Used when you want to affect every instance of an
element
Class
.class
Selects any element to which the class has been applied,
as many times per page as needed
HTML:
<p class="intro">…</p>
CSS:
.intro {
font-weight: bold;
}
Dot in front of the class name
in CSS, but no dot in HTML
Dot labels the class in CSS
The class attribute labels the
element in HTML
The paragraph with class
applied to it is different from
the paragraph that does not
have that class
A class can be applied as many
times per page as you wish
You can use multiple (2, 3, 4, whatever) classes on an
element when needed
✏ SIDE NOTE
A student once did this:
<figcaption class="center" class="image-
caption"> 🤨
This will not work! No duplicate attributes!
You must use:
<figcaption class="center image-caption">
✏ SIDE NOTE
How do you match an element that has a particular
combination of classes on it?
<p class="center note">
See Compound Selectors later in this slide deck
There is no default list of class names
You come up with the class names your project uses (or
you use those provided by a framework like Bootstrap)
Don’t use spaces
Rules for class values in HTML5
In fact, you can use emoji for class names
.📰 {
background-color: hsl(0,0%,76%);
}
.🤮 {
font-family: "Comic Sans", cursive;
}
The big rule for class names: describe function, not
appearance
Not “what does it look like?” but instead “what is it
for?”
Bad class names Good class names
.author name .author-name
.big-red .caption
.small .alert
.footnote
.center
Multiple words in a class name?
.main-content-nav ← What most developers use
.main_content_nav
.maincontentnav
.mainContentNav
.MainContentNav
Just be consistent!
ID
#id
Selects any element to which the ID has been applied,
but each ID can only be used once per page
You can use multiple IDs on a page, but each ID must
be unique
#id & .class share a lot of similarities
» Names are made up by developers, not specs
» Names shouldn’t have spaces
» Names should denote purpose, not appearance
» Names containing multiple words should be
combined with a - or something else consistently
A specific ID can be applied
one time per page
Class ID
CSS .foo #bar
HTML class="foo" id="bar"
Unique on page No Yes
class="foo" 10x id="bar" once
Values per element Multiple One
class="foo bar" id="baz"
Specificity 10× 100×
URL addressable No Yes
Bad ID names Good ID names
#top nav #sidebar (use <aside>)
#tiny-little-fonts #utility-nav (use <nav>)
#site-footer (use
<footer>)
#logo
#legalese
Use classes instead of IDs (in fact, try to avoid IDs as
much as possible when it comes to CSS)*
Classes can be reused, while IDs cannot
IDs can make the cascade (more about that soon!) very
complicated
Many (most?) frameworks (like Bootstrap) stick to
classes entirely
* OK, you may need one every once in a blue moon
However, even if we don’t use IDs in CSS as much as
we used to, they are still necessary
» Page fragment identifiers
» Unique hooks for JavaScript
IDs as page fragment identifiers
Given this HTML on http://www.foo.com/toc/:
<h2 id="chapter2">
You could link directly to it on the same page:
<a href="#chapter2">
Or from a different page:
<a href="http://www.foo.com/toc/#chapter2">
This parameter…
…helps the JavaScript…
…target this ID
Other simple selectors
» Attribute selector
» Pseudo-class
» Pseudo-element
Those will be covered in CSS - Selectors
Compound Selectors
A compound selector describes multiple conditions on
an element
If all conditions are true, the element is selected
Consists of a chain of simple selectors connected
together, but not connected by a combinator (which is
coming up next)
p.alert matches
<p class="alert">
table.inventory matches
<table class="inventory">
table.inventory.northwest matches
<table class="inventory northwest">
.cthulhu:first-child matches the first
<element class="cthulhu">
A compound selector is used to match an element that
has two classes on it
<p class="center note">
.center { Selects elements with the
text-align: center; .center class
}
.note { Selects elements with the
font-size: .9em; .note class
}
.center.note { Selects elements with the
font-style: italic; .center and .note classes
}
Complex Selectors
Using Combinators
A complex selector uses combinator(s) to combine
multiple selectors together into 1 selector
.ws-gallery img { … }
ul > li { … }
h2 + p.lead { … }
Combinator Name Ex. Which B is selected?
␣ (space) Descendant A B Any descendant of A
> Child A > B Direct children of A
+ Next Sibling A + B Next sibling after A
~ (tilde) Subsequent A ~ B All siblings after A
Siblings
A combinator expresses a relationship between
selectors
Key Selectors
Rendering engines match selectors from right to left
The right-most part is the key selector, the actual object
being selected
Really helpful understanding complex selectors
ul li
ul > li
ul > li a[title="home"]
.callOut > p:last-child
.ws-header .nav > li > a
p code, pre code, blockquote code
Descendant Combinator
selectorA selectorB
Selects all selectorB who have selectorA as an
ancestor
selectorB can be a child, grandchild, or later
descendant of selectorA
Any other selectorB who does not have selectorA as
an ancestor is unaffected
Default for nested <li>:
disc •, circle ◦, square ▪
I only wanted these <li>s to
change to ▪, not all of them
You can often use a descendant combinator instead of a
class (& you must if you cannot change the HTML)
👎
HTML
<aside>
<img
class="headshot"
src="…">
</aside>
CSS
.headshot {}
👎 👍
HTML Cleaner HTML
<aside> <aside>
<img <img src="…">
class="headshot" </aside>
src="…">
</aside> Better CSS using the
descendant combinator
CSS aside img {}
.headshot {}
Child Combinator
selectorA > selectorB
Selects any selectorB who is a direct child of selectorA,
not a grandchild or any other descendants
All siblings who are direct children of selectorA are
selected
Siblings: 2 or more elements that share a parent
Contrasts with the descendant combinator, which selects
both direct children & any descendants, no matter how deep
Default for nested <li>:
disc •, circle ◦, square ▪
👍
} 🤨
}
1st level changed from • to ▪,
but 3rd level remains ▪ because
that’s the default
Let’s change all 3 level defaults:
1st from • to ▪, 2nd from ◦ to •,
& 3rd from ▪ to ◦
An illustration of the difference between the descendant
& child combinators
Using > limits the scope of the styles
Selector List
selectorA, selectorB, selectorC
List selectors that have similar declarations for
simpler & cleaner CSS & HTML
Don’t do this: Do this:
p { blockquote, p {
font-family: serif; font-family: serif;
font-size: 1em; font-size: 1em;
} }
blockquote {
font-family: serif;
font-size: 1em;
}
Any selector can be included in the list
.emphasis, .title {font-style: italic;}
em, .title {font-style: italic;}
p, #nav, .pullquote {font-family: Verdana,
sans-serif;} 🤪
A very common selector list
h1, h2, h3, h4, h5, h6 {
font-family: "Georgia Pro", Georgia, serif;
}
Group similar selectors, but be specific where needed
CSS is cumulative unless overridden
blockquote, p {
font-family: Verdana, sans-serif;
}
p {
line-height: 1.5;
}
Turn this… …into this:
h1 { h1, h2 {
font-weight: normal; font-weight: normal;
font-size: 2.5em; font-family: serif;
font-family: serif; }
}
h1 {
font-size: 2.5em;
h2 {
}
font-weight: normal;
border-bottom: 1px h2 {
dotted black; border-bottom: 1px dotted
font-family: serif; black;
font-size: 1.8em; font-size: 1.8em;
} }
Good practice Elements, then IDs, then classes
blockquote,
Alphabetical order within
option,
p,
each grouping of selectors
td,
#sidebar,
.legalese {
font-family: Verdana, sans-serif;
font-size: 1em;
}
Formatting
Don’t do this:
h1 {color: dimgray;}
h1 {font-size: 1.4em;}
h1 {font-weight: bold;}
h1 {font-family: Verdana, sans-serif;}
Instead, combine related declarations
h1 {
color: dimgray;
font-family: Verdana, sans-serif;
font-size: 1.4em;
font-weight: bold;
}
Formatting CSS rulesets
selector {
property: value;
property: value;
property: value;
…
}
The order of declarations in the declaration block
doesn’t matter
Do not forget to put ; at the end of every line in a
ruleset
You do not actually have to put ; at the end of the last line in a ruleset, but that is a very bad
habit to get into
Use comments in CSS for the same reasons as in
HTML
» Notes to yourself & others
» Debugging: comment out troublesome CSS for testing
(use your browser’s Inspector)
HTML comments
<!-- blah blah html blah blah html -->
CSS comments
/* blah blah css css blah blah css css */
✏ SIDE NOTE
Design Pattern
“a formal way of documenting a solution to a design
problem in a particular field of expertise.” —Wikipedia
“Each pattern describes a problem that occurs over and
over again in our environment, and then describes the
core of the solution to that problem” —Christopher
Alexander, architect & author of A Pattern Language
(1977)
✏ SIDE NOTE
Bootstrap 4’s classes for the common design pattern of
rounded borders
✏ SIDE NOTE
Bootstrap 4’s classes for the common design pattern of
cards
💡PRO TIP
Here’s the order Jans normally uses in his
stylesheets
1. General rules that apply to the whole site (linked
libraries, typography)
2. Site-wide design patterns (header, nav, footer)
3. Page type design patterns (sidebar, news, post)
4. Specific page design patterns (home page)
5. Content design patterns (callouts, image gallery)
With appropriate comments sprinkled throughout
💡PRO TIP
Here’s the order I sometimes shoot for in my stylesheets
@font-face
html
body
/* General */
<type selectors, A➝Z>
<ID selectors, A➝Z>
<class selectors, A➝Z>
/* <New Section> */
<type>
<ID>
<class>
…
<span>
&
<div>
HTML elements “work” without attributes & values
(with a tiny few exceptions, like <img> & <a>)
<span> & <div> are HTML elements exist solely to
work with CSS*
<span> & <div> by themselves do nothing on a
webpage (except draw invisible boxes)
They must use CSS (class="foo" or id="bar") to do
anything productive
* & JavaScript
<span>
<span> is a text semantic element that creates an inline box &
does nothing else without CSS
Use <span> to hold attribute-value pairs relevant to CSS
As a text semantic element, it usually doesn’t have other
elements nested inside it
<span class="foo">Ph’nglui mglw’nafh Cthulhu R’lyeh
wgah’nagl fhtagn!</span>
Use it when other text semantic elements are not semantically
appropriate
<div>
<div> is a grouping element that creates a block box by
default & does nothing else without CSS
Use <div> to hold attribute-value pairs relevant to CSS
As a grouping element, it groups other elements, e.g.,
put a <div> around 3 <p>s & a <ul>
Use it when other grouping elements are not
semantically appropriate
I want the table of contents to stand
out with a background color,
borders, & rounded corners
Well that looks stupid…
Much better—& that is why we have
<div>
Actually, to be semantic, I should
really use an <ol>
This is a useless <div>
<div class="lead-copy">
<p>
When a traveller in north central Massachusetts takes
the wrong fork at the junction of the Aylesbury pike just
beyond Dean’s Corners he comes upon a lonely and
curious country.
</p>
</div>
Only use <div> around 2 or more elements that create block
boxes*
* It’s OK to wrap a <div> around 1 element in a few cases
Inheritance
Some properties, like font-size & color, are inherited:
elements with those properties pass those properties
down through the DOM to their descendant elements
(unless overridden)
Other properties, like background-image & border, are
not inherited: elements with those properties do not pass
those properties down to their descendent elements
Inheritance is for elements that do not have properties
set
border- font-style line-height
collapse font-variant orphans
border-spacing font quotes
caption-side letter-spacing text-align
color list-style- text-edge
cursor type text-indent
direction list-style- text-transform
empty-cells position visibility
font-family list-style- white-space
font-size image widows
font-weight list-style word-spacing
Partial list of inherited properties
Cascading
Style Sheets
How does the rendering engine know which style to apply
to an element?
If a selector matches an element, that selector’s styles are
used
Inheritance comes into play if an element does not have
properties set
But what if the CSS rules conflict; e.g., what if CSS tells
the rendering engine to make all <p>s use serif and sans-
serif fonts?
If an element’s CSS declaration conflicts with another
declaration, the rendering engine uses the Cascade to
find a winner
In other words, conflicting declarations follow a
cascade, & the rule with the most weight wins
3 parts to the Cascade
1. Origin & Importance
2. Specificity
3. Order
Note: as of CSS Cascading and Inheritance Level 4 (August 2020), things have changed if the
Shadow DOM is involved; more on this in the Web Components presentation
Origin & Importance
CSS can originate from 3 places:
» Browser, aka, the user agent
» User
» Author
All Web browsers have built-in CSS rules
In Firefox, for example, why does <p> have a certain
amount of space before & after it?
Because of Firefox’s built-in default CSS
Firefox
Equivalent to margin-top: 1em
& margin-bottom: 1em
WebKit (Safari)
Equivalent to margin-top: 1em
& margin-bottom: 1em
1em on top & bottom; 0 on right & left
“The CSS rules given in these subsections are, except
where otherwise specified, expected to be used as part
of the user-agent level style sheet defaults for all
documents that contain HTML elements.”
Users can specify CSS rules too
Why?
» All fonts are at least a certain size
» A certain font is used because it’s more readable
» Always enable text-decoration: underline so
links are obvious
» See outlines around elements with keyboard focus
using outline: solid
Firefox has always allowed users to create their own
styles in a file called userContent.css that goes into
your Firefox Profile
For more about your Profile: kb.mozillazine.org/
Profile_folder_-_Firefox
For more about userContent.css: kb.mozillazine.org/
UserContent.css
✏ SIDE NOTE
As of Firefox 69, userContent.css isn’t supported
by default unless users first enable the feature
1. Type about:config in the Firefox address bar &
select Enter
2. Click the button that confirms you Accept the Risk
and Continue
3. In the box at the top, search for toolkit.
legacyUserProfileCustomizations.stylesheets
4. Double-click on the resulting line to toggle to true
5. Restart Firefox
Internet Explorer
Chrome 33 (2014) dropped support for a user styles file
Chrome 33 (2014) dropped support for a user styles file
Edge: Never supported a user styles file!
Edge: Never supported a user styles file!
Safari — I created safari.css for my own use
My safari.css file
html {
font-family: "Source Sans Pro", sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Georgia Pro", serif;
}
code, kbd, pre, samp, tt, var {
font-family: "Source Code Pro", monospace;
}
✏ SIDE NOTE
Browser makers’ response when asked about missing
support for a user styles file: “Get an extension”
Do get:
» Stylus for Chromium-based browsers & Firefox (which
is excellent & removes all analytics, telemetry, & data
collection)
» Cascadea for Safari
Do not get: Stylish (used to be good, but now it’s
spyware)
If a user’s CSS contradicts a author’s CSS, the user can
make sure hers “wins”
Use !important after a property-value pair
p {
font-size: 36px !important;
}
However, CSS authors can do the same thing!
My safari.css file Notice: no !important
html {
font-family: "Source Sans Pro", sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Georgia Pro", serif;
}
code, kbd, pre, samp, tt, var {
font-family: "Source Code Pro", monospace;
}
The order of origin & importance
AKA
The order in which stylesheets are weighted, from
lightest to heaviest
Order of
origin & Browser
importance,
from lightest User
to heaviest
Author
Author !important
User !important
Author & Author !important?
Why are you contradicting yourself?
Do I contradict myself?
Very well then I contradict
myself,
(I am large, I contain
multitudes.)
From Walt Whitman’s
“Song of Myself” from
Leaves of Grass
You’re not contradicting yourself (hopefully!)
What if you’re using Bootstrap & its default CSS?
<link rel="stylesheet" href="bootstrap.css">
Is that CSS coming from the browser, user, or author?
You will want to override some of Bootstrap’s selectors
<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="me.css">
Author vs. author
Sometimes, you will have to use !important to beat the
other author
Be careful using !important
“!important: 3 seconds to type, 3 years to remove.”
—Harry Roberts
“!important is the Hammer of Thor, smiting
everything in its path.” —Jans Carton
Only use it as a last resort
Specificity
Specificity asks how specific is each selector?
Each simple selector is assigned a weight value
The greater the weight, the more specific the selector
In other words, with great weight comes great specificity 😜
Selector(s) Column
1 × #ID a
1 × .class, :pseudo-class, & [attribute] b
1 × type & ::pseudo-element c
Take the numbers & place them a,b,c, e.g., 0,2,1
a b c Total
* 0,0,0
li 1 0,0,1
.foo 1 0,1,0
#chapter1 1 1,0,0
Remember, compound & complex selectors are made
up of multiple simple selectors
Simply add their simple selector weight values together
p.foo.bar (compound) is made up of 1 type & 2
classes, so 0,2,1
.foo > cite (complex) is composed of 1 class & 1 type,
so 0,1,1
The following are ignored when calculating
specificity:
» Combinators: ␣, >, +, ~
» Universal selector: *
» Negation pseudo-class (but not the contents — that is
counted!): :not(.but-this-part-is-counted)
Inline styles (<style="foo">) always outweigh
everything else (a good reason to hate them 🤬)
a b c Total
* 0,0,0
li 1 0,0,1
.foo 1 0,1,0
#chapter1 1 1,0,0
ul li 1 × 2 0,0,2
.foo > li 1 1 0,1,1
ul ol li.steps 1 1 × 3 0,1,3
li.steps.mech 1×2 1 0,2,1
style="foo" ∞
A positive integer in a column
outweighs any positive
integer, even if it’s greater, in
a column to the right
26 in column b is outweighed
by 1 because it is in column a
Visual Studio Code shows you the specificity of a
selector when you hover over it & what it will look like
visually
Order
Later CSS in the stylesheet wins over earlier CSS
main.css:
.blue {color: blue}
.red {color: red}
index.html:
<p class="red blue">
What color am I?
</p>
main.css:
.blue {color: blue}
.red {color: red}
index.html:
<p class="red blue">
What color am I?
</p>
main.css:
.red {color: red}
.blue {color: blue}
index.html:
<p class="blue red">
What color am I?
</p>
main.css:
.red {color: red}
.blue {color: blue}
index.html:
<p class="blue red">
What color am I?
</p>
The Cascade
Here’s some code I have on a website:
<div class="callOut">
<p>
For the next 2 weeks…
</p>
</div>
.callOut {
background-color: #E6E8F2;
margin: 1em 1em 2em 1em;
padding: 1em;
border: 1px #ccc solid;
border-radius: 1em;
}
The result!
However…
That extra space at the
bottom really bothers me
That extra space at the
bottom really bothers me
To fix it, I put this in my CSS at lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Let me explain what that means…
> is a combinator that selects the p:last-child is a
direct children of (not descendants pseudo-class that
of) the .callOut class means the <p> that
is the last child of
(not descendant of)
.callOut > p:last-child { the .callOut class
margin-bottom: 0;
}
So this selects the <p> that is the last direct child of
the .callOut class
.callOut > p:last-child {
EX
margin-bottom: 0; AM
}
PL
<div class="callOut"> E
<p>foo</p>
<p>bar</p>
<p>baz</p>
<p>quz</p> Selected!
<blockquote>
<p>quux</p> Not selected, as this <p> is
</blockquote> not the last direct child
</div>
Why use this?
.callOut > p:last-child {
margin-bottom: 0;
}
Why not just use this?
.callOut > p {
margin-bottom: 0;
}
Because sometimes there are 2 or more paragraphs inside
.callOut
So back to where I was… I put this in my CSS at line
194:
.callOut > p:last-child {
margin-bottom: 0;
}
Let’s check the webpage…
Nothing changed!
Why didn’t it work?
Let’s open the Inspector & find out why
Hmmm… mine is being beaten by earlier code
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Why isn’t mine winning since it’s later in order?
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Is origin & importance causing the 1st declaration block
to win? 🙅
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Is specificity causing the 1st declaration block to win? 🤔
#content p { .callOut > p:last-
margin-bottom: 12px; child {
} margin-bottom: 0;
}
Specificity Specificity
(#content = 100) + (.callout = 10) +
(p = 1) = (p = 1) +
101 (:last-child = 10) =
21
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Because specificity meant the 1st declaration block had
the most weight, order never entered into the picture
Nope—tied
Specificity beat me Never got to it
There are 3 solutions to this problem
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0 !important;
}
Adding !important makes the 2nd ruleset win due to origin
& importance, so specificity & order never come into play
I won before
we could get to
anything else
Never got to it
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
#content .callOut > p:last-child {
margin-bottom: 0;
}
Adding #content to line 194 makes the 2nd ruleset win due
to specificity, so order & importance never comes into play
Lines 146–148: 100 + 1 = 101
#content p {
margin-bottom: 12px;
}
Lines 194–196: 100 + 10 + 1 + 10 = 121
#content .callOut > p:last-child {
margin-bottom: 0;
}
Adding #content to line 194 makes the 2nd ruleset win due
to specificity, so order & importance never comes into play
Nope—tied
I won (121 over 101)
Never got to it
Lines 146–148:
#content p {
margin-bottom: 12px;
}
Lines 194–196:
.callOut > p:last-child {
margin-bottom: 0;
}
Getting rid of #content on line 146 makes the 2nd
ruleset win due to specificity, but I can’t easily remove it!
Lines 146–148:
#content p { 1
margin-bottom: 12px;
}
Lines 194–196: 10 + 1 + 10 = 21
.callOut > p:last-child {
margin-bottom: 0;
}
Getting rid of #content on line 146 makes the 2nd
ruleset win due to specificity, but I can’t easily remove it!
Much better!
Much better!
Bonus question: how do we get rid of those extra pixels at
the top?
Much better!
Then I realized that <div class="callOut"> doesn’t
always end with <p>
#content .callOut > :last-child {
margin-bottom: 0;
}
Now it’s weighted to win and selecting the correct DOM
objects
Remember, :last-child is the same as *:last-child
What if I have nested last children inside other nested
last children?
.callOut > :last-child,
.callOut > :last-child > :last-child,
.callOut > :last-child > :last-child > :last-
child {
margin-bottom: 0;
}
CSS Reset
Keywords
✏ SIDE NOTE
CSS keywords have special meaning in CSS & are
reserved by the language, e.g.:
» border & font-family are property keywords
» solid & dotted are value keywords
» black & red are color value keywords
» <length> & <color> are data type keywords
» @media & @supports are at-rule keywords
» attr() & calc() are function keywords
» :hover & :focus are pseudo-class keywords
» ::before & ::first-letter are pseudo-element
keywords
There are 5 global keywords in CSS
» 4 are values: initial, inherit, unset, & revert
» 1 is a property: all
initial value resets property back to its default value as
defined in the spec
inherit value forces an element to inherit styles from an
ancestor that it would not normally inherit
unset value acts as either inherit (if the property is
inherited) or initial (if the property is not)
revert value rolls back the property’s cascade, depending
upon who declared it: the browser, user, or author
initial value resets property back to its default
value as defined in the spec
Remember, in the specs for CSS…
» display default is inline
» font-size default is medium
» border-style default is none
» border-width default is medium
» margin & padding defaults are 0
» font-family default “depends on user agent”
Don’t get confused
Look at <p>
» Browsers set defaults by selector, so <p> defaults to
display: block
» The spec sets defaults by property, so display:
inline is the default
initial resets properties back to the spec, not the
browser!
The browser’s default for <p>
is display: block
The spec says that all boxes
default to display: inline
initial resets back to the
spec, not the browser
The inherit value forces an element to inherit values
from properties that are not normally inherited
unset value acts as either inherit (if the property is
inherited) or initial (if the property is not)
What’s the use case for this? See all just ahead
revert value rolls back the property’s cascade,
depending upon who declared it: the browser, user,
or author
» if the author is the origin, it rolls back to the user
» if the user is the origin, it rolls back to the browser
» if the browser is the origin, it rolls back to the spec
If the origin that is rolled back to does not declare a
value for the property, it is skipped & the rendering
engine rolls back another level
Effects of revert
Author
If revert is rolling back a property’s
User style set by an author, & the user has
not set a style, it skips the user &
Browser rolls back to the browser, & so on
Spec
Most common use-case for revert: you have a heavily-
modified selector & you want to revert back to the
browser’s defaults (remember, most users never set any
styles, so that one is skipped over)
all
Magic property that resets all property values, except
for direction & unicode-bidi
Really designed to be used with small components —
you wouldn’t want to do this for an entire page
Values are the 4 global keywords: initial, inherit,
unset (which now makes sense in a limited scenario!),
& revert
initial – 12 19 3.2 4 4 2.3
inherit 8 12 2 3.1 3.2 4 2.1
unset – 13 27 9.1* 9.3* 41 41
revert – 84 67 9.1 9.3 84 84
all – 79 27 9.1 9.3 37 4.4.4
* all: unset is buggy in Safari & sets color to black, preventing you from setting another color; the
* workaround is to use -webkit-text-fill-color everyplace you also use color; Safari 14 fixes this
Tools
Books
Great overview of HTML5
& CSS2 (& some CSS3)
References
developer.mozilla.org/en-US/docs/Web/CSS/Reference
As of July 2020 there are 617 terms!
MDN supporters & contributors
1st 8 Guides on CSS Tricks (there are lots more!):
» A Complete Guide to Flexbox ★
» Media Queries for Standard Devices
» A Complete Guide to Grid ★
» A Complete Guide to the Table Element
» Centering in CSS: A Complete Guide
» A Complete Guide to SVG Fallbacks
» A Nerd’s Guide to Color on the Web
» A Complete Guide to Data Attributes
apps.workflower.fi/vocabs/css/
pinboard.in/u:rsgranne/t:css
Browser Tools
Built-in developer tools are excellent
Validation
jigsaw.w3.org/css-validator/
Color Pickers
Sip
Color picker
theolabrothers.com
$0 (with $9.99 in-app purchase)
Just Color Picker
Small & with the necessary features
$0
annystudio.com/software/colorpicker/
ColorPro
Professional color picker
www.iconico.com/colorpro/
$30
Thank you!
[email protected]
www.granneman.com
ChainsawOnATireSwing.com
@scottgranneman
[email protected]
websanity.com
CSS Overview
Selectors, Integration, Inheritance, Cascading
R. Scott Granneman r Jans Carton
© 2009 R. Scott Granneman
Last updated 2021-08-16
You are free to use this work, with certain restrictions.
2.8 For full licensing information, please see the last slide/page.
Changelog
2021-08-16 2.8: Explained how @import is different
from Sass @import; removed wrong advice to put
@charset at top of style sheet with emoji; more detail
about @charset & how parsers detect UTF-8
Changelog
2021-07-13 2.7: Added another explanation of the DOM,
from Wikipedia; more improvements to Specificity;
updated chart in Reset Keywords; added conceptual
models to DOM
2021-04-12 2.6: Added in Notes that class & ID names are
identifiers; added better explanation & chart for Complex
Selectors Using Combinators; completely re-did Specificity
section; added Side Note under Linking about using
@charset "utf-8";; fixed W3C logo in MDN members
Changelog
2020-11-30 2.5: Re-ordered & changed wording slightly
in Specificity; updated examples in Compound Selectors;
added detail re: Shadow DOM & the Cascade; changed
Importance to Order & Importance to match the spec
more closely; updated Cascade diagram & improved
wording throughout Cascading Style Sheets
2020-07-31 2.4: Created diagram for the Browser
Processing Pipeline; made Descendant Combinator
examples clearer by adding arrows
Changelog
2020-07-21 2.3: Added list of Web APIs after
JavaScript; added slides about design patterns in
Formatting; added example of looking up property’s
initial value at MDN; updated screenshot for initial
value & added explanation to it; added additional,
easier examples for descendant & child combinators;
changed CSS Resets to CSS Reset Keywords; improved
wording explaining inherit value; moved Key
Selectors at the beginning of Complex Selectors
Changelog
2020-07-15 2.2: Minor fixes; re-did Specificity
completely; removed the Miller’s Crossing example;
made clearer in Order what is in HTML & what is in
CSS
2020-07-10 2.1: Added note about Safari bug with all:
unset
Changelog
2020-07-09 2.0: (con’t. from ↓) added better
descriptions of <span> & <div>; changed “Default
inherited properties” to “Partial list of inherited
properties” & added text-edge; added detail to MDN’s
CSS Reference in Tools; updated screenshots of CSS-
Tricks in Tools; added CSS Resets section for initial,
inherit, unset, revert, & all; added explanation of
CSS keywords; so many changes I bumped version
number up to 2!
Changelog
2020-07-09 2.0: Added more details to Specificity; minor
edits; added definition of simple selector; moved Key
Selectors under Complex Selectors; for user styles, gave
more detail re: Firefox’s userContent.css, Chrome, &
extensions, & updated screenshot of Safari’s Advanced
Preferences; better screenshot for embedded styles;
updated screenshot for .class selector; updated table
showing difference between HTML & CSS terms; added
order Jans places things in his stylesheets; (con’t. ↑)
Changelog
2018-12-06 1.20: Added screenshots showing embedding
with <style> & how to link to main.css; added logos for
MDN supporters; *:first-child is the same as :first-
child; added Side Note re: using 2 class attributes; in
Formatting, always put ; at the end of each declaration;
added CSS Tricks to Tools; in Class, told viewer to see
Compound to learn how to match an element with 2
classes; screenshots for @import & reorganized those
slides; minor wording changes; better example for
Compound selectors; replaced ID screenshots
Changelog
2018-11-21 1.19: Called out items on browser processing
pipeline illustration; fixed image for multiple classes
(<figurecaption>?!); updated screenshots for child
combinator; for selector lists, removed silly example &
added headings slide; added Side Note on <div> that it
should semantically be <ol>; fixed Cascade example so
proper method is shown; added slides showing difference
between descendant & child combinators; added table on
Time & User Perception to @import; replaced inherit
screenshot
Changelog
2018-10-01 1.18: Added how DOM changes attribute-
value pairs; replaced DOM section with The Browser
Processing Pipeline; fixed Default inherited properties
slide; updated theme to Granneman 1.5; added Walt
Whitman on contradicting yourself
2017-11-06 1.17: Improved key selectors; added reasons
for user CSS
Changelog
2017-10-30 1.16: Added Just Color Picker; added
screenshot of ColorPro website; changed color of some
arrows & shapes to Tulip Tree (#E8A433); better
solutions to specificity problem with .callOut; fixed
wording to be correct &/or more specific; added emoji
for class names; added Opera user-agent styles; better
examples for Key Selectors; applied Granneman 1.4
theme; fixed formatting issues; added default order I
use in stylesheets
Changelog
2017-10-25 1.15: Added better examples for DOM vs
source code; organized Basic Selectors much better;
moved Key Selectors, IDs as page fragment identifiers &
JavaScript hooks, & Compound Selector example from
CSS Selectors to here; gave full list of selectors & grayed
out ones we’re not covering here; fixed wording
introducing the Cascade
Changelog
2017-10-18 1.14: Took out details about how to turn on
Firefox 3D View, since it’s not longer supported; made
Cascading chapter slide italicized; corrected & added info
on anonymous boxes; in History, hid modules & added
Can I Use, minor fixes & corrections
2016-09-23 1.13: Moved slide comparing class & ID; under
Importance, rearranged IE & Safari & added Firefox for
Windows, Chrome, & Edge; re-ordered examples of
Descendant Combinator; fixed formatting errors
Changelog
2016-09-16 1.12: Updated theme to Granneman 1.2;
small changes in wording to make things clearer;
cleaned up formatting in a few places; added slide re:
using classes instead of IDs; fixed slides in Selector
Grouping; changed Important example from
WordPress to Bootstrap; fixed wrong information re:
class & id values & clarified; added example for
Descendant Combinator
Changelog
2016-01-20 1.11: Added slide re: CSS3 Taxonomy &
Status; better explanation why we need <div>; added note
re: specificity
2016-01-11 1.10: Minor improvements taken from CSS -
Selectors; added Child Combinator to Selectors; added
another example of Child Combinator; added screenshots
of browser CSS; explained author vs author in
Importance; explained how my Safari CSS works; added a
long example showing how the Cascade works in practice
Changelog
2015-12-13 1.9: Clarified source of DOM quote; changed numbers
of selectors; got rid of E & F in selectors & made them clearer;
changed .bigRed to .big-red; clarified source of class & ID names;
add tweet re: CSS to beginning
2015-05-10 1.8: Added info about CSS 4; clarified that <span> &
<div> draw boxes; added additional names of directories that are
always created; changed “What Google prefers” to “… uses”;
removed Hues & added Sip to Color Pickers; fixed URL &
screenshots for CSS Vocabulary; moved Viewport Resizer to
Bootstrap; for Separation of Concerns, added “& Meaning” to
HTML
Changelog
2015-03-06 1.7: Added another example of selector
grouping; added details about resource inlining
2015-01-12 1.6: Added my safari.css file; clarified &
added info on specificity
2015-01-11 1.5: Clarified Inheritance
2014-09-27 1.4: Changed “browser” to “rendering engine”
in a few places where it made sense
Changelog
2014-08-12 1.3: Improved Descendant Selector examples;
improved wording & added slides in DOM section; improved
Cascade diagram; fixed <div> screenshot; added URLs for
<div> & <span> screenshots; fixed Viewport Resizer
screenshots
2014-08-10 1.2: Added DOM spec info & screenshots of DOM
& Source Code; added details about Firefox Web Dev Tools
2014-08-04 1.1.1: Added definition of anonymous object
Licensing of this work
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
You are free to:
» Share — copy and redistribute the material in any medium or format
» Adapt — remix, transform, and build upon the material for any purpose, even commercially
Under the following terms:
Attribution. You must give appropriate credit, provide a link to the license, and indicate if changes were made.
You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your
use. Give credit to:
Scott Granneman • www.granneman.com • [email protected]
Share Alike. If you remix, transform, or build upon the material, you must distribute your contributions under
the same license as the original.
No additional restrictions. You may not apply legal terms or technological measures that legally restrict others
from doing anything the license permits.