Chapter 29 Make it fancier

Now it’s time to customize our book even further. We can do a little bit of HTML and CSS work to add-on some fancy features.

29.1 Before you begin

  • If this is your first time dipping your toe into styling with CSS, you might want to check out our CSS crash course.

  • To stay organized, we recommend creating a folder called assets/ in your project directory and moving the CSS file called style.css that came with your skeletal book into that folder.

  • If you just followed the previous suggestion, then you’ll also want to update your _output.yml file to show this change:

    bookdown::gitbook:
      css: assets/style.css
  • Also, if you don’t already have one, create an image/ folder in your project directory.

29.2 Anatomy of a fancy book

Here’s where we’re starting:

And here’s where we’re going:

29.3 Aesthetics and branding

As the old adage goes, you shouldn’t just a book by its CSS—but we all know it’s a little hard not to. Bring your learners in and have them stay a while with an interface that’s welcoming, easy to ready, easy to use, and easy on the eyes.

29.3.1 Align the toolbar line

This first aesthetic adjustment goes out to everyone who notices the little things.

You may have noticed that the horizontal line from the toolbar and the TOC do not match up perfectly. This CSS will fix that:

  1. Open style.css.

  2. Paste in the following, after any code that was already in here.

    
    /* The next two rules make the horizontal line go straight across in top navbar */
    
    .summary > li:first-child {
        height: 50px;
        padding-top: 10px;
        border-bottom: 1px solid rgba(0,0,0,.07);
    }
    
    .book .book-summary ul.summary li.divider {
        height: 0px;
    }
  3. Make sure each line within each of the curly braces {} ends with a semicolon ;.

  4. Save and Build your book to see how it looks.

Ahh, fixed. Now doesn’t that feel better?

Organize your CSS using comments like /* --insert-comment-- */ to create make-shift section dividers for your CSS, as we’ve done above.

29.3.2 Symmetrical code chunks

Another small thing you may have noticed is that the code chunks in bookdown don’t have equal spacing above and below the code. Let’s change that with the CSS below:

/*____Code Chunks____*/

.sourceCode pre {
  margin: 0 !important; /* makes space above and below symmetrical*/
}

.sourceCode {
  margin-bottom: 0.85em; /* adds same amount of margin as a <p> would */
}

29.3.3 Google fonts

To change the appearance of your text with a new font, you need to:

  • Pick a Google font
  • Add it to your CSS file
  • Style specific text using CSS selectors
  • Make sure your CSS file is linked to _output.yml (and if you’ve been following along and using the book skeleton, it already will be).

29.3.3.1 Select and import your Google font’s script

  1. Go to https://fonts.google.com/ and pick a font for your book’s main body text. We’ll choose Muli, but Lato and Source Sans Pro are other nice options.

  2. Select the font you want by clicking on the upper red + sign, and navigate to the small pop up window.

    Selecting a Google font

    Figure 29.1: Selecting a Google font

  3. Click on the CUSTOMIZE tab, and select the extra font weights and styles you want. Don’t check any that you don’t think you’ll use (because it slows down your site’s loading time ever-so-slightly when you add more). In addition to regular, we’re choosing one italic and one bold.

    Choosing additional font weights and styles

    Figure 29.2: Choosing additional font weights and styles

  4. Now click on EMBED and look under the @IMPORT tab. Copy the code within the <style> tags (you don’t need the style tags themselves). We will also need the second code chunk in a couple steps that says Specify in CSS, so keep this page open to come back to that.

    Getting the script to import your Google Font

    Figure 29.3: Getting the script to import your Google Font

We recommend going with sans-serif fonts (i.e. no little feet on the letters) for the main text because they’re easier to read at smaller sizes on screens compared to serif fonts. Don’t pick anything too narrow, too wide, or ornate.)

29.3.3.2 Import the font to your site

  1. Back in the RStudio IDE, open up your style.css file.

  2. On the very first line, paste in the Google Font import code for the Muli font. This makes the font available within your bookdown site.

    @import url('https://fonts.googleapis.com/css?family=Muli:400,400i,700&display=swap');

You might see others import Google fonts by embedding the script (with <script> tags) in an HTML file instead. This is perfectly legitimate. But if you’re just starting out, it’s easier to keep all the font stuff together in a CSS file, which is why we’re doing it this way.

29.3.3.3 Style specific text using CSS selectors

We have our fonts imported, but now we have to let site know which text gets what font. We want to apply the Muli font to our body’s text by using the font-family: property.

  1. Add the following style rules to style.css beneath the other CSS we’ve already added.

     /*------------- Body and header text---------------- */
    
    .book.font-family-1 {
      font-family: 'Muli', sans-serif;
     }
    • The .book.font-family-1 selects the book’s main text.
    • The CSS within the curly brackets {} comes the second code chunk that we got from Google Fonts (see Fig 29.3).
    • The sans-serif part is a backup–it tells the browser to use any old sans-serif font in case there’s a problem rendering Muli.

The perfect selector: By the way, a little insight in the the trial-and-error process of getting the right selectors: I first tried using body as the selector here, but it didn’t work. I would have never figured out that this selector would work by by using the tips we suggested in the CSS crash course to use the inspector and start hovering elements. So, .book.font-family-1 happens to be what identifies the main text of the book. No magic to this, folks. Just a little grit!

29.3.3.4 Confirm style.css is linked in _output.yml

If you’ve been following along using the book skeleton, then there’s nothing more you need to do to apply this font. But just for completeness, we’ll point out that if we were building our book from scratch without the skeleton, then in order for your hardwork in CSS to be work, we would need to tell bookdown that our CSS file exists by referencing style.css in _output.yml:

```yaml
bookdown::gitbook:
  css: assets/style.css
```

29.3.3.5 Build, assess, and style more

Build and preview your book. Do you like the font that you chose? Now you can go back and pick fonts for other elements of your book.

  1. Choose another Google Font for your book headers and title and repeat the steps above to add your header fonts to your CSS, using the selectors below to fonts to your headers, title, and subtitle (if you have one).

    • We chose Prata as our header font, and we added its import line of code right beneath where we imported Muli earlier:
      @import url('https://fonts.googleapis.com/css?family=Muli:400,400i,700&display=swap');
      @import url('https://fonts.googleapis.com/css?family=Prata&display=swap');
  2. Optionally, we also change the color: and font-size: for the title and headers.

    /*------------- Body and header text---------------- */
    
    .book.font-family-1 {
      font-family: 'Muli', sans-serif;
    }
    
    h1, h2, h3, h4 {
      font-family: 'Prata', serif;
      color: #2f5275;
    }
    
    .title {
      font-family: 'Prata', serif;
      font-size: 3em !important;
      color: #5699cc;
     }
    
    .subtitle {
      font-family: 'Prata', serif;
      color: #2c6793;
    }
    • The selector h1, h2, h3, h4 separated by commas means that the styles will be applied to an element on our site that has any of the these classes–in this case, all level 1 through level 4 headers.

Header fonts: Header fonts can have some more pizazz ✨, but stay away from the intense fonts like handwritings or very artsy looking things, unless you’re only applying it to the book title for dramatic effect.

Picking colors: You can add interest to text on your page without being distracting by choosing very dark flavors of your accent color as an alternative to choosing black. For example, when using a color picker, slide down to the darkest, almost-pure-black-but-not-quite version of your color of choice. Consider using this for your body text’s or headers’ color.

29.3.6 Add a hero image

A hero image is “web-speak” for the large banner image that usually stretches across the page of many websites. We can sort of accomplish this in bookdown with a combination of both HTML and CSS. The image will not go all the way across the page, but will stop at the TOC. Before you decide to implement this, you should first know that this image will appear at the top of every single book page. If you feel like that will visually wear you out, then either skip this step, or think carefully about choosing an image that doesn’t have too much going on.

You’ll need:

  • An image. This should be an image that will still look good when it appears large across the screen. Some good options here.
  • An HTML file
  • CSS to style the image
  • To edit _output.yml

Let’s get started:

29.3.6.1 Embed the image in an HTML file

  1. Create a new HTML file by going to File > New File > Text File.

  2. Paste these contents at the top of the file.

    <link href="style.css" rel="stylesheet">
    <div class="hero-image-container"> 
      <img class= "hero-image" src="../images/books.png">
    </div>
    • <link href="style.css" rel="stylesheet"> will allow any content we put in this HTML file to be styled by the CSS file we’ve been working on.
    • The <div class="hero-image-container"> </div> tags will serve as the "container" for our image. The reason we bother with putting our image in a "container" at all is because this can make it easier to position and size our image later on the page. We give it a class name“hero-image-container”` because that’s what we’ll use as a selector to style it in our CSS.
    • The tag itself is where we actually specify the image path.
  3. Replace the file path to the image (what comes within src= " ") with your own file path.

  4. Save this HTML file in your project directory, ideally inside of the assets/ folder. Name it hero-image.html. You can choose a different name.

29.3.6.2 Add the HTML file to _output.yml

Now we tell bookdown that this HTML exists and that we want its contents (our image) to be the first thing in the <body> tag of our site:

  1. Open up _output.yml.

  2. Add the includes: and before_body: options with a path to your hero-image.html file.

    bookdown::gitbook:
      includes:
        before_body: assets/hero-image.html
      css: style.css

29.3.6.3 Position and style the image with CSS

Finally, we add CSS to the styles.css file to style and position the image in the right spot. This might take a little bit of rendering and adjusting to get it just right.

  1. Open style.css

  2. Paste the three style rules below into your CSS.

    /* HERO IMAGE */
    
    .hero-image-container {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 390px;
      background-color: #133454;
    }
    
    .hero-image {
      width: 100%;
      height: 390px;
      object-fit: cover;
    }
    
    .page-inner {
      padding-top: 400px !important;
    }
  3. Change the background-color: to a color that that will match your image. Why does an image need a background color? This is important because it will give the container some “placeholder” content while your image loads or in case your image doesn’t render. (If your hero image has some transparency, then your background color will be visible).

  4. Note: The height: of .hero-image-container must be the same height that you choose for the .hero-image. The height you choose is up to you. It does not necessarily have the be the same height as your image file.

  5. Note: To disable the hero image (especially if you’re using the rstudio4edu template), you can add display: none; to each of the first two style rules as an additonal line, and then comment out the third style rule above below, using /* on it’s own line just above where the style rule begins and */ after its closing the curly brace }.

  6. Build your book, and see if you like your hero image choices!

A little more about what’s going on under the hood:

  • position: absolute: To make the image go all the way across the page (not including the table of contents), we have to make the container that the image sits in position: absolute and then spell out its position explicitly (with top, left, right, etc. all set to 0.) These positions are relative to the container that .hero-image-container itself is inside.

  • .page-inner: All of our book content is by default inside a container labelled .page-inner. We don’t want our book content to get stuck hiding behind the big image we just stuck to the top of our page. So, we need to move the book content down by at least the height of our image + some wiggle room of about 10px. That’s what adding so much padding-top: is doing here.

29.4 Usability

The next three additions are less about aesthetics and more about making your book easier to read and use. We’ll add:

  • Custom sidebar div tips: These are the “notes” boxes scattered throughout a book that point out tips or warnings or note. You can create differently styles div tips for different purposes.

  • Anchor links: These linked icons next to every section header make it easy for readers to link and share specific parts of your book. See this resource.

  • Copy to clipboard: This creates small clipboard icons within code chunks that let your users quickly copy and paste from book to script.

29.4.1 Custom div tips

  1. Open your style.css file.

  2. Paste the following two style rules into your CSS file:

    /* -----------Sidebar div tips------------- */
    /* from r-pkgs.org*/
    
      div.puzzle, div.fyi, div.demo, div.note {
        padding: 1em;
        margin: 1em 0;
        padding-left: 100px;
        background-size: 70px;
        background-repeat: no-repeat;
        background-position: 15px center;
        min-height: 120px;
        color: #1f5386;
        background-color: #bed3ec;
        border: solid 5px #dfedff;
      }
    
    div.puzzle {
      background-image: url("../images/Your-turn.png");
    }
    
    div.fyi {
     background-image: url("../images/fyi.png");
    }
    
    div.demo {
      background-image: url("../images/Live-code.png");
    }
    
    div.note {
      background-image: url("../images/lightbulb.png");
    }
  3. Format the color of the box by changing background-color: and change the color of the text of the div tips with color:.

  4. With this styling, all div tip sidebars will be the same except for the icons. Those are controlled with background-image:. You can swap the image paths out for ones of your own if you want to use different images.

  5. Use the div tips, in any of your .Rmds. For example, here’s what it looks like to use the div.puzzle one:

    :::puzzle
    You use a div tip by writing `:::` following by the name that you assigned to it in the CSS after the `div`.
    :::
    

    Which makes a div tip that looks like this:

You use a div tip by writing ::: followed by the name that you assigned to it in the CSS after the div.

29.4.2 Anchor links

The steps that follow are an abbreviated version of the tutorial that you can find here.

Here’s what we’re going to use to make anchor links:

  • A wee bit of javascript in a .js file (“but I know nothing about javascript!” you say?–don’t worry, you don’t need to. Copy/paste is all you need).
  • An HTML file
  • Some CSS style rules.
  • Linking our HTML file to _output.yml.

29.4.2.1 Add javascript to make anchor links for all section headers

  1. In RStudio, go to File > New File > Text File .

  2. Paste the javascript below into this new file.

    $(document).ready(function() {
    
      // Section anchors
      $('.section h1, .section h2, .section h3, .section h4, .section h5').each(function() {
        anchor = '#' + $(this).parent().attr('id');
        $(this).addClass("hasAnchor").prepend('<a href="' + anchor + '" class="anchor"></a>');
      });
    });
    • This code essentially says, “Wait until the page is loaded and ready, and when it is, find every section header and tack on a link to itself right before that header.” The other important thing the javascript file will do is to add a CSS class "hasAnchor" to each of the headers. This is part of what will allow to style our anchor links with CSS in a couple steps.
  3. Save the file as book.js. (You can give it another name, but the convention is usually to name it file after the project you’re using it for.) Save this file in your working directory or in the assets/ folder.

Phew–you’re done with the javascript code now!

29.4.2.2 Embed book.js into HTML file

We’ll make an HTML file that will refer to our javascript file.

  1. In RStudio, go to File > New File > Text File .

  2. Paste the line below into this new file.

    <script src="book.js"></script>
  3. Modify the path in quotes to point to your javascript file if yours is not in your working directory.

  4. Save this file as header.html in your project directory or in the assets/ folder. You can choose a different name if you’d like.

:::tip *No

tags needed*: If you have a little experience with javascript, then you may know that any javascript <script> tags usually need to be placed within <head> tags, too. We don’t need to use these here because this little line of code will be automatically injected within our bookdown’s existing <head> tags when we use includes: in_header: in a few steps. :::

29.4.2.4 Add anchor link elements to _output.yml

We created all the anchor link infrastructure, now we just need to tell bookdown about it by referencing it in our _output.yml.

  1. Open _output.yml, located in your project directory

  2. Reference your HTML file with the includes: in_header: option underneath bookdown::gitbook. Make sure CSS file is also referenced. This part of your _output.yml should look something like this:

    bookdown::gitbook:
      includes:
        in_header: assets/header.html
        before_body: assets/hero-image.html
      css: style.css
  3. Save and build your book to check that everything has worked!

29.4.3 Copy to clipboard

Here’s what we’re going to need to make copy to clipboard buttons:

  • A little javascript in a .js file (we can add on to the .js file we used to make the anchor links).
  • An HTML file –we can use the same one we created for the anchor links above.
  • One CSS style rule
  • Linking our HTML file to _output.yml (you already did this if you created the anchor links).
  1. Open book.js that you created for making section anchors. If you didn’t make section anchors, then go back and do 1) and 3) from this section.

  2. Paste the following javasript into into the book.js file, beneath the other javascript from your section anchors.

$(document).ready(function() {

  // Copy Button
  $chunks = $('pre.sourceCode > code.sourceCode');
  $chunks.each(function(i, val) {
    $(this).prepend("<button class=\"button copy\"><i class=\"fa fa-copy fa-2x\"></i></button>").click(function() {
      var $temp = $("<textarea>");
      $("body").append($temp);
      var content = $(this).clone().children("button").remove().end().text();
      $temp.val(content).select();
      document.execCommand("copy");
      $temp.remove();
    });
  });
  
});
  1. Open style.css.
  2. Add the following to style the appearance of the button:
.copy {
  width: inherit;
  background-color: #e2e2e2 ;
  border: none;
  border-radius: 2px;
  float: right;
  font-size: 60%;
  padding: 4px 4px 4px 4px;
}
  1. Build and preview your work!

29.5 Table of Contents

Now comes the time to style the TOC. It’s a huge part of the book’s appearance, so we can get a lot of bang for our buck if we’re intentional about our choices here. All of these changes will be made using CSS alone.

We will:

  • Change the TOC background color
  • Style the TOC links
  • Make the TOC hierarchy clearer by adding space and styling Part titles

29.5.1 Change TOC background color

  1. Open style.css.
  2. Paste in the CSS below. The selector for the Table of Contents is .book-summary.
  3. The border-right: none parameter removes the line that separates the TOC by default.
    • If you want to keep the little line, then either remove border-right: none; below, so that bookdown will keep the default line.
    • Alternatively, style the line differently by replacing none with a different thickness, color, and line-type (e.g. border-right: 5px #5699cc solid).
    /*------------ TOC --------------*/
    
    .book .book-summary {
      background: white;
      border-right: none;
    }

We chose white as the background color for the TOC because we think it helps “open up” the space. But feel free to experiment here.

29.5.3 Hierarchy styling

Lastly, we make it clearer which chapters belong to the same part by styling the Part titles a bit differently.

Give breathing room, darken, and make uppercase

  1. Copy and paste the CSS rule below.

    li.appendix span, li.part span { /* for TOC part names */
      margin-top: 1em;
      color: color: #1c3046 !important;
      opacity: 1 !important;
      text-transform: uppercase;
    }
    
  2. We added margin-top: 1em for some much needed space above each Part title.

  3. We choose a color: that is similar to the dark blue of the links, but even closer towards black on that spectrum without going all the way to black (#000000).

  4. By default, bookdown gives Part titles an opacity that makes them appear light-colored. We have to override this, by choosing an opacity of 1.

  5. We also make these Part title uppercase.

Unnumbered first chapters

If you’re using Parts for your book, then you might want to use the first (unnumbered) chapter of each part as an intro chapter to that Part. You can style this ununumbered chapter differently with the following CSS. We make it uppercase.

```style.css
/* grabs first .chapter immediately after .part...but only those ch without numbers */
.part + li[data-level=""] { 
 text-transform: uppercase;
}
```

Now time to build and preview your fancy book!