Today we'll look at what CSS is, how it operates, where to put it, how to write CSS rules, and how to validate our CSS.
Today we learn a new language! CSS, or "Cascading Stylesheets" is a computer language that has been a part of the web since 1996. Currently, we use "CSS3", but since new features keep getting added incrementally, there likely won't be something we call "CSS4".
Just like HTML and the Web Accessibility Guidelines, CSS is governed by W3C.
(For better, or for worse) CSS controls how web documents (a.k.a. web pages, a.k.a. HTML) look, from colours and fonts to layouts and animation.
As discussed, having our styling kept separate from our content (HTML) and our functionality (JavaScript), allows for the "separation of concerns".
These different languages do different tasks, which makes things more resilient (one thing can break without taking everything down with it), more maintainable (you can update the look without having to rewrite the content, for example), and easier to understand.
CSS as a language is tremendously flexible (and can be a lot of fun!) But that flexibility means we have to code responsibly, or things can get messy and quick.
Today we're going to go into what makes CSS messy, but before we dive into the nitty-gritty, let me do some quick live-coding to show you, in a nutshell, how CSS normally works.
CSS rulesets (commonly just called 'rules') start with a selector. The selector determines what HTML elements the rules should apply to.
Following the selector, there are braces (a.k.a. curly brackets) that wrap the rules.
Inside the braces are the declarations. Declarations are the rules that are going to apply to the selected elements.
These declarations are made up of properties and values. The property is the quality that you want to change. The value is what you want to change the property to be.
After each declaration within the ruleset, you write a semicolon.
At the end of your ruleset is a closing brace.
(selector) | open brace | (property) | colon | (value) | semicolon | closing brace |
---|---|---|---|---|---|---|
h1 | { | color | : | blue | ; | } |
h1 {
color: blue;
font-size: 2rem;
}
Unless I tell you otherwise, use single classes as your selectors. I'll explain more later. What you're learning in this section will help you work with other people's code, but when you are writing your own code, use classes as your selectors.
Selector | Description | Example | Selected element |
---|---|---|---|
. | Selects elements with matching class attribute | .my-class {color: blue;} | <p class="my-class"></p> |
Element name | Selects a matching elements | p {color: blue;} | <p></p> |
# | Selects elements with matching id attribute | #myId {color: blue;} | <p id="myId"></p> |
* | Selects all elements | * {color: blue;} | <p></p> and literally every other element on your page. |
[attr=value] | Selects all elements with matching attribute | [href="#home"] {color: blue;} | <a href="#home"></a> |
(Actually, this guy's too big to fit on a slide - check it out
in the notes.)
Selector | Description | Example | Selected element |
---|---|---|---|
, | Adds multiple selectors to the same ruleset | .my-class, .my-other-class {color: blue;} | <p class="my-class"></p><h1 class="my-other-class"></h1> |
Combined selectors | Selects one element based on multiple selectors | div.my-class.my-other-class{color: blue;} | <div class="my-class my-other-class"></div> |
[space] | Selects descendant elements | div .my-class{color: blue;} | <div><p><span class="my-class"></span></p></div> |
> | Selects direct child elements | #myId > span {color: blue;} | <p id="myId"><span></span></p> |
~ | Selects all sibling elements | p ~ .my-class {color: blue;} | <p></p><div></div><span class="my-class"></span> |
+ | Selects immediate sibling | h1 + p {color: blue;} | <h1></h1><p></p> |
See the Pen CSS selectors demo by Simon Borer (@simonborer) on CodePen.
There are 3 places you can write CSS:
<head>
of your HTML document, wrapped in a <style>
element<span style="color:red;">My red text</span>
Most of the CSS you write will go in an external stylesheet - a document with a .css
file extension. This gets loaded into your document via a <link>
element in the <head>
of your HTML document, much the same way we load images via an <img>
element. But we'll worry about that next week.
This week, we can just work in the 'CSS' pane of Codepen.
It's fine to write CSS in a style tag in the head of your document. However, if you're hoping to share this CSS across multiple pages (and you're not templating the head across documents), or if you write more than a few dozen lines of CSS, this can get really messy and unmaintainable.
The least popular way to write CSS is in the style attribute. It's inefficient, messy and hard to maintain. People will make fun of you if you do this without a good reason. And they're right to do it.
The messy part of CSS is determining what rules take precendence based on priority.
The priority is set based on 3 factors: inheritance, specificity, & the 'Cascade'.
Some properties1 are inherited from parent elements.
<p style="color:green">
All this <strong>text</strong>
will <em>be green</em>
<p>
Inheritance is the lowest priority. Any selector beats inheritance.
Specificity gets very complicated Opens in a new window very quickly.
Here's the short version:
An id selector (#myId
) beats a class selector (.my-class
), and a class selector beats an element selector (h1
, for example).
Three levels of specificity (.three-levels .two-levels .one-level {}
) beats two levels of specificity (.two-levels .one-level {}
) which beats one level of specificity (.one-level {}
)2.
Combined selectors (h1#myId
) beat single selectors (#myId
).
All of this specificity gets beaten by an inline style3.
The only thing with a higher priority than an inline style is !important
.
.so-important {
color: purple !important;
}
The only thing that can override !important
is another !important
.
If you have more than one declaration targetting the same selector with the same level of specificity, the cascade determines precedence.
The 'Cascade' refers to prioritization based on the type and load-order of stylesheets (and CSS written in <style>
tags).
Default browser styles (also called 'User-agent styles') get loaded first.
Next, styles defined by the web page's author ('author styles') are loaded in the order they appear in the document.
I mean, you get it at this point, right? It can be really hard to figure out what takes precedence, and therefore how to make that thing blue, or whatever.
That's why I'm going to strongly, strongly encourage you to use classes with little to no layers of specificity for all your styles. It is very, very easy to make your code into a confusing mess, also known as specificity wars Opens in a new window.
If you want to have lots of classes that do very specific things (i.e. one for font-size, one for border), that's actually very popular these days Opens in a new window, and is certainly better than the alternative.
Personally, I like having a system for naming Opens in a new window my component classes. But that's just me.
Okay, now that you've been thoroughly intimidated by the 'Cascading' part, it's time to actually get stylish!
Here's a list from our friends at MDN Opens in a new window. Check it out in order to determine what values a property can have, and what elements it can be applied to.
Where a property can take a colour as a value, those values are usually written as hexadecimal values (the # symbol, followed by a six-digit alphanumeric code). You can also use named colors, and RGBA units if you want to take advantage of an opacity value.
Unit | Description |
---|---|
px | Number of pixels (1/96th of an inch). The only common way of hard-coding an absolute value in CSS. |
rem | Font size of the root element. |
em | Font size of the parent element. |
vw | 1% of the viewport's width. |
vh | 1% of the viewport's height. |
% | Well, this is context-dependent and gets messy. For example, if you set a width to a percentage, then it would be that percentage of the parent's width. |
(Yah, this guy's waaay too big to fit on a slide - check it out
in the notes.)
Property | Description |
---|---|
background | Defines the background color or image. |
border | Defines the width, style and colour of the element's border. |
border-radius | Defines the degree to which an element's corners are rounded. |
color | Changes the color of text. |
font-family | Changes the text's font. |
font-size | Changes the text's size. |
font-weight | Changes the text's weight. |
margin | Changes the space around the outside of an element. |
padding | Changes the padded space inside of an element. |
text-align | Changes the justification of text. |
text-decoration | Changes the decoration of text. |
height | Changes the height of an element. |
width | Changes the width of an element. |
Just like HTML, we have the option to spot-check things in Codepen, and do a proper validation through the W3C Opens in a new window.
font-size
, line-height
, and text-align
, including list properties like list-style
.+
, >
, ~
, and [space]
don't affect specificity.