Lecture 8 More Foundational Concepts of CSS

Topics for today

Inheritance

  • Notice how the p, em, mark elements have the same font family, font size, and color that we set on their ancestor, body
  • What happens if we add a border to the body? Does it get inherited too?

Some properties are inherited, and some aren’t. Why? It's a heuristic.

What kinds of properties inherit?

background font border text-decoration display color padding white-space margin text-shadow box-shadow box-sizing outline --*

Inherited Not inherited

Components of the Cascade

Where does inheritance fit in?

Inherited properties have lower precedence than *any* values directly applying to the element, regardless of origin, specificity, or order.

Q: Where does inheritance sit in the cascade?
A: The very bottom

inherit is an explicit value that makes any property inherit

Values & Units

width: 400px;

width: 50%;

width: 400px;

width: 400px;

<length>

Read more about lengths

<length> units

Absolute

Same measurement everywhere

Examples: px, cm, mm, in, pt

Relative

Dependent on another factor

  • Font-relative units scale with the text size
    Examples: em, ch, rem, ex
  • Viewport-relative units scale with the viewport
    Examples: vh, vw, vmin, vmax
  • Some useful units are:
    • em is relative the current font size
    • rem is relative to the current font size of the html element
    • ch represents the width of the "0" glyph in the current font. This is useful in monospaced fonts where every character has the same width.
    • vw is a percentage of the viewport width (100vw = viewport width)
    • vh is a percentage of the viewport height (100vh = viewport height)
  • Font-relative units are useful in making components that scale by changing one property (the font-size).
  • Viewport-relative units are useful in making layouts that scale nicely with the viewport size.

Font relative units


				button {
					background: yellowgreen;
					border: 1px solid olivedrab;
					padding: 15px;
					border-radius: 6px;
					font-size: px;
					line-height: 32px;
				}
			

				button {
					background: yellowgreen;
					border: 1px solid olivedrab;
					padding: .5em;
					border-radius: .2em;
					font-size: px;
					line-height: 1em;
				}
			
Why are font-relative units useful? Let’s look at an example. Put your caret on the font-size and press Shift + to increase the font size fast. Note that the rest of the styling (padding, line-height, border-radius etc) becomes disproportionately small. If we use font-relative units, we can make everything adapt! Our button is now nicely scalable by changing only one parameter. We can even set font-size itself to font-relative units, if we want it to adapt to the surrounding font size!

Viewport relative units


				h1 {
					font-weight: 300;
					font-size: 4em;
				}
			

				h1 {
					font-weight: 300;
					font-size: 12vw;
				}
			
  • Viewport scalable units allow us to scale text to the viewport size.
  • calc allows us to perform calculations with different units. The type returned depends on the units that participate in the calculation.
  • min, clamp and max allow us to create upper and lower bounds for our values, and can participate in calc() expressions too.
  • All these functions can of course be combined, e.g. min can be used inside calc and vice versa.
  • Note that unlike Python or most other programming languages, these calculations are re-evaluated every time anything changes (e.g. the viewport or font size)

width: 50%;

Percentages

Each property defines whether percentages are allowed and what they represent

margin-left: 10%;

margin-top: 10%;

border: .3em steelblue;

outline: auto;

margin: auto;

overflow: auto;

Lorem Ipsum dolor sit amet

CSS-wide keywords

Other datatypes

opacity: [num];

transform: rotate([angle]deg);

background-color: hsl([hue], 100%, 40%);

background: url(img/chocolate-mousse.png) center / cover, linear-gradient(teal [stop]%, gold);

background: conic-gradient(teal [stop]%, gold);

Percentages do not always resolve to lengths. E.g. in conic gradients, they resolve to angles, since color stops are placed along a *gradient circle*.

Shorthands & Longhands

Shorthands & Longhands

A shorthand is a CSS property that represents multiple other properties, its longhands, or constituent properties. Setting a shorthand is equvalent to setting all of its longhands.

border: .3em dotted steelblue;

Disambiguation Shorthands often accept their arguments in either order, but only iff *disambiguation* is possible.

border: dotted .3em steelblue;

border: steelblue .3em dotted;

Longhands can be shorthands too

Different shorthands can resolve to the same longhands

What happens if we set both the shorthand and some of its longhands?
What happens if we set the same properties in a different order? Do you understand why we got the result we did?

Often they evolve over time

CSS 1 CSS 2.1 CSS Backgrounds & Borders Level 3 CSS Backgrounds & Borders Level 4

Naming is not always consistent

What happens if we swap the order of these two declarations? Why??

⚠️

A shorthand always sets all of its longhands, whether values have been provided for them or not

Any value not explicitly provided is set to `initial`.

padding: .2em .5em .1em .5em;

Top
Right
Bottom
Left
🕐

background: url(foo.png) 50% 50% / 100% auto no-repeat gold;

Some shorthands have a mixed syntax: their longhands can be mostly specified in any order, but some values need to come after other values, for disambiguation. In this case, `background-size` can only follow `background-position` (separated from it with a slash)

background: gold no-repeat 50% 50% / 100% auto url(foo.png);

font: 120%/1.5 Helvetica Neue, sans-serif;

Some shorthands require at least some values to be specified to be valid. Here, [`font`](https://developer.mozilla.org/en-US/docs/Web/CSS/font) requires at least a value for `font-size` and `font-family`.

Shorthand usability


			background: url(cat.jpg)
			            0 10% / 100% 100%
			            no-repeat
			            content-box border-box
			            fixed;
		

			background-image: url(cat.jpg);
			background-position: 0 10%;
			background-size: 100% 100%;
			background-repeat: no-repeat;
			background-origin: content-box;
			background-clip: border-box;
			background-attachment: fixed;
		
Computer languages are also interfaces, they are just text-based interfaces. The same usability dimensions apply. When it comes to CSS shorthands and longhands, which of these is more learnable? Which of these is more efficient?

Don’t
Repeat
Yourself

DRY Principle

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system

The Pragmatic Programmer, Andy Hunt and Dave Thomas

A big part of writing good code is avoidingcodeknowledgeduplication


			def right_triangle_perimeter(a, b, c):
				return a + b + c

			# ... later on
			p = right_triangle_perimeter(3, 4, 5)
		
  • Here, you can see a contrived example of WET Python code. c is dependent on a and b, so providing it is superfluous.
  • Not only is this an example of poor efficiency (both to write and to read), but also poor safety, since we may inadvertently provide arguments that are inconsistent.

			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)
		

Keeping CSS DRY

Avoid presentational class names

Presentational class


				.red-button {
					background: hsl(0, 80%, 90%);
				}
			

Semantic class


				.primary-button {
					background: hsl(0, 80%, 90%);
				}
			

Keeping CSS DRY

Use font-relative units


				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%; }
			

Keeping CSS DRY

Use shorthands wisely

Hardcover
Paperback
Audiobook

				.tab {
					border-radius: .3em .3em 0 0;
					padding: .1em .5em .1em .5em;
					margin: 0 .1em 0 .1em;
				}
			
Hardcover
Paperback
Audiobook

				.tab {
					border-radius: .3em;
					border-bottom-left-radius: 0;
					border-bottom-right-radius: 0;
					padding: .1em .5em;
					margin: 0 .1em;
				}
			
Note that the DRY version has more code. Short code is not the goal, maintainability is.

Overgeneralization

Rule of three Three strikes and you refactor

Duplication is far cheaper than the wrong abstraction

Sandy Metz

Pseudo-elements

Pseudo-elements allow us to style parts of an element

- Similar to how certain pseudo-classes represent additional state information not directly present in the document tree, a pseudo-element represents an element not directly present in the document tree. They are used to create abstractions about the document tree beyond those provided by the markup. - [Specification on pseudo-elements](https://www.w3.org/TR/selectors/#pseudo-elements)

Examples

List markers


					li::marker {
						color: red;
					}
					­
				

Input placeholders


					input::placeholder {
						color: slategray;
					}
					­
				

Text selection


					::selection {
						background: rebeccapurple;
						color: white;
					}
				
Note that some pseudo-elements can be very limited in what properties they support. E.g. try applying `filter` on `::marker` or `::selection`.

Pseudo-elements also allow us to insert content

CSS Variables / Custom properties

  • CSS variables (aka Custom Properties) start with -- and behave like normal CSS properties.
  • We read their value via the var() function and we can use that anywhere (including inside calc()), except inside url().
  • They are dynamic, and can be set in the inline style or even via JavaScript!
  • They help reduce repetition, and thus make code more maintainable. They also help encapsulation: Other people can use your components and style them via the variables you have exposed, without having to know and override the internal structure of your CSS.
  • Notice the repetition here: We have to repeat the button color 3 times! And changing it requires repeating so much code. How can CSS variables help us reduce this repetition and create themes more easily?