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 a
a
anywhere inside footer
ol.tasks > li
:checked + label
label
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>
h1
s that come before h2
s”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()
.