Themed slide sections
When I present, I really like to theme the individual sections of my slide deck visually ā both as a way to break things up and to help reinforce the structure of the talk.
When you make slides with Quarto and Reveal, you can organise slides into sections with level 1 headers and into individual slides with (unnested) level 2 headers:
demo.qmd
---
title: "My great slides"
format:
revealjs:
theme: [default, style.scss]
---
# First section {#section1}
## Slide 1A
Non officia proident ad adipisicing Lorem Lorem qui Lorem nulla.
Occaecat mollit excepteur velit.
## Slide 1B
Officia minim velit fugiat pariatur cillum duis.
# Second section {#section2}
## Slide 2A
Fugiat minim commodo magna esse enim non consequat laborum ipsum enim ullamco nostrud.
Also note here that Iāve put IDs on each of these slides and sections: #section1
, #slide1a
, etc. Quarto generates these IDs automatically from the title if you donāt add them, but itās good to be able to see them.
At the top weāve added a stylesheet to the default theme: style.scss
.
Stylesheets give us a lot of flexibility, but itās easy to get carried away with them. If Iām not careful, the front-end engineer in my heart will let me spend more time making my slides look pretty than the actual content.
Plus, if we overload the slides with markup, the source file starts to get difficult to edit and read.
What I really want is to just mark each section, then move on with my life.
So Iāve settled on a stylesheet that starts like this:
style.scss
/* grab a nice font from google fonts for the headers */
@import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz,wght@8..60,700&display=swap');
/*-- scss:defaults --*/
$presentation-heading-font: "Source Serif 4", serif;
The first part is pretty standard for a Quarto theme: pull in a font from Google Fonts and use it for the headings.
But then we start to mix it up. The idea is that in the defaults layer we have one variable that defines all of the essential elements ā names, colours, etc. ā for each theme. Thatās our $section-styles
variable.
Then, we use @each
to iterate over each theme, making a block of rules for it (instead of writing each one out manually).
The stylesheet ends up continuing like this:
style.scss
// (scss:defaults continued)
// name, color1, color2, body-color
$section-styles:
"aqua" "#00aadd" "#66dd00" "#16365a",
"sunset" "#c21500" "#ffc500" "#4b1625",
"carbon" "#222222" "#444444" "#222222",
"moss" "#134E5E" "#71B280" "#0b2c36",
"indigo" "#4776E6" "#8E54E9" "#152447";
/*-- scss:uses --*/
.reveal {
// this block will repeat for each of our section-styles above
@each $name, $color1, $color2, $body-color in $section-styles {
// anything in here will cover the whole section
// that uses this identifier
.stack:has(#section-#{$name}) {
section
, li {
pcolor: #{$body-color};
}
, h2, h3 {
h1background: linear-gradient(45deg, #{$color1}, #{$color2});
text;
-webkit-background-clip: background-clip: text;
color: transparent;
}
}
}
}
Instead of referring to a regular SCSS variable like $variable-name
, we refer to the ones weāre looping over with #{$variable-name}
.
Whatās that has()
rule?
When you create sections in your Quarto presentation with a first level header, Quarto puts the ID for it on the title slide of the section, not on the section itself. That makes targeting the entire section difficult.
The :has(X)
rule is essentially ātarget all things that have an X inside themā. When we use it above, weāre saying, ātarget all of the section
s with class stack
that also have an element with the ID #section-X
inside it, where X
is one of our theme identifiers.
Thatās a lot of new stuff if you havenāt used SCSS or advanced CSS before, but once you have this boilerplate down you can fill it with whatever themable rules you want.
The most basic case I use is to give each a theme a text colour that is quite dark but has some hue to it. like #4b1625 or #152447.
The h1, h2, h3
block is an example of a CSS classic (and darling of every tech startup): gradient text.
You apply the gradient to the background of the text and set the text itself to be transparent. Then you clip the background to only show through where text is. All done!
In practice, I just grab this stylesheet, change the values up the top, and then get straight into my presentation. I just add sections IDs to my section slides but otherwise focus on my content:
# Section 1 {#section-sunrise}
## First slide
Here's an **important point** [And some less important, longer stuff]{.small}
Sometimes Iāll add a class like .small
or .deemph
for a bit of extra visual hierarchy. You can also intensify the colour bolded text with a rule across all sections like: strong { filter: brightness(90%) contrast(150%); }
. (We could theme this too, but Iām lazy š
)
Et voila! Mix up your slides from section to section, and from presentation to presentation, without having to start an entire frontend engineering project.
Hereās the complete demo again (or see the Quarto doc and stylesheet):
How about slide backgrounds?
Okay, title slides with fancy backgrounds can also be a nice way to break the visual hierarchy up.
Unfortunately, theyāre a little trickier to abstract away in a themed stylesheet. Thatās because Reveal keeps slide backgrounds entirely separate from slide content.
This has a lot of upsides: it lets Reveal do cool things like its parallax background and iframe background effects, and it allows Reveal to keep slide content centered while backgrounds extend to the edge of the window, even at weird window sizes.
But the backgrounds donāt carry the IDs the way the content does. That makes it really hard to style slide backgrounds from external stylesheets at all.
The canonical way to do Reveal backgrounds is to add them as attributes to the slide (or, in Quartoās case, to the slide or section title):
# First section {#section1 background-color="aquamarine"}
## Slide 1A
# [Second section]{style="color: white;"} {#section2 background="linear-gradient(45deg, cyan, limegreen)"}
## Slide 2B
Then Reveal sets up the backgrounds separately. I donāt love this, but I donāt really have a better solution.
But, backgrounds aside, you have a lot of latitude to build a theme system that gives your slides character without having to slow down every time you give a talk!