Topics for today
- DRY
- Selectors
- Inheritance
- The Cascade
- Bonus: Custom properties for cascading variables (if there’s time)
Every piece of knowledge must have a single, unambiguous, authoritative representation within a systemThe Pragmatic Programmer, Andy Hunt and Dave Thomas
def right_triangle_perimeter(a, b, c):
return a + b + c
# ... later on
p = right_triangle_perimeter(3, 4, 5)
from math import sqrt
def right_triangle_perimeter(a, b):
return a + b + sqrt(a**2 + b**2)
# ... later on
p = right_triangle_perimeter(3, 4)
.red-button {
background: hsl(0, 80%, 90%);
}
.primary-button {
background: hsl(0, 80%, 90%);
}
button {
border-radius: 5px;
padding: 5px 12px 6px;
font-size: 24px;
line-height: 24px;
}
button.large { font-size: 46px; }
button {
border-radius: .2em;
padding: .2em .5em .25em;
font-size: 100%;
line-height: 1;
}
button.large { font-size: 200%; }
.tab {
border-radius: .3em .3em 0 0;
padding: .1em .5em .1em .5em;
margin: 0 .1em 0 .1em;
}
.tab {
border-radius: .3em;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
padding: .1em .5em;
margin: 0 .1em;
}
Three strikes and you refactor
Duplication is far cheaper than the wrong abstractionSandy Metz
h1 {
font-size: 300%;
line-height: 1;
}
h1 headings.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
* {font-weight: normal} might seem like a reasonable default, but it means our strong elements also will start from the same non-bold baseline.a.docs matches an <a> element with the class docs.
Note that element selectors can only be first in the sequence (i.e. [title]element is invalid)
input[type="text"]
input AND [type="text"]
p.notice.tip[title]#tip42
.notice.tip[title]p#tip42
button:hover {
background: greenyellow;
}
:hover:active:focus:focus-within:checked:target:first-child:last-child:only-child:nth-child(odd)p:nth-last-of-type(4n + 8):*-child family of pseudo-classes.:first-child and :last-child match elements who are first and last among their siblings, respectively.:only-child is equivalent to :first-child:last-child:nth-child() is a generalization. It accepts an argument of the form An+B (e.g. 2n+1)
and matches elements whose position among their siblings matches the argument for some non-negative integer n.
A and B can be negative.
:nth-child(even) is equivalent to :nth-child(2n) and matches each 2nd, 4th, 6th etc child.:nth-child(odd) is equivalent to :nth-child(2n+1) and matches each 1st, 3rd, 5th etc child.:nth-child(3n+1) matches every 3rd child starting from the first.:nth-child(1) is equivalent to :first-child:nth-last-child() is exactly the same as :nth-child() but starts counting from the end.
:nth-last-child(1) is equivalent to :last-child:*-of-type family of pseudo-classes, with exactly the same syntax, that only counts elements of the same type.
You can experiment with it herefooter aa anywhere inside footer
ol.tasks > li:checked + labellabel directly after a or
label that contains a or
label directly after or
h1 ~ h2
<h1>…</h1>
<h2>…</h2>
<h1>…</h1>
<p>
<h2>…</h2>
<h1>…</h1>
<section>
<h2>…</h2>
</section>
<h2>…</h2>
<h1>…</h1>
h1s that come before h2s”How to perform set operations? (¬, ∪, ∩)
p.warning = p ∩ .warning
td, th = td ∪ th
a { text-decoration: none }
a:hover { text-decoration: underline }
:not()
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:not(:hover) {
text-decoration: none;
}
:is() pseudo-class
:is(h1, h2, h3, h4, h5, h6):is(section *, article *) {
border-bottom: .1em solid slategray;
}
li::marker {
color: red;
}
input::placeholder {
color: skyblue;
}
::selection {
background: rebeccapurple;
color: white;
}
::before emulates a text node inserted in the beginning of an element and ::after a text node inserted after every other child.content: "")
that are then styled with CSS to create various decorations ::before::before is invalid (though there are discussions about enabling it in the future).!important?
body {
background: yellow;
}
body {
background: pink !important;
}
button {
border: none;
}
button {
border: 2px outset #777;
}
button {
border: none;
}
button {
border: 2px outset #777 !important;
}
(Unless !important is involved)
li,
strong,
em,
mark
elements have the same font, font size, color as the entire list, but not the same background or padding. Why?strong element doesn't inherit it.inherit to inherit from a non-inherited property.initial.
background
font
border
text-decoration
display
color
padding
white-space
margin
text-shadow
box-shadow
box-sizing
outline
--*
Inherited Not inherited
#id selectors.classes, :pseudo-classes, [attributes]:not()) (= B)| Selector | Specificity |
|---|---|
style="background: red" |
(∞, ∞, ∞) |
:not(em, strong#foo) |
(1, 0, 1) |
:is(em, #foo) |
(1, 0, 0) |
style attribute have infinite specificity:not() does not contribute to specificity as a pseudo-class, but based on the specificity of its most specific argument:is() does not contribute to specificity as a pseudo-class, but based on the specificity of its matching argument.foo.foo.foo:not(#nonexistent)#foo to [id="foo"]:where()-- and behave like normal CSS properties.var() function and we can use that anywhere (including inside calc()), except inside url().