Creating a Quarto website hero panel

R
Quarto
SCSS
Author

Kyle Grealis

Published

March 4, 2024

Let’s explore creating a hero panel in Quarto using some raw HTML code and SCSS styling tweaks.

What is a hero panel?

We’ve all seen them, but may not have known what to call them. They’re the image that sits usually at the top of a home page. They’re designed to immediately draw your eyes to purpose and main message of the site. Hero panels, also referred to as “hero sections” or “hero images”, have evolved from the newspaper printing concept of “above the fold”. When you see a newspaper, you’re immediately drawn to what the editors intended for you to see first: a bold headline and image. The hope is that it compels you to pick it up and read on.

In web design, the hero panel is situated “above the fold”, but instead, this format requires our content to be visible without scrolling. We’re going to create a hero panel in a Quarto HTML document. We’ll also use some simple HTML create the initial layout, and then write some SCSS to style our panel and place the text where we want.

If you’re interested in learning more about HTML and CSS, a resource that I used and still often reference is W3 Schools. They have free content consisting of bite-sized tutorials to quickly get your feet wet.

Let’s build!

This is the hero panel that we will be recreating. Now, I have to give the disclaimer that this is but one of a multitude of ways to achieve the same goal. For me, this was the easiest as it uses minimal HTML and CSS. I’m going to assume that you know what HTML elements and tags are. If you don’t, the short and sweet: elements are the Lego blocks used to build your site or document and tags are the instructions for the browser to know what the element is and where to put it. Tags are identified by their <> brackets surrounding things like <h1> or <img>.

One small package

Using the lorem package can quickly render content to help visualize your layout. Later, you can go back and add what will ultimately be final version. As you can see, it’s that Latin text that is composing the paragraphs below the hero panel. Let’s download it now:

install.packages('lorem')

Time for Quarto

You need to have Quarto installed. Download the latest version here if you need it. In RStudio, click File >> New File >> Quarto Document to create a new Quarto file. Select HTML, leave the document untitled, uncheck Editor: Use visual markdown editor, and lastly Create Empty Document.

Modify the YAML header

Let’s make a few changes in the YAML header. To reproduce our example image, let’s remove the title so that we can place the hero image directly at the top of the document. If you’re using this tutorial for adding hero panel to your Quarto website, leave the title as that area will be occupied by the navigation bar. Adding embed-resources: true creates a standalone HTML file that incorporates necessary images, stylesheets, and JavaScript without relying on external files. This can increase accessibility of the file. Finally, we’re going to create layout-styles.scss for styling and positioning HTML elements, so let’s add that here.

---
title: ""
format: 
  html:
    embed-resources: true
theme: layout-styles.scss
---

Adding raw HTML to Quarto

Again, for me, this was the simplest method to create a hero panel. Under the YAML, add in this HTML:

---
title: ""
format: 
  html:
    embed-resources: true
theme: layout-styles.scss
---

<!----- start hero panel -------->

```{=html}
<div class="hero-panel column-screen">
  <img class="banner" src="banner.jpg" alt="Banner Image">
  <div class="banner-text">
    <h1>Learning Quarto Layout Tricks</h1>
    <h3>This is the hero panel</h3>
  </div>
</div>
```

<!----- end hero panel ---------->

Breaking this down, a div element is a container that holds something. Adding one or more classes to a div helps to “find” this element when we add some styles to it. The div class="hero-panel column-screen" is our main container. Within that div, you can see our img and another div holding our text in the h1 and h3 elements. A cool trick that I learned was setting class="column-screen" in Quarto allows the div to occupy the entire viewport! That’s great because it helps make our styling that much easier.

Style it out

We just modified the YAML header by pointing to our stylesheet, layout-styles.scss. We’re going to use a SCSS file as opposed to CSS because it will give you a little more freedom later on in your project to write your styling to be more readable, if nothing else.

Create layout-styles.scss and let’s add some content. When we write the styles, we can format it in much the same way that we described the aspect of container: we can format the SCSS so that it gives the appearance that our styles are “contained” within other parts of the code. Here, let me show you what I mean:

// Set up the hero panel
.hero-panel {
  // This is required. Think of it like a family unit where they are "relative"s
  position: relative;
  
  img.banner {
    width: 100%;
    height: 350px;
  }
  
  .banner-text {
    position: absolute;
    left: 5%;
    bottom: 20%;
    color: white;
    font-weight: bold;
  }
}

Our main container for our hero panel’s content lives inside the container that we gave the class hero-panel when we wrote the raw HTML. Now if you look at the SCSS that we added, img.banner is written inside of the {} braces for .hero-panel. This is “nesting” where one element’s CSS code can be read by human eyes as existing within another element. In our case, you’ll notice that both img.banner and banner-text are nested inside of .hero-panel.

Two quick things: you can identify a class that was written in HTML within the SCSS (or CSS) code because they’ll start with a . like in .hero-panel. Also, img.banner is an image (img) with the class of banner… put it together and you have img.banner for the SCSS.

The most difficult concept for me to initially grasp was this idea of position: relative; versus position: absolute;. I bet there will be much more technical and better ways of explaining this talking about the document flow and whatnot, but our main container, .hero-panel has “child” elements inside that we’re using as well. To be less technical about it, what we’re concerned with is that its elements are “related” to it, so we’ll give .hero-panel the position: relative.

There are only a few children within our parent container: the image and some text. Referring back to the HTML that we wrote and armed with the understanding that using proper indentation can help visually group elements for readability, our text container was given the class banner-text. Adding the . for our SCSS now, we’re going to give .banner-text the position: absolute. Why? Changing its position to absolute can be thought of this way: a parent can pick up a child and absolutely put that child where they want. For us, we want parent (hero-panel) to move its child (banner-text) where it wants to put it…ugh, where we want to put it. Gosh, I hope that made sense.

We’re going to move all of the text inside banner-text starting from the left and moving to the middle 5%. I recommend using percentages as opposed to pixels (px) because this could help when your page is rendered on different size screens. I’m sure now you can guess that bottom: 20%; moves the position of the text elements up 20% from the bottom. You can also use right and top for positioning elements absolutely too, but we just don’t use them that way in our example.

The final part is that we want our text to have the color: white; and we want it to stand out a little more, so let’s make font-weight: bold;.

Is that it?!

You can complete the look by adding a H2 header (using two ## in Quarto) for “Words in Latin…”. Then add a r code block with lorem::ipsum(paragraphs = 3) to fill in the rest of the space.

Viola! That should do it. But be sure to look for other ways to add more styling to your text or image for the hero panel. You can add shadowing effects to the text, you can make the image appear a little darker, or you can even blur the background image if that fits the idea you have. There are endless possibilities and I’m constantly learning and improving.

To be honest, I hope that I reread this post in a few months and immediately want to rewrite this to be even clearer or explained better. For now, this is where I am and I hope I was able to share something with you.

Thank you for your time and check back soon!


Happy coding!

~Kyle