One place for hosting & domains

      Create

      How To Create Layout Features with Position and Z-Index in CSS


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Elements of a website’s user interface (UI) can interact with and overlay on top of one another in many different ways, making CSS layout challenging to control. One way to set the placement of an element and how it overlays other elements is with a combination of the position property, z-index property, and the direction properties, which apply spacing values with top, right, bottom, and left. Experience with these CSS properties will enable you to create UI elements like dropdown navigation bars and figure captions efficiently and quickly.

      In this tutorial, you will create a page of content with a navigation element in the header. The navigation element will include a dropdown sub-navigation component, and the header itself will be affixed to top of the page as the page is scrolled. You will use the position property and its values relative, absolute, and fixed in conjunction with some direction properties to create this effect. Then you will work with the z-index property and to manage element layering with that property.

      Prerequisites

      Setting Up the Example Web Page and Initial position Value

      The default position value for all HTML elements is static, which constitutes the normal flow of content. The static state cannot be affected by a z-index property or any of the direction properties. To introduce more flexibility in your web page’s layout, you will later change the value of position away from this default. In this section, you will create the content for a page of a Lunar travel website and apply a change to the position of an element.

      To begin, open the index.html file in your text editor. Then, add the following HTML to the file:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <title>Destination: Moon</title>
          <link rel="preconnect" href="https://fonts.googleapis.com"> 
          <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 
          <link href="https://fonts.googleapis.com/css2?family=MuseoModerno:wght@400;700&display=swap" rel="stylesheet">
          <link href="styles.css" rel="stylesheet" />
        </head>
        <body>
        </body>
      </html>
      

      In this HTML snippet, the <meta> element defines the character set to use for the text. This will make most special characters, such as accent marks, render without special HTML codes. The <title> element provides the browser with the title of the page. The first three <link> elements load in the custom font Museo Moderno from Google Fonts, and the last loads the styles you will add to your styles.css file.

      Next, fill the page with content so that you have something to style. You will use sample content from Sagan Ipsum as filler copy to work with the styles. Return to index.html in your text editor and add the highlighted HTML from the following code block:

      index.html

      <html>
        <head>
          ...
        </head>
        <body>
          <main>
            <h2>Schedule Your Trip</h2>
            <p>Intelligent beings made in the interiors of collapsing stars vanquish the impossible gathered by gravity not a sunrise but a galaxyrise how far away. Extraordinary claims require extraordinary evidence dispassionate extraterrestrial observer a very small stage in a vast cosmic arena descended from astronomers as a patch of light the ash of stellar alchemy. Concept of the number one citizens of distant epochs with pretty stories for which there's little good evidence with pretty stories for which there's little good evidence the carbon in our apple pies a mote of dust suspended in a sunbeam.</p>
      
            <p>Drake Equation white dwarf something incredible is waiting to be known tesseract quasar dispassionate extraterrestrial observer? Concept of the number one intelligent beings kindling the energy hidden in matter extraordinary claims require extraordinary evidence network of wormholes Euclid? Vanquish the impossible citizens of distant epochs as a patch of light inconspicuous motes of rock and gas made in the interiors of collapsing stars a mote of dust suspended in a sunbeam.</p>
      
            <figure>
              <img src="https://www.digitalocean.com/community/tutorials/images/moon.jpg" alt="The Moon during twilight" />
              <figcaption>Photo by <a href="https://unsplash.com/@ilypnytskyi?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Igor Lypnytskyi</a> on <a href="https://unsplash.com/collections/9479529/moon?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></figcaption>
            </figure>
      
            <p>Citizens of distant epochs rings of Uranus intelligent beings birth take root and flourish across the centuries. Corpus callosum invent the universe as a patch of light the only home we've ever known a mote of dust suspended in a sunbeam made in the interiors of collapsing stars. Kindling the energy hidden in matter Orion's sword Sea of Tranquility great turbulent clouds with pretty stories for which there's little good evidence extraordinary claims require extraordinary evidence.</p>
      
            <p>A billion trillion take root and flourish extraplanetary gathered by gravity hearts of the stars consciousness. Dispassionate extraterrestrial observer Orion's sword are creatures of the cosmos realm of the galaxies descended from astronomers white dwarf. The carbon in our apple pies globular star cluster across the centuries a very small stage in a vast cosmic arena radio telescope vanquish the impossible. Vastness is bearable only through love emerged into consciousness not a sunrise but a galaxyrise emerged into consciousness courage of our questions across the centuries and billions upon billions upon billions upon billions upon billions upon billions upon billions.</p>
          </main>
        </body>
      </html>
      

      The code you just added to index.html creates a headline and four paragraphs that reside inside a <main> element. After the second paragraph, a <figure> element is created to load a moon.jpg image after the second paragraph. The <figure> element also includes a <figcaption> element that contains the citation information for the image. Save your changes to index.html.

      In order to display the image linked here, you will need the Moon Image. First, make an images directory in the same folder as your index.html file:

      Use your browser to download this file to your newly created images directory, or use the following curl command to download it via the command line:

      • curl -sL https://assets.digitalocean.com/articles/68084/moon.jpg -o images/moon.jpg

      Now that you have your image, open your web browser. Select the File menu item and then select the Open option to load your index.html file in the browser. The following image demonstrates how this HTML will render in the browser:

      Four paragraphs of text content in a black serif font on a white background with a photo of the moon between two of the paragraphs.

      Next, you will begin writing your styles. Return to your text editor and open styles.css. The following code block contains the beginning styles for the body, main, figure, img, and h2 elements:

      styles.css

      body {
        margin: 0;
        font: 1rem / 1.5 sans-serif;
      }
      
      main {
        margin: 6rem auto;
        width: 95%;
        max-width: 75ch;
        font-size: 1.125rem;
      }
      
      figure {
        margin: 2rem 0;
        padding: 0;
      }
      
      img {
        max-width: 100%;
        display: block;
      }
      
      h2 {
        font: 400 1.875rem/1.25 MuseoModerno, sans-serif;
        color: hsl(300, 40%, 30%);
      }
      

      Save your additions to styles.css, then return to your browser and refresh index.html. The styles will now be coming together, with a default font sizing set, the content area centered to the page, and the image taking an appropriate amount of space. The following image demonstrates how this is rendered in the browser:

      Four paragraphs of text content in a black sans-serif font on a white background with a photo of the moon between two of the paragraphs.

      Return to styles.css in your text editor. Then, add the highlighted CSS from the following code block to define the caption for your moon image:

      styles.css

      ...
      figcaption {
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      
      figcaption a {
        color: inherit;
      }
      

      The figcaption element selector sets up the image as an inline-block to make it only as wide as its content. The styles on the figcaption also set the background to a dark purple with white text, with a bit of padding all around. Then, the figcaption a descendant selector sets the color value to inherit so that it uses its parent’s white instead of the default blue.

      Save your addition to styles.css and refresh index.html in the browser. The <figcaption> element will now be displayed as a dark background block with some white text, as shown in the following image:

      Photo of the mooon with a black box below the photo containing white sans-serif text.

      Next, to begin working with the position property, return to styles.css in your text editor. In the figcaption element selector block, add the position property. Then use the relative value, as highlighted in the following code block:

      styles.css

      ...
      figcaption {
        position: relative;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      The relative value for the position property behaves the same as static when it comes to the flow of content. But unlike the static default value, the relative value can use the direction properties and z-index property in order to shift placement and layering options.

      Save this change to your styles.css and return to the browser to refresh index.html. You will find there is no difference made by the new property.

      In this section, you set up the initial HTML and CSS for the project. You also wrote your first position property, setting the ficaption value to relative. In the next section, you will apply the direction properties to move and position the figcaption content over the image.

      Placing Elements with the Direction Properties

      There are four direction properties: top, bottom, right, and left. These properties only work with elements that have a position set to any valid value other than static. Each of these four properties accept any unit-based positive or negative numerical value, including percentages. They also accept a keyword value of auto, which can be used to set these properties back to their default. In this step, you will use these properties to move the figcaption element in one of those four directions.

      To begin using a direction property, open styles.css in your text editor. Return to the figcaption element selector and add a top property after the position property and value:

      styles.css

      ...
      figcaption {
        position: relative;
        top: -4rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      In this code, you set the value for top to -4rem. A positive value on the top property will push the element down from the top, but a negative value pulls the element up away from the top edge of its initial placement.

      Save your changes to styles.css, then open index.html in your web browser. The caption information is now overlaying the photo and hugging the left side, as shown in the following image:

      Photo of the mooon with a black box overlaying the photo containing white sans-serif text.

      The element is along the left side because this browser’s default language is set to a left-to-right direction. If the browser or page were set up for a right-to-left language instead, the position element would be on the right side of the image.

      With the position value set to relative, the influence of the direction properties is limited. When setting a direction property value to 0, the expected and intended result is for the element to be along that side with no spacing, but the relative value will only do this if it does not interrupt the normal flow of the page’s content.

      To see this limitation in practice, remove the top property and add the following right and bottom properties:

      styles.css

      ...
      figcaption {
        position: relative;
        right: 0;
        bottom: 1rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      In this snippet, you set the right property to a value of 0. Next, you added a bottom property with a value of 1rem. Save your changes to styles.css and then refresh index.html in your browser. The expected behavior is for the <figcaption> element to be on the right side and hover a little bit above the bottom of the photo. However, as the following image displays, the element is still on the left side and is only barely over the photo:

      Photo of the mooon with a black box overlaying the bottom left corner of the photo containing white sans-serif text.

      In this section, you used three of the four direction properties to move the <figcaption> element over the photo. Direction properties can only be used on position elements that use a keyword value other than static, and the direction properties are limited in where all content can be aligned with the relative value. In the next section, you will change the position value from relative to absolute to fix this problem.

      Using the relative and absolute Relationship

      The position values of static and relative are similar in how they interact with the flow of content on the page. You can use direction properties with the relative value to move an element in the page layout, but this movement will not disrupt the flow of content. In this section, you will use the absolute value to more precisely control and adjust how an element works with the content of the page.

      Open styles.css in your text editor and go to the figcaption element selector. Then, change the position property value from relative to absolute, as highlighted in the following code block:

      styles.css

      ...
      figcaption {
        position: absolute;
        right: 0;
        bottom: 1rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      Save this property value to styles.css. Next, return to your browser to refresh index.html. The element is now on the right side of the whole page and is aligned with the bottom of the window when scrolled to the top of the page. The following image showcases how this code change is rendered in the browser:

      Text content in sans-serif with a black box with white text in the bottom right corner.

      When you change the position value from relative to absolute, the absolute element needs a context from which to apply the direction property values. The context is defined by an ancestor element that also has a position value. When the browser cannot find an ancestor with a position value, the context becomes the browser’s window. In this case, the bottom value places the element 1rem up from the bottom of the browser window. Then, the right property set the element along the right edge of the window.

      In order to have the <figcaption> overlay the photo and be aligned to the photo’s right-most edge, the context needs to change. You can do this by applying the position property to the closest ancestor element set to a value of relative. This will provide the <figcaption> element a starting point for the direction properties to move the element.

      To begin setting a new context for the <figcaption> element, return to styles.css in your text editor. Next, go to the figure element selector, since the <figure> element is the closest ancestor of <figcaption>. In the figure selector block, add a new position property set to the value relative, as highlighted in the following code block:

      styles.css

      ...
      figure {
        margin: 2rem 0;
        padding: 0;
        position: relative;
      }
      ...
      

      Save this update to styles.css then refresh index.html in the web browser. The <figcaption> moves from the bottom right corner of the page to the bottom right corner of the photo. The following image shows how change is rendered in the browser:

      Photo of the mooon with a black box overlaying the bottom right corner of the photo containing white sans-serif text.

      You have now controlled the placement of an absolute positioned element by using the combination of relative and absolute to fine-tune where the intended element is placed. In the next section, you will use what you learned to create a more advanced use of absolute positioning to make a hover-based dropdown navigation.

      Making a Dropdown Navigation Bar with absolute Positioning

      One of the more common uses for the position property is for a dropdown navigation system. In this section, you will write the HTML and then the styles to create a site header with a dropdown navigation that is activated by a hover interaction.

      To begin creating dropdown navigation, open index.html in your text editor. Then create a <header> element before the <main> element inside the <body> tags. Inside the <header> you will create an <h1> title for the page, followed by a <nav> tag filled with a nested unordered list:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          <header>
            <h1>Destination: <strong>Moon</strong></h1>
            <nav>
              <ul class="nav nav-main">
                <li class="item-top">
                  <a href="#" class="link link-top">Base Station</a>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Travel Packages</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">Apollo Sights</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Great Craters</a>
                    </li>
                    <li>
      <a href="#" class="link link-sub">Mare the Merrier</a>
                    </li>
                  </ul>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Accommodations</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">The Armstrong Hotel</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Lunar Lander Lodge</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Tranquility Inn</a>
                    </li>
                  </ul>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Plan Your Trip</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">Seasonal Rates</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Food and Restaurants</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Gravity Acclimation</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Recommended Duration</a>
                    </li>
                  </ul>
                </li>
              </ul>
            </nav>
          </header>
      
          <main>
            ...
          </main>
        </body>
      </html>
      

      The list elements contain the several classes you will use to create the styles. Save these additions to index.html.

      Next, open styles.css in your text editor. This site header and navigation will use a couple instances of CSS Flexbox to create a side-by-side layout for elements that are stacked vertically be default. Add the highlighted CSS from the following code block to the bottom of your styles.css file:

      styles.css

      ...
      header {
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      
      h1 {
        margin: 0;
        font-size: 1.75rem;
        font-weight: 400;
      }
      
      .nav {
        margin: 0;
        padding: 0;
        list-style: none;
      }
      
      .nav-main {
        display: flex;
        align-items: stretch;
      }
      
      .item-top {
        position: relative
      }
      

      This header selector defines the font values for all text in the <header> element. Then the display, align-items, and justify-content properties lay out the header with flex so the contents are in a horizontal row, centered to each other. They also make the <h1> and <nav> elements occupy opposing ends of the container. The h1 selector defines the site title styles, and the .nav class selector removes the default unordered list styles. The .nav-main class puts the top level navigation items in a flex row of their own. Lastly, the .item-top class selector defines the top-level <li> as a position: relative context.

      Continuing in your styles.css file, the next set of styles will hide the sub-navigation and create the link styles:

      styles.css

      ...
      .nav-sub {
        display: none;
      }
      
      .link {
        color: inherit;
        display: block;
        text-decoration: none;
      }
      
      .link-top {
        padding: 1.25rem 1.5rem;
      }
      
      .link-sub {
        padding: 0.75rem 1.5rem;
      }
      
      .item-top:hover .link-top,
      .item-top:focus .link-top,
      .item-top:focus-within .link-top {
        background-color: black;
      }
      
      .link-sub:hover,
      .link-sub:focus {
        background-color: hsl(210, 40%, 20%);
      }
      

      The first task for these rules is to hide the dropdown sub-navigation by using the display: none property and value, since the dropdown portion needs to be hidden until hovered. Then you create a series of class selectors to apply the styles for the visible top level links and the hidden nested links. The .link class removes the default <a> styles from all links in the navigation. Then, the .link-top and .link-sub rules define the padding needed for each link at the two levels.

      Next, the grouping combinator that includes .item-top:hover .link-top provides a background color to the link when its parent <li> element is hovered, has focus, or has a descendant that is focused. The states are on the <li> and not the <a> because the interactive state styling remains on the <a> after the cursor or focus moves to the sub-navigation items. Lastly, .link-sub:hover, .link-sub:focus defines the background-color change for the sub-navigation links when hovered or focused.

      Save your changes to styles.css, then open index.html in your browser. The page will now have a dark purple bar crossing the top of the page, with a large site title to the left and a sequence of navigation items to the right, as shown in the following image:

      Purple box containing a text in futuristic font above an area with a white background containing paragraphs of text in a black sans-serif font.

      Next, return to styles.css in your text editor to create the styles for the sub-navigation dropdown effect:

      styles.css

      ...
      .link-sub:hover,
      .link-sub:focus {
        background-color: hsl(210, 40%, 20%);
      }
      
      .item-top:hover .nav-sub,
      .item-top:focus .nav-sub,
      .item-top:focus-within .nav-sub {
        display: block;
        position: absolute;
      }
      

      In this code, you are appending a group combinator selector .item-top:hover .nav-sub to your CSS, along with state variations for :focus and :focus-with in place of :hover. When the <li> element is hovered or has focus, the nested <ul> should change the display property from none to block to make it visible. Additionally, the sub-navigation should not disappear when the focus moves from the top level, which is where :focus-within helps. Next, you added the position property set to absolute, as this will need to have more precise positioning control.

      Next, since the the desired outcome is to have the dropdown always start at the very bottom of the <header> element, a top property needs to be added set to 100%, in addition to a few more rules:

      styles.css

      ...
      
      .item-top:hover .nav-sub,
      .item-top:focus .nav-sub,
      .item-top:focus-within .nav-sub {
        display: block;
        position: absolute;
        top: 100%;
        right: 0;
        width: 15rem;
        background-color: black;
      }
      

      A top property set to 100% will move the absolute element so that its top starts at the relative ancestor’s bottom. Then, since the top-level navigation will be all the way to the right, a right property set to 0 is necessary so that the width of the dropdown does not disrupt the horizontal width of the page by going offscreen. Lastly, you added a width value set to 15rem and a background-color set to black.

      Save these changes to styles.css, then return to the browser and refresh index.html. You can now interact with the navigation by hovering your cursor over the top-level elements and then moving the cursor vertically to the sub-navigation items. Additionally, if you use the TAB key on your keyboard, you will be able to cycle through each top-level and sub-level navigation item. The following animation shows how this will appear while using keyboard navigation to focus on each navigation item:

      Animation showing a cursor hovering over text in a purple box causing a black box with white text to appear.

      Throughout this section, you created a dropdown sub-navigation system using the power of the absolute positioning value and two direction properties. You also used the value of 100% on the top property to push the sub-navigation to always show up below the header bar. In the next section, you will use the fixed value for the position property to make the header bar stay affixed to the top of the page while scrolling.

      Using the fixed Value

      Another common use for the position property is to implement the fixed value to make an element stay within the viewport, no matter the scroll position. This value is often used when creating features such as alert banners, which need to be visible no matter where the user is on the page. In this section, you will use the fixed value to keep the header in the viewport at all times. This will provide quicker access to the navigation throughout the user’s experience.

      To begin using the fixed positioning value, return to styles.css in your text editor. Go to the header element selector and at the top of the selector block, add the position property with the fixed value. Since the goal is for the header to be attached to the top of the page, add a top property set to 0, as highlighted in the following code block:

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      Save these additions to stlyes.css, then open index.html in your web browser. When the page finishes rendering, begin scrolling the page up and down to show how the header remains fixed to the top of the viewport window. The following animation demonstrates how this effect appears in the browser:

      Animation of a purple box remaining stationary as content of the page is scrolled.

      There is one issue with the header now that it has a position: fixed added: it no longer spans the full width of the window. One of the side-effects of using the fixed value is that it causes the element to condense down as far as it can. There are a couple of solutions, one of which is to add a width property set to 100%. But this can cause horizontal scrolling if the element has padding and the default box model.

      Instead, add a left and right property, each set to 0:

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      This will stretch out the header to be affixed to the left and right edges of the viewport.

      Save your changes to styles.css, then refresh index.html in the browser. The header once again will span edge-to-edge and remain visible while scrolling down the page. The dropdown navigation continues to work the same no matter how far down the page the user scrolls, as shown in the following animation:

      Animation of a purple box remaining stationary as content of the page is scrolled, with the cursor hovering white text in the purple box to reveal a black box with white text below.

      You’ve now effectively created a fixed header, allowing the navigation to be accessible regardless of where on the page the user is. You also learned that position: fixed requires additional styles in order to stretch to each side of the browser. In the last section, you will use the z-index property to control how position elements overlap each other.

      Layering Elements with z-index

      The hardest part of working with the position property is having multiple position elements on a page and managing the order in which they should overlap. By default, the browser layers these elements by putting each position element it encounters further down the HTML page in front of those that came before it. In this section, you will use the z-index property to change this default layering. You will also use custom CSS variables to track layer ordering.

      When scrolling the page down with the position: fixed header, there is a large issue that occurs once you scroll far enough down that the moon photo and the header meet. The expectation is that the fixed header will overlap the relative photo, but the actual behavior is the other way around:

      Animation of a stationary purple box with white text as the page is scrolled. The photo of the moon passes over top of the stationary purple box.

      The reason the photo is overlapping the header is due to the HTML order. Each position element of relative, absolute, or fixed value is set as a series of planes added one in front of each other along the z-axis. A fix to this issue could be achieved by moving the navigation to the bottom of the page, since the position: fixed would visually keep the header at the top. However, the z-index property exists to control this kind of situation. The z-index value is a whole number value that defines the order in the z-axis stack the element will occupy.

      All elements set to relative, absolute, and fixed are given a default z-index value of 0, but when there is more than one element along the same plane, the stack renders based on markup order. Using small z-index values such as z-index: 1 for the photo and z-index: 2 for the header will fix this issue, but since the z-index value must be a whole number, there would be no room for another element to fit in between the two. One method to add flexibility to your styling is to use a 100-based system to increment z-index values with the use of CSS variables.

      To create your own z-index system, open styles.css in your text editor. Then, at the top of the file create a :root selector, which is a pseudo-class selector that applies styles to the top-most HTML element on the page, most commonly the <html> element. Inside, create a series of CSS custom properties, also known as CSS variables:

      styles.css

      :root {
        --z-1: 100;
        --z-2: 200;
        --z-3: 300;
        --z-4: 400;
        --z-5: 500;
        --z-6: 600;
        --z-7: 700;
        --z-8: 800;
        --z-9: 900;
      }
      ...
      

      As shown in this code, custom properties start with two hyphen symbols, followed by a custom name. For the z-index system, you created a series that begins with z, followed by another hyphen, then a number ranging from 1 to 9. For the value of each custom property, you set it to the one hundred value of the corresponding range: 100 for 1, 200 for 2, and so on. The purpose for this 100-based incrementation is to allow a large amount of possible space between each level of the system. If there is ever a situation where a position element needs to go between --z-3 and --z-4, then there are 99 possible values to accomodate that situation.

      Next, go to the figure element selector in your styles.css file. To use the values of the custom properties, first add a z-index property. Then, to implement the system, add a var() as the value for the z-index property:

      styles.css

      ...
      figure {
        margin: 2rem 0;
        padding: 0;
        position: relative;
        z-index: var(--z-1);
      }
      ...
      

      var() in CSS declares that the value will be defined by a custom property. Inside the parentheses of the var(), you added the first property from the :root ruleset: --z-1. This defines the bottom layer of the z-index system and doesn’t change the visual ordering just yet.

      Next, go to the header selector and add a z-index property with the same format to load the --z-9 custom property value.

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: var(--z-9);
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      Since --z-9 is the highest number in the system, the <header> element will always be above all other position elements. One thing to note is that the z-index value is only placed on three of the five position elements. This is because a z-index is only needed per position context. The figure and the header are the topmost position elements on the page, with the body being the initial position context. The remaining nested position elements will travel with their ancestor to the appropriate z-axis plane.

      Save your changes to styles.css, then return to your browser to reload index.html. Now, as you scroll the page, the photo of the moon and its caption now travel under the header and its open sub-navigation items. The following animation demonstrates the new overlapping scenario:

      Animation of a stationary purple box with white text as the page is scrolled. A photo of the moon passes underneath of the stationary purple box.

      In this final section, you used custom properties to create a z-index system to better control which position elements overlap which. You also used a CSS variables method to accomodate projects with a large number of position elements by incrementing z-index values by 100.

      Conclusion

      The position property provides a number of ways to create unique layouts and interactions. In this tutorial, you put to practice the position property values of relative, absolute, and fixed. You worked through examples of how each interacts with the page and each other in different ways. You also used the direction properties top, right, bottom, and left to fine-tune the placement of position elements on the page and in relation to each other. Finally, you used the z-index property to control the layering order of the position elements. These tools will be valuable in your front-end development practice to solve many kinds of other solutions, including modals, alert banners, and sticky elements.

      If you would like to read more CSS tutorials, try out the other tutorials in the How To Style HTML with CSS series.



      Source link

      How to Create Anchor Links in WordPress (3 Methods)


      Google loves long-form content, and as a result, lengthy articles tend to rank higher on search results pages. The problem is that readers’ attention spans are getting shorter even as search algorithms favor longer content. This means that if you want visitors to find the information they need within your posts and pages, you have to make it easy for them.

      That’s where anchor links come in. With this feature, you can send readers toward specific sections (or subheadings) within the same page, often by using a table of contents. That way, visitors can find the exact answers they’re looking for instead of skimming through hundreds or thousands of words.

      In this article, we’ll show you how anchor links work and discuss the pros and cons of using them. Then we’ll go over some best practices for using anchor links in WordPress and show you three different ways to add them. Let’s get to work!

      What Anchor Links Are

      In theory, an anchor link is any link within a page that points to another section on that same page. In most cases, you’ll encounter anchor links within a table of contents at the start of a page or post.

      A table of contents.

      Above you’ll see an example taken from one of our own articles, which covers how to start a blog step by step. It’s a lengthy process, which makes a table of contents with anchor links an essential component.

      Other common examples of anchor links include buttons that return you to the top of the page when you reach the bottom. You can also use anchor links to help users navigate long landing pages. Whether there’s a page or post on your website that’s a bit too long for manual scrolling, anchor links can improve the user experience.

      WordPress + DreamHost

      Our automatic updates and strong security defenses take server management off your hands so you can focus on creating a great website.

      The Pros and Cons of Using Anchor Links in WordPress

      There are very few downsides when it comes to using anchor text and links in WordPress. Overall, WordPress anchor links make your content easier to navigate. They also offer a host of other benefits. For example:

      • Readers can get a quick overview of your content.
      • Search engines love lists that sum up a post or page.
      • Anchor links can help reduce your website’s bounce rate.

      Let’s dig a bit deeper into those last two advantages. It’s important to note that anchor links don’t improve your search engine rankings directly. However, they do provide more context for search engines.

      For example, here’s what you’ll see if you Google “how to start a blog with DreamHost”:

      A featured snippet in Google.

      This is a “rich snippet” that includes part of the post’s table of contents, which is made up of anchor links. The snippet doesn’t include the links themselves, but this list helps the blog post demonstrate how comprehensive it is to both search engine bots and human searchers.

      In some cases, Google may actually include anchor links below the meta description within Search Engine Results Pages (SERPs).

      A search result including anchor links.

      Additionally, providing anchor links in the form of a table of contents can help reduce your website’s bounce rate. That’s because you’re making life easier for users who might access the page, assume that it’s not what they’re looking for because they don’t see what they want right away, and leave. Instead, you can keep them around much longer by telling them exactly what they can find within a post or page and linking them to specific sections.

      Overall, tables of contents are the best way to leverage anchor links on your website. However, it only makes sense to use anchor links for long pages or blog posts. There’s no hard-and-fast rule, but anything above 1,500 words or so can likely benefit from a table of contents and its corresponding anchor links.

      Adding anchor links to shorter content isn’t necessarily bad, but it can be less useful. If readers can scroll through the entirety of a page in one or two wheel turns, there’s little benefit in spending the time to add anchor links.

      How to Create Anchor Links in WordPress (3 Methods)

      Creating anchor links is remarkably simple. You can do so either manually or with the help of plugins. Let’s start by talking about how to add anchor links in WordPress using the Classic Editor.

      1. Manually Create an Anchor Link Using the Classic Editor

      If you’re still using the Classic Editor, you’ll be happy to know that it makes short work of creating anchor links.

      As we mentioned earlier, anchor links point toward specific sections on the same page. However, you can’t simply add a link in WordPress that points toward a phrase or a title and hope the editor knows how to interpret it. That’s because all of the text you see in the editor is powered by HTML.

      To create an anchor link, you first need to set an anchor. To do that, select a subheading that you want to link to, and switch to the Text view of the editor.

      A subheading within the WordPress code editor.

      In our example, we’ve selected the following H2 subheading:

      <h2>How to Fry a Fry</h2>

      What we need to do is add an HTML ID. That ID will be the “anchor” we’re going to link to later on and will be in the form id= “unique-anchor-name”. Here’s what that code should look like:

      <h2 id=“fry-a-fry”>How to Fry a Fry</h2>

      Once the ID is in place, you can add the anchor link to your table of contents (or wherever else you want to place it). In our example, we want to add the link to the first entry in our table of contents.

      You can do this within the Text view or the Visual tab. If you’re using the visual editor, simply add the link as normal. However, instead of an URL, you’ll need to specify the HTML ID you’re linking to, preceded by a “#”.

      Adding an anchor link in WordPress.

      That’s it! When users click on that link within the table of contents, their browser will jump to the corresponding section.

      In the Text view, here’s what the HTML for a table of contents full of anchor links will look like:

      Multiple anchor links in a table of contents.

      Manually creating HTML anchor links may seem intimidating if you’re not used to working with code. However, as you can see, adding anchor tags is remarkably simple. Once you know how the process works, adding these links manually should only take seconds.

      However, keep in mind that you can only point toward anchors on the same page. If you try to create a link toward an anchor ID located on another page or post, it simply will not work.

      2. Manually Create an Anchor Link Using the Block Editor

      Creating anchor links using the Block Editor is even easier than with its Classic counterpart. That’s because the Block Editor enables you to add HTML anchors or IDs without the need to switch over to the code view.

      As with the previous method, the first thing you need to do is add an HTML ID or anchor to the text you want to link to. Select the text in the Block Editor, and open the Advanced tab within the Block section to the right.

      Adding an HTML anchor using the Block Editor.

      You’ll see a field called HTML anchor. All you need to do is add some unique anchor text within that field, and you’re ready to create the link. Select the text where the anchor link will go, and click on the option to add a link.

      Adding a link using the Block Editor.

      Instead of a regular URL, add a link that looks like this:

      #anchor-text-goes-here

      The link won’t work if you forget to add the “#” sign before the anchor text. Confirm the link, and that’s it.

      Adding an anchor link using the Block Editor.

      The Block Editor can automatically recognize if a link points to an internal or external page. If it recognizes the anchor text you enter, it will automatically display it as an internal link, as shown in the screenshot above.

      All that’s left to do now is repeat the process as many times as you need, depending on how many sections you want to link to. The Block Editor allows you to do this in a matter of minutes, which is perfect if you deal with long-form content on a regular basis.

      3. Create an Anchor Link in WordPress Using a Plugin

      It shouldn’t come as a surprise that there’s more than one plugin you can use to add anchor links in WordPress. So instead of recommending a single option, we’ll show you how to use two plugins, one geared toward simple anchor links and the other designed for building tables of contents.

      Let’s start with the former. The Advanced Editor Tools plugin is a tool that adds a broad range of features to both the Classic and Block Editors.

      Add Anchor Links Using the Advanced Editor Tools Plugin

      The Advanced Editor Tools plugin.

      However, it’s worth noting that this plugin only offers an option for adding anchor links in the Classic Editor.

      To see that feature in action, open the Classic Editor and select the text you want to add an HTML anchor to. You’ll see a new menu on top of the default Classic Editor formatting options. Select Insert and click on Anchor.

      Using the Advanced Editor Tools to add an anchor ID.

      That option will open a simple pop-up, which you can use to specify the anchor ID you want to use.

      Adding an HTML anchor using a plugin.

      Click OK, and you just added an HTML ID in the Classic Editor without needing to tinker with code.

      Now, go ahead and add a link that points toward this anchor anywhere you want within the same page.

      Adding an anchor link in WordPress.

      Advanced Editor Tools adds plenty of other features to the Classic Editor. You can read about them on the plugin’s official page. For now, let’s explore a different approach to adding anchor links in WordPress using plugins.

      Create a Table of Contents Using the Easy Table of Contents Plugin

      Creating a table of contents for each of your posts can be a lot of work. You have to add multiple anchor IDs manually and create links one by one. Moreover, you might also want to style the table of contents so it doesn’t look like a regular list within a post.

      One way to tackle that process more efficiently is by using a plugin such as Easy Table of Contents. This plugin can help you automatically generate tables of contents for posts and pages within your website.

      The Easy Table of Contents plugin.

      After you activate the plugin, you’ll need to configure its settings. Go to Settings > Table of Contents, and look for the section that says Enable Support at the top of the page. By default, the plugin will only work for pages, so you may want to enable its functionality for posts as well.

      Configuring the Easy Table of Contents plugin.

      Now scroll down to the Position and Show when settings, which are right next to each other. The Position setting will enable you to decide where to display your tables of contents. By default, they’ll show up on posts and pages right before the first heading.

      Configuring where to display your table of contents.

      The Show when setting lets you decide how many headings a post or page needs for the plugin to display a table of contents. By default, the plugin sets that number to four, but you can change it.

      Deciding how many subheadings a post should include to display a table of contents.

      Once you configure those settings, save your changes and go to the post or page where you want to add the table of contents. Open the Block Editor and scroll down to the bottom of the page. There you’ll see a new section called Table of Contents. There should be an option at the top to insert a table of contents for that post or page.

      Adding a table of contents to a post using the Easy Table of Contents plugin.

      The plugin will automatically set anchor IDs and generate a full table of contents leading to them. That table will include any subheadings within the post or page that you add it to unless you choose to exclude some of them.

      A table of contents generated using a plugin.

      Although the plugin includes an option for adding tables of contents automatically, we recommend that you decide which posts to use it for manually. This only takes a second, and you’ll avoid generating tables of content for posts or pages that don’t need them.

      Finally, if you’re not happy with the plugin’s default style for its tables of contents, you’re free to change it. The plugin’s Settings screen includes several options for modifying the appearance of its tables.

      You Dream It, We Code It

      Tap into 20+ years of coding expertise when you opt for our Web Development service. Just let us know what you want for your site — we take it from there.

      Check Out Our Other WordPress Tutorials

      If you want to learn more about improving the WordPress user experience and your site’s SEO, here are a few additional tutorials you may want to check out:

      Using anchor links is just one of the many tricks you can implement to improve your website’s search engine rankings. The more you understand SEO, the easier it will be to create search-engine-friendly content from the moment you publish it.

      Conclusion

      Anchor links are incredibly useful elements for helping users navigate complex pages and long-form content. You can use anchor links in tables of contents, navigation menus, footnotes, and more.

      Most importantly, WordPress makes it incredibly simple to add anchor links to your content. Let’s recap the three ways you can add anchor links in WordPress:

      1. Add anchor links manually using the Classic Editor.
      2. Add anchor links manually using the Block Editor.
      3. Create anchor links using plugins such as Advanced Editor Tools and Easy Table of Contents.

      Are you looking for a WordPress host that can help you serve long-form content to thousands of visitors without slowing down your site? DreamHost plans are designed to handle large amounts of traffic while keeping your website fast. Check out one of our WordPress hosting packages today!



      Source link

      How To Create a Custom Source Plugin in Gatsby


      The author selected the Internet Archive to receive a donation as part of the Write for DOnations program.

      Introduction

      In building a website or application, often one of the most difficult tasks is pulling data from multiple sources and collating it into a uniform output. A common way to solve this is to use entirely different build systems for different parts of a site, but this sometimes adds complexity while making uniformity harder to achieve. This is where Gatsby, a data-driven Static Site Generator (SSG), can provide a solution.

      One of the core objectives of Gatsby is to solve this problem for developers, and source plugins are the main way it does so. A source plugin is a bundle of code that handles bringing data into the Gatsby ecosystem from a given source. Sources can be from the local filesystem as with Markdown files, databases, published data feeds, or even completely dynamic remote data sources such as APIs.

      In this tutorial, you will build your own custom source plugin to bring new data into Gatsby from a real-world API. You will also format the data so that it can be accessed throughout Gatsby, and by the end of the tutorial, have a working project that builds static HTML from your new dynamic data source.

      Prerequisites

      Before starting, here are a few things you will need:

      • A local installation of Node.js for running Gatsby and building your site. The installation procedure varies by operating system, but DigitalOcean has guides for Ubuntu 20.04 and macOS, and you can always find the latest release on the official Node.js download page.
      • Some familiarity with JavaScript, for working in Gatsby. The JavaScript language is an expansive topic, but a good starting spot is our How To Code in JavaScript series.
      • Some familiarity with web APIs, Node.js, and JSON.
      • A new Gatsby project, scaffolded from gatsby-starter-default. For satisfying this requirement and building a new Gatsby project from scratch, you can refer to Step 1 of the How To Set Up Your First Gatsby Website tutorial.
      • Some familiarity with React and JSX, as well as HTML elements, if you want to customize the user interface (UI) of your posts beyond what is covered in this tutorial.

      This tutorial was tested on Node.js v14.16.1, npm v6.14.12, Gatsby v3.13.0, and node-fetch v2.6.2.

      Step 1 — Scaffolding Files and Installing Dependencies

      When building something, the first step is always to get your tools and parts in order. In this step, you will put the initial building blocks of your source plugin in place by creating the necessary file structure and installing the dependencies your code will rely on.

      Since this will be a local plugin, create a directory within your Gatsby project to hold the source code of the plugin under a root-level plugins directory. You can do this by manually creating the folder in your file browser, or from the command line in the root of your project with the mkdir command:

      • mkdir -p plugins/my-custom-source-plugin

      Note: If you want to develop your plugin outside of your Gatsby project directory, you can do so, but it requires some extra steps to get Gatsby to pull the files into your site. For more on this, check out the official Gatsby documentation.

      Next, you need to create a package.json file to mark this directory as a Node.js package with its own dependencies. To create this file and pre-fill some required fields, use the following command:

      • cd plugins/my-custom-source-plugin
      • npm init -y

      This command navigates to your newly created plugin folder and then uses npm init to initialize a new package. The -y flag skips some questions that are irrelevant to this project and fills in the package.json file with the minimum required values.

      Now that package.json exists, you can add dependencies to your plugin that will make coding out functionality easier. Go ahead and install the only extra dependency you will be needing in this tutorial, node-fetch, by using the following command:

      • npm install node-fetch@^2

      Finally, create the gatsby-node.js file that will end up holding the main code of the source plugin:

      Note: If you are frequently building Gatsby plugins, you might find their plugin template helpful.

      Now that you have created the file structure to support your plugin and installed the initial dependencies, you will move on to giving instructions to Gatsby on how to find and load your plugin.

      Step 2 — Loading and Configuring the Plugin

      As is the case with any Gatsby plugin or theme, Gatsby has to be instructed on where and how to load the plugin from. To do this, you edit the main Gatsby config file gatsby-config.js , which resides in the root of your Gatsby project. Open the file in your editor of choice and add the following highlighted line:

      gatsby-config.js

      module.exports = {
      ...
        plugins: [
          `gatsby-plugin-react-helmet`,
          `gatsby-plugin-image`,
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `images`,
              path: `${__dirname}/src/images`,
            },
          },
          `my-custom-source-plugin`,
          `gatsby-transformer-sharp`,
      ...
      

      Because your plugin’s source code lives in the plugins directory, all that is required to get Gatsby to load it is to pass in the name of the sub-directory where it can be found within that folder. Your plugin also does not take any options at the moment, so there is no need to pass an options object to it in the Gatsby configuration block.

      Save gatsby-config.js and exit from the file.

      You have now configured Gatsby to load your custom source plugin, as well as told it exactly where to find the source code it should execute. In the next step, you will build out this source code to pull data into the Node.js runtime from your custom remote source.

      Step 3 — Pulling Raw Data Into Node.js

      In the previous step, you configured Gatsby to load and execute your custom source plugin’s code, but you still need to build out this code to accomplish the task of bringing new data into the Gatsby ecosystem. In this step, you will write the code that does this, fetching remote data via node-fetch and preparing it for use in future steps.

      Source plugins can pull data from almost anywhere, local or remote, but in this tutorial your source plugin will be specifically pulling titles and excerpts from the Computer Programming Books category in Wikipedia via their public API.

      Open your my-custom-source-plugin/gatsby-node.js file in your plugins directory and add the following code:

      plugins/my-custom-source-plugin/gatsby-node.js

      const fetch = require('node-fetch').default
      
      /**
       * Fetch a list of computer books from Wikipedia, with excerpts
       */
      async function getWikiProgrammingBooks() {
        const BASE_ENDPOINT = "https://en.wikipedia.org/w/api.php?action=query&format=json&utf8=1&redirects=1";
      
        // Get list of books
        const listEndpoint = new URL(BASE_ENDPOINT);
        listEndpoint.searchParams.append('list', 'categorymembers');
        listEndpoint.searchParams.append("cmtitle", "Category:Computer_programming_books");
        listEndpoint.searchParams.append("cmlimit", "10");
        const listResults = await (await fetch(listEndpoint.toString())).json();
      
      
        // Extract out the page IDs from the list
        const pageIds = listResults.query.categorymembers.map((listing) => listing.pageid);
      
        // Fetch details for page IDs
        const extractEndpoint = new URL(BASE_ENDPOINT);
        extractEndpoint.searchParams.append("pageids", pageIds.join("|"));
        extractEndpoint.searchParams.append("prop", "extracts|info");
        extractEndpoint.searchParams.append("exintro", "");
        extractEndpoint.searchParams.append("explaintext", "");
        extractEndpoint.searchParams.append("inprop", "url");
      
        const bookResult = await (await fetch(extractEndpoint.toString())).json();
      
        return Object.values(bookResult.query.pages);
      }
      

      In this code, you have created a reusable function that can be called to return a list of computer programming books, along with their page IDs (a unique ID within Wikipedia) and excerpts/extracts. In the first part of the function, you build up the right API URL to use to fetch the initial list of titles and IDs belonging to a specific category (Computer Programming Books). The URL constructor and interface is used to make modifying the query string more readable and manageable.

      You use the fetch method from node-fetch to make a GET request to the constructed URL, which returns a list of the book titles with their IDs. That response is then turned into an array of just the pageid values, subsequently used to query the Wikipedia API again, this time requesting extracts and meta info generated for the given page ID. The page IDs are joined by the pipe character (|), as the Wikipedia API uses this format to accept multiple IDs through a single string value.

      Finally, since the results for page excerpts come back as an object with each book listing nested under its own ID as a key, you use Object.values() to omit the page ID key and convert the results into an array before returning them.

      If you were to log the output of this function, it would look something like this:

      [
        {
          "pageid": 379671,
          "ns": 0,
          "title": "The C Programming Language",
          "extract": "The C Programming Language (sometimes termed K&R, after its authors' initials) is a computer programming book written by Brian Kernighan and Dennis Ritchie...",
          "fullurl": "https://en.wikipedia.org/wiki/The_C_Programming_Language",
          ...
        },
        ...
      ]
      

      Make sure to save your changes, but keep this file open as you will be adding more code to it in the next step.

      In this step you used node-fetch to retrieve remote source content and expose it within the gatsby-node.js file. In the next step, you will normalize the content as you use it to create new Gatsby nodes to use throughout the Gatsby project.

      Step 4 — Normalizing Data and Creating Nodes

      Fetching remote content and bringing it into gatsby-node.js in the previous step doesn’t mean that it is now accessible throughout Gatsby; in order to share data in a universal way, Gatsby uses the concept of nodes, which are shared across a unified GraphQL data layer. In this step, you will create these nodes, formatting your new content to match.

      Although you can now retrieve and access the results from Wikipedia by calling getWikiProgrammingBooks(), you still need to add the code to integrate this with Gatsby’s node system. In the same gatsby-node.js file from the previous step, add this new block of code to handle generating the nodes:

      plugins/my-custom-source-plugin/gatsby-node.js

      const fetch = require('node-fetch').default
      
      ...
      
      exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
        // Arbitrary node type constant
        const BOOK_TYPE = 'BookWikiPage';
      
        // Get books
        const bookResults = await getWikiProgrammingBooks();
      
        // Convert raw book results to nodes
        for (const book of bookResults) {
          actions.createNode({
            ...book,
            id: createNodeId(`${BOOK_TYPE}-${book.pageid}`),
            parent: null,
            children: [],
            internal: {
              type: BOOK_TYPE,
              contentDigest: createContentDigest(book)
            }
          })
        }
      };
      

      In this code block, you are iterating over each book returned by getWikiProgrammingBooks and creating a Gatsby node for it via the createNode method. Each property and value passed into createNode has importance, and is worth consideration:

      • ...book is used to spread the key-value pairs from your Wikipedia API object into the Gatsby node you are creating. This means that later on you can access node.title, as it will be copied from book.title.
      • id is a globally unique value within Gatsby. To make each book’s ID unique within your own plugin, you are combining the book type with the Wikipedia page ID to form an ID string. However, because you can’t be sure what IDs other plugins are using, you’ve used the best practice of passing your ID to createNodeId, which is a Gatsby helper function that ensures the ID is turned into something globally unique.
      • parent is a field that can be used to link your node to another via ID, marking this node as a child. Since each book is its own entity, unconnected to other nodes, you have left this as null, signifying it does not have a parent.
      • children is similar to parent as a way to link nodes, but takes an array of IDs. Since each book has no children, you have left the array empty.
      • internal is an object that groups together fields highly-specific to Gatsby’s internal node management system and other plugins. It can only contain official fields, which is why you did not spread the book object into it.
      • type is a globally unique string that describes the type of node you are creating, and will be used later when querying for nodes via GraphQL.
      • contentDigestis a hash string, which is built from the contents of the node and the Gatsby createContentDigest helper utility. This field helps Gatsby detect when a node has changed, as the hash string will change if any properties of the book object are modified.

      You have just added code that takes your source content and creates new Gatsby nodes with it, sharing them across the Gatsby environment. In the next step, you will verify that these nodes appear in the GraphQL data layer and can be queried.

      Step 5 — (Optional) Inspecting Node Output with the GraphQL API

      By now, you have pulled your source content into Gatsby and used it to create new nodes. As an alternative to manually debugging with breakpoints or log statements, in this step you will use the interactive GraphQL IDE to verify that these new nodes are being created and are able to be queried with the GraphQL API.

      Go ahead and start up your local development server by running this command from the root of your Gatsby project:

      Note: At the time of writing this tutorial, a problem with Gatsby’s dependency chain introduced an error that can return the message Error: Cannot find module 'gatsby-core-utils' when attempting to start the development server. If you encounter this error, run the following:

      • npm install gatsby-core-utils

      This will re-install the Gatsby core utilities and will resolve the dependency problem. For more information on this, check out the GitHub issue for this Gatsby error.

      In addition to launching a live version of your Gatsby site, the develop command also exposes a local GraphQL server and IDE. To verify that your code in gatsby-node.js is creating all the book nodes, you will use this GraphQL query to fetch the book titles, page IDs, and Gatsby IDs:

      {
        allBookWikiPage {
          edges {
            node {
              title
              pageid
              id
            }
          }
        }
      }
      

      To run this query, either open up the interactive GraphQL IDE at localhost:8000/___graphql and paste the query into the left side before executing, or query it via cURL:

      • curl --location --request POST 'http://localhost:8000/___graphql'
      • --header 'Content-Type: application/json'
      • --data-raw '{
      • "query": "{ allBookWikiPage { edges { node { title pageid id } } } }"
      • }'

      The response JSON will look something like this:

      {
        "data": {
          "allBookWikiPage": {
            "edges": [
              {
                "node": {
                  "title": "The C Programming Language",
                  "pageid": 379671,
                  "id": "818771ca-40aa-5cfd-b9e7-fddff093d5ec"
                }
              },
              ...
            ]
          }
        },
        "extensions": {}
      }
      

      Having verified that your new custom source nodes have been created and are accessible in the GraphQL data layer, the next step is to use them to create visible content for visitors of your site or application.

      Step 6 — (Optional) Creating Pages Based on Nodes

      So far, all of the previous steps have been focused on creating internal Gatsby nodes, including the last step of verifying their creation and ability to be retrieved. However, these nodes are only visible to code running in your Gatsby project, not to visitors of your site or application. In this step, you will add a React page template file and wire it up to your nodes so that your source plugin content turns into actual public-facing webpages.

      There are multiple ways to create pages based on Gatsby nodes, but for this tutorial you will be using the File System Route API, which creates pages based on a special filename syntax.

      First, create an empty file in src/pages with a filename of {BookWikiPage.title}.js. The curly braces tell Gatsby that the filename is using the File System Route API, and inside the braces, BookWikiPage.title tells Gatsby to create a page for each unique book title. Note that you are no longer working on files within the plugins directory, but are now working inside of the main Gatsby project.

      Next, add code to that file that will take the book node and display it as a webpage:

      src/pages/{BookWikiPage.title}.js

      import { graphql } from "gatsby";
      import * as React from "react";
      import Layout from "../components/layout";
      import Seo from "../components/seo";
      
      export default function BookPageTemplate({ data: { bookWikiPage } }) {
        const { title, extract, fullurl } = bookWikiPage;
        return (
          <Layout>
            <Seo title={title} />
            <h1>{title}</h1>
            <blockquote>{extract}</blockquote>
      
            <i>This article uses material from the Wikipedia article <a href={fullurl} target="_blank" rel="noreferrer">"{title}"</a>, which is released under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share-Alike License 3.0</a>.</i>
          </Layout>
        );
      }
      
      export const pageQuery = graphql`
        query ($id: String!) {
          bookWikiPage(id: { eq: $id }) {
            title
            extract
            fullurl
          }
        }
      `;
      

      At the end of your code is an exported variable called pageQuery, which uses the Gatsby GraphQL tag. Gatsby will evaluate the GraphQL query that follows it, passing the results to the BookPageTemplate function.

      The BookPageTemplate function, which is a React component, then takes the results of the GraphQL query and displays them as part of a web page by embedding the values into the JSX that it returns. The title of the book is used as the main heading and title of the page, the extract is displayed as a block quote, and a link to the full Wikipedia entry page is embedded at the bottom.

      You also mark the BookPageTemplate function as the default export by using export default before its declaration, as Gatsby expects to find the React component responsible for producing the final rendered page as the default export of each page template file.

      Having added the React template code to the file, save the changes and close it. Navigate to http://localhost:8000/the-c-programming-language/ to render a sample page:

      Screenshot showing a book listing page generated for

      Note: For a more manual approach to creating pages based on nodes, you can use the createPages API inside of gatsby-node.js.

      To display a listing of these new nodes and their associated pages, you will also create a dedicated listing page, which will display all the books in one location. Under src/pages, create a new file with the filename of books.js. Next, add the following code into it:

      src/pages/books.js

      import { graphql, Link } from "gatsby";
      import * as React from "react";
      import Layout from "../components/layout";
      import Seo from "../components/seo";
      
      export default function BookListingsPageTemplate({ data: { allBookWikiPage } }) {
        return (
          <Layout>
            <Seo title="Programming Books Listing" />
            <p>Here are some computer programming books that have their own Wikipedia entries:</p>
      
            {allBookWikiPage.edges.map((edge) => {
              const node = edge.node;
              return (
                <details key={node.title}>
                  <summary>{node.title}</summary>
      
                  <div className="details-body">
                    <p>{node.extract}</p>
                    <div className="links">
                      <Link href={node.gatsbyPath}>Internal Page</Link>
                      <a rel="noreferrer" href={node.fullurl}>Wikipedia Page</a>
                    </div>
                  </div>
                </details>
              )
            })}
          </Layout>
        );
      }
      
      export const pageQuery = graphql`
        query {
          allBookWikiPage {
            edges {
              node {
                title
                extract
                gatsbyPath(filePath: "/{BookWikiPage.title}")
                fullurl
              }
            }
          }
        }
      `;
      

      Similar to the {BookWikiPage.title}.js page template, this file also uses the GraphQL pageQuery tag to pull in data from the GraphQL layer and pass it to a React component. However, while the previous template rendered a single book based on ID, this template will render a listing of all the books, while linking to the individual book pages created previously.

      Each book listing uses a <details> element, which enables the listing to expand to show the full excerpt of the book and links or to collapse to show just the title. Following best practices, you also pass a unique value to key while iterating through the array, using the Gatsby Link component for internal links and a tags for external links.

      The gatsbyPath(filePath: "/{BookWikiPage.title}") string in the GraphQL query uses the special gatsbyPath() function to retrieve the public path that will be created based on the File System Route API filename that is passed in.

      Save and exit from this file.

      Note: When changing data sources for components, the hot re-loading feature will sometimes return an error like the following: error Cannot query field "gatsbyPath" on type "BookWikiPage" graphql/template-strings. To fix this error, restart the development server manually by ending the process and running npm run develop again.

      With all the books on one page, even with collapsible sections things have gotten a little crowded, so the final step is to add some styling to make it easier for visitors to read the listing. Create a new stylesheet file at src/styles/books.css. You can do this in your file browser or with the command line from the root of your Gatsby project:

      • mkdir -p ./src/styles
      • touch ./src/styles/books.css

      Next, add the following CSS into the file:

      src/styles/books.css

      details {
        border: 1px dotted black;
        margin: 6px;
        padding: 6px;
      }
      
      .details-body {
        background-color: #eedeff;
        margin: 4px 0px 2px 12px;
        padding: 4px;
        border-radius: 4px;
      }
      
      .links {
        display: flex;
        justify-content: space-evenly;
      }
      

      This CSS adds a border around each book listing, spacing and margins within the listing, and spacing between the internal and external book links. After adding the CSS into the file, save and close it before moving on.

      Finally, update the book listing page template to pull this CSS file in:

      src/pages/books.js

      import { graphql, Link } from "gatsby";
      import * as React from "react";
      import Layout from "../components/layout";
      import Seo from "../components/seo";
      import "../styles/books.css";
      

      Save and close this file with the newly added CSS import line.

      To see the results, run the develop command again to bring up the development server and preview the new pages:

      You can now access your book listing page at localhost:8000/books/.

      Screenshot showing the book listings page, using the template file in the tutorial. Each section can be expanded to show the excerpt and links or collapsed to show just the title.

      You have now not only built a Gatsby source plugin from scratch, but also used it to generate pages based on a React template.

      Conclusion

      By following the steps in this tutorial, you have now finished building a custom source plugin that brings outside content into your Gatsby project and used it to power new pages within your site.

      There is a lot of depth to source plugins. If you are interested in following best practices and learning more advanced source plugin concepts, here are some areas that might interest you:

      If you would like to read more about Gatsby, check out the rest of the How To Create Static Web Sites with Gatsby.js series.



      Source link