Theming

Colors, fonts, sizes & SCSS

Emil Hvitfeldt

Objectives

  • Know what an SCSS file is and how to use it
  • Set fonts, colors, and sizes with sass variables
  • Know when to drop down to CSS rules

The 10 Minute Theme

You can get very far with theming using only

  • fonts
  • colors
  • sizes

How do we specify the theme?

Themes are written with CSS

Cascading Style Sheets (CSS) is a stylesheet language used to describe the presentation of a document written in HTML

CSS is written as a series of pairs; selectors and properties.

  • selectors specify what elements on a page we want to style.

  • properties specify what the elements should look like.

One rule

styles.css

.reveal .slide a {
  color: #219ea7;
  text-decoration: underline;
}

.reveal .slide a is the selector. It picks out the links on your slides.

color and text-decoration are the properties. They say what those links look like.

Why so many words on the left?

styles.css

a {
  text-decoration: underline;
}

This does nothing. Reveal already has its own rule for links, and it is more specific than yours.

.reveal .slide in front is how you out-specify it. Expect that prefix on most rules you write.

A language that compiles to CSS

While CSS is very powerful, it can also feel a little too wordy and less expressive. So we use the compiled langauge Sass.

  • You write Sass
  • A compiler turns it into plain CSS
  • The browser gets the CSS

Quarto runs that compiler for you on every render. There is no build step to set up.

Sass has two syntaxes

styles.sass

.reveal .slide
  ul
    line-height: 1.4

styles.scss

.reveal .slide {
  ul {
    line-height: 1.4;
  }
}

Same language, same features. SCSS is the one that looks like CSS, and the one everybody uses.

So, names

  • Sass the language and the compiler
  • SCSS the syntax you write it in, and the file extension
  • CSS what comes out the other end

Quarto expects .scss. That is the only one you need to think about.

Why SCSS?

One value, one place

styles.scss

$theme-blue: #219ea7;

.blue {
  color: $theme-blue; 
}

.reveal .slide a {
  color: $theme-blue;
  }

.reveal .progress {
  background: $theme-blue;
}

styles.css

.blue {
  color: #219ea7;
}

.reveal .slide a {
  color: #219ea7;
}

.reveal .progress {
  background: #219ea7;
}

The compiler writes the boring parts

styles.scss

$colors: (
  "red": #FA5F5C,
  "blue": #394D85,
  "yellow": #FFF7C7
);

@each $name, $color in $colors {
  .text-#{$name} {
    color: $color; 
  }
  .bg-#{$name} {
    background-color: $color;
  }
}

styles.css

.text-red {
  color: #FA5F5C;
}
.bg-red {
  background-color: #FA5F5C;
}

.text-blue {
  color: #394D85;
}
.bg-blue {
  background-color: #394D85;
}

.text-yellow {
  color: #FFF7C7;
}
.bg-yellow {
  background-color: #FFF7C7;
}

Write the awkward prefix once

Reveal’s own styles are specific, so your rules need .reveal .slide in front to win.

styles.scss

.reveal .slide {
  ul {
    line-height: 1.4;
  }

  a {
    text-decoration: underline;
    &:hover {
      text-decoration: none;
    }
  }
}

styles.css

.reveal .slide ul {
  line-height: 1.4;
}

.reveal .slide a {
  text-decoration: underline;
}

.reveal .slide a:hover {
  text-decoration: none;
}

Mistakes get caught

A typo in CSS is silent. The browser drops the line and moves on.

  • $primry-color fails to compile and tells you the line
  • Undefined mixins and functions do the same
  • You find out at render time, not from the back row

The theme outlives the talk

You are not styling one deck. You are building a look you keep.

  • Next talk starts by copying one file
  • Fix something once and every future deck has it fixed
  • Variables at the top are the knobs you actually turn

That is the whole bet: pay the setup cost once, spend the rest of your time on content.

Setup

One line of YAML, one file

my-deck.qmd

format:
  revealjs:
    theme: [default, styles.scss]

Combine a built-in theme with your sheet, or skip the built-in with theme: styles.scss.

The two layers

styles.scss

/*-- scss:defaults --*/

/*-- scss:rules --*/
  • defaults sass variables, read before Quarto builds the theme
  • rules plain CSS, applied after

Reach for a variable first. Write a rule only when no variable exists.

Fonts

Three variables

  • $presentation-heading-font slide titles
  • $font-family-sans-serif body text
  • $font-family-monospace inline code and code blocks

Where to find a good font?

Getting the font in

https://fonts.google.com

  1. Pick a font
  2. Select the styles you want
  3. “Get embed code”
  4. Copy the @import version, not the <link> version

Getting the font in

styles.scss

/*-- scss:defaults --*/
@import url('https://fonts.googleapis.com/css2?family=Josefin+Sans&family=Lato&family=Space+Mono&display=swap');

$presentation-heading-font: "Josefin Sans", sans-serif;
$font-family-sans-serif: "Lato", sans-serif;
$font-family-monospace: "Space Mono", monospace;

Tips for finding good fonts

Seeing what other people are doing

Looking up font pairings online

Lots of trial and error

Default fonts are fine too!

Colors

Five variables

  • $body-bg slide background
  • $body-color body text
  • $presentation-heading-color titles
  • $link-color links, progress bar, menu
  • $code-color inline code

A dark theme in five lines

styles.scss

/*-- scss:defaults --*/
// ...

$body-bg: #1C1C2B;
$body-color: #bac2de;
$presentation-heading-color: #cba6f7;
$link-color: #fab387;
$code-color: #89b4fa;

Contrast is not optional

Where to get your colors

  • Brand guidelines
  • Color palettes
  • Pulling from images
  • Pinterest

The code highlighter is separate

highlight-style controls code blocks, and it does not follow your $body-bg.

Sizes

Six variables, you need three

  • $presentation-font-size-root everything scales off this
  • $presentation-h1-font-size / $presentation-h2-font-size
  • $code-block-font-size

New sizes

styles.scss

/*-- scss:defaults --*/
// ...

$presentation-font-size-root: 40px;
$presentation-h1-font-size: 80px;
$presentation-h2-font-size: 60px;
$code-block-font-size: 0.9em;

When variables run out

quarto revealjs sass variables

you can go really far with the revealjs sass variables

however it doesn’t cover everything possible that we could want to do

so we will need to write our own SCSS rules

Demo: which class do I hit?

If you can see it on a slide, it has a selector. The browser will tell you what it is.

  1. Right-click the thing you want to style, pick “Inspect”
  2. Read the HTML pane: the element and the classes it carries
  3. Read the styles pane: the rules already hitting it, most specific first
  4. Edit a value right there to check you picked the right one
  5. Then write that selector into styles.scss

Nothing you change in the inspector is saved. It is a scratchpad, not an editor.

Write a rule

styles.scss

/*-- scss:rules --*/
.reveal .slide ul {
  line-height: 1.4;
}

Changing the line height of a unordered list

Your own classes

Define a class once, use it on any slide or span.

styles.scss

/*-- scss:rules --*/
.reveal .slide .highlight {
  background-color: #fab387;
  color: #1C1C2B;
  padding: 0 0.2em;
  border-radius: 4px;
}

The [important part]{.highlight} of the sentence.

Slide variants

Same deck, a handful of slide looks. Give a slide a class and style that class.

my-deck.qmd

## A normal slide

## A section break {.variant-one}

## An exercise {.variant-two}

The plain slide is your base style. A class is what you reach for when you want a different one.

One block per variant

styles.scss

/*-- scss:rules --*/
.variant-one {
  background-color: #1C1C2B;
  color: #d6d6d6;

  h1, h2 {
    color: #f3f3f3;
  }

  a {
    color: #00e0e0;
  }
}

Nesting keeps a variant in one readable block, so adding a second is copy, rename, change the colors.

What variants are good for

  • Section breaks, so the deck visibly changes gear
  • Functional slides: exercises, demos, results
  • Marking the parts of an argument: problem, solution

The classic is xaringan’s inverse: one dark slide among the white ones, used for a section break or a quote.

Your turn

Exercise

  1. Add styles.scss to the preview deck and wire up theme:
  2. Pick two Google Fonts, one for headings, one for body
  3. Set the 2 color variables, then check the contrast
  4. Bump $presentation-font-size-root until it feels too big, then leave it there

Thank you

Back to the workshop materials.