One place for hosting & domains

      Custom

      How To Load and Use Custom Fonts with CSS


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

      Introduction

      The visual identity of a website is largely dictated by two principles of design: color and typeface. In the last decade, there have been great strides in providing custom fonts to users with more preloaded fonts on devices, the ability to load custom fonts with the @font-face rule, and the use of font hosting services. Web browsers have also implemented support for variable fonts, which are single font files from which multiple fonts can be interpolated, providing a high-degree of tuning and font customization.

      In this tutorial, you will try out examples of loading fonts onto your website. You will use the font stack, a rank ordering of fonts based on availability, to use fonts that may be installed on the user’s device. Then, you will use a font-hosting service, Google Fonts, to find, select, and load custom fonts onto your page. Lastly, you will load a self-hosted font family using the @font-face rule, followed by a self-hosted variable font.

      Prerequisites

      • An understanding of CSS’s cascade and specificity features, which you can get by reading How To Apply CSS Styles to HTML with Cascade and Specificity.
      • Knowledge of type selectors, combinator selectors, and selector groups, which you can find in How To Select HTML Elements to Style with CSS.
      • An understanding of font stacks and font properties in CSS, which you can find in the tutorial How To Style Text Elements with Font, Size, and Color in CSS.
      • An empty HTML file saved on your local machine as index.html that you can access from your text editor and web browser of choice. To get started, check out our How To Set Up Your HTML Project tutorial, and follow How To Use and Understand HTML Elements for instructions on how to view your HTML in your browser. If you’re new to HTML, try out the whole How To Build a Website with HTML series.

      Setting Up the HTML and Creating the Initial Font Stack

      The concept of a font stack comes from early in the web, when there were only a few trustworthy fonts that one could installed on the majority of computers. It was often likely the font would not be available, so the font stack provided an order of fonts that the browser could attempt to find and load. In this section, you will learn the principles of a resilient font stack and what options are available for fonts on modern devices. But first, you will create example HTML to demonstrate the fonts.

      Begin by opening index.html in your text editor. Then, add the following HTML to the file:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <title>A Demo Font Family Page</title>
          <link href="https://www.digitalocean.com/community/tutorials/styles.css" rel="stylesheet" />
        </head>
        <body>
        </body>
      </html>
      

      Inside the <head> tag, the first <meta> tag defines the character set for the HTML file. The second <meta> tag defines how mobile devices should render the page. Next, the <title> tag gives the page its title. Finally, the <link> tag references the CSS file you will use later to create the styles for the page.

      Next, inside the <body> tag, add the content of the page. This content is known as filler content from Cupcake Ipsum and it provides text to appear like content without actually saying anything. The filler content is highlighted in the following code block. You will encounter this highlighting method throughout the tutorial as code is added and changed:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <title>A Demo Font Family Page</title>
          <link href="https://www.digitalocean.com/community/tutorials/styles.css" rel="stylesheet" />
        </head>
        <body>
          <main>
            <header>
              <div class="content-width">
                <h1>Sweet strawberry cheesecake</h1>
                <p><em>Sweet muffin bear claw</em> donut chupa chups liquorice tiramisu candy canes sweet.</p>
              </div>
            </header>
      
            <div class="content-width">
              <p>Chocolate shortbread caramels tootsie roll tiramisu sweet dessert apple pie fruitcake. <strong>Croissant icing chupa chups</strong> sweet roll cake tart fruitcake soufflé jujubes. Shortbread brownie tootsie roll ice cream pudding dessert marshmallow sesame snaps. Cake pie jujubes lemon drops sesame snaps soufflé cookie jujubes wafer. Caramels ice cream fruitcake pastry cheesecake chocolate tootsie roll cake marshmallow. Pie candy canes cupcake dragée bonbon fruitcake marzipan. Tootsie roll halvah bonbon cake muffin gummies. Bonbon cotton candy marzipan cake sesame snaps chupa chups donut dessert. Macaroon gummies macaroon biscuit chocolate carrot cake gummi bears.</p>
      
              <h2>Donut candy canes cotton candy</h2>
      
              <p><strong><em>Liquorice gingerbread tiramisu</em></strong> pie bonbon soufflé. Jujubes tootsie roll muffin gingerbread powder. Carrot cake halvah chocolate bar tart sugar plum sugar plum pastry. Jelly topping jelly beans candy canes cheesecake gingerbread pie sesame snaps sugar plum. Pie cheesecake pudding jelly brownie jelly beans halvah. Ice cream powder carrot cake bear claw cake cheesecake.</p>
      
              <p><em>Jelly-o jelly-o jelly</em> lollipop croissant. Carrot cake tart danish macaroon dragée gingerbread. Sugar plum cotton candy biscuit <strong>fruitcake powder liquorice</strong>. Shortbread candy pie tart pudding. Sesame snaps bear claw tart tiramisu donut chocolate cake. Cheesecake tiramisu chocolate cake dessert dessert candy candy canes apple pie marshmallow. Sweet croissant pudding toffee tootsie roll gummies tart pastry pie. Candy apple pie cake wafer tootsie roll tart icing halvah.</p>
      
              <h3>Gingerbread gummi bears</h3>
      
              <p><em>Tiramisu sweet pastry</em> danish topping ice cream caramels. Tiramisu candy liquorice jelly-o marzipan candy canes cupcake topping. Gummi bears jujubes carrot cake shortbread sesame snaps marshmallow danish pudding cotton candy. <strong>Cake jujubes biscuit</strong> topping marzipan sweet roll apple pie bonbon. Bear claw donut bear claw bonbon caramels halvah gummi bears. Gummi bears apple pie jelly-o donut sesame snaps icing marzipan.</p>
      
              <p><strong><em>Bonbon chupa chups</em></strong> donut dessert pudding. Sweet roll caramels dessert muffin croissant. Powder chocolate lollipop ice cream bonbon pie candy muffin cotton candy. Fruitcake topping chupa chups toffee jelly-o halvah. Candy soufflé toffee gummies fruitcake oat cake chocolate cake. Dessert cupcake cheesecake sweet roll bear claw. Marshmallow halvah bear claw biscuit dragée marzipan lemon drops jelly.</p>
            </div>
          </main>
        </body>
      </html>
      

      The filler content contains a number of elements that are used to provide different font styles. The <strong> tag will by default make its content bold, the <em> tag will italicize its content, and the heading tags will increase the font size and bold their content.

      Next, return to your text editor and create the styles.css file in the same folder as index.html. This is the file that you referenced in the <head> element of index.html. In the styles.css file, add the following code:

      styles.css

      body {
        margin: 0;
        background-color: hsl(0, 0%, 100%);
        color: hsl(0, 0%, 10%);
        line-height: 1.5;
      }
      
      .content-width {
        max-width: 70ch;
        width: calc(100% - 4rem);
        margin: 0 auto;
      }
      
      main {
        margin-bottom: 4rem;
      }
      
      header {
        margin-bottom: 4rem;
        padding: 2rem 0;
        background-color: hsl(280, 50%, 40%);
        border-bottom: 4px solid hsl(300, 50%, 50%);
        color: hsl(300, 50%, 90%);
      }
      
      header p {
        color: hsl(300, 50%, 85%);
      }
      
      h1, h2, h3 {
        margin: 0;
        line-height: 1.25;
      }
      
      h2, h3 {
        color: hsl(280, 50%, 40%)
      }
      

      These styles create the overall visual style of the page. The header has a purple background with the h1 and p inside being a light purple. The main and .content-width selectors create the layout of the page, and the body and heading selectors provide several typographic styles by setting the line-height, color, and margin values.

      Save your changes to styles.css, then open your web browser. Open index.html in the browser by dragging the file into the browser window, or using the browser’s Open File option. The browser will render the HTML and CSS code to produce a page like the following image:

      Large purple block with white text in a serif font inside. Below there are several paragraphs of serif text in a dark gray with purple bold serif headings.

      The text of the index.html file in your browser will be using the browser’s local default font. In most cases, this will be a serif font like Times New Roman. The most performant way to customize fonts is to use fonts already on the end user’s computer. Using local fonts relieves the browser of downloading and processing sizable files.

      Today, there are often several dozen local fonts to choose from; these are known as system fonts. Both Microsoft and Apple keep an updated list of the fonts that come with their systems.

      To begin using pre-installed system fonts, return to styles.css in your text editor. In the body selector, add a font-family property, and make its value a comma-separated list of fonts known as a font stack:

      styles.css

      body {
        margin: 0;
        background-color: hsl(0, 0%, 100%);
        color: hsl(0, 0%, 10%);
        line-height: 1.5;
        font-family: "PT Sans", Calibri, Tahoma, sans-serif;
      }
      ...
      

      The browser will sequentially attempt to load the local fonts in the font stack until it is successful. For this font stack, the first font to attempt is "PT Sans", which is in quotes because it is a multi-word font name. PT Sans is a font from ParaType that comes pre-installed on Apple operating systems and is also available for free from Google Fonts. The next font is Calibri, followed by another comma and Tahoma. Calibri is a font from Microsoft that comes installed on recent version of Windows, and Tahoma is another font from Microsoft that has been present on Apple operating systems for over a decade.

      The final font is the generic name-spaced value sans-serif. If none of the previous three fonts are available, then the browser will use the browser’s default sans-serif font, such as Helvetica or Arial.

      Save your changes to styles.css and then refresh index.html in your browser. Your operating system and installed fonts will determine which font is rendered and how it is rendered. The following image shows how PT Sans appears as the font when loaded in Firefox on macOS:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple bold sans-serif headings.

      A font family consists of all the weight and style variations of a given font. Families can include many additional weight and styles that change how thin, thick, and slanted a font will display.

      The font-style property determines the slant of the font. The value is most commonly italic; however, some fonts support the oblique value, which accepts an optional degree value to indicate the steepness of the slant.

      The font-weight property has two defined named values of normal and bold, but the most versatile and predictable manner to determine this value is to use a weight number. The weight number values are commonly defined in increments of 100 from 100 to 900, with 100 being a thin weight and 900 being a thick weight. If the browser cannot find a font corresponding to the specified weight, it will find the closest available size.

      To set some new base font styling for this page throughout the tutorial, return to styles.css in your text editor. Then create an element selector for each of the h1, h2, h3, and p elements. Inside each selector, add the highlighted CSS from the following code block to increase the font size and emphasize the headings:

      styles.css

      ...
      h2, h3 {
        color: hsl(280, 50%, 40%)
      }
      
      h1 {
        font-size: 3rem;
        font-weight: 100;
      }
      
      h2 {
        font-size: 2rem;
        font-weight: 200;
      }
      
      h3 {
        font-size: 1.75rem;
        font-style: italic;
        font-weight: 200;
      }
      
      p {
        font-size: 1.125rem;
      }
      

      The h1 here is set to a font-size of 3rem, which is equivalent to 48px, with a thin font-weight of 100. Then, the h2 is set to 2rem, equivalent to 32px, and a font-weight of 200. Next, the h3 is set to the same font-weight and a slightly smaller font-size as the h2, but gains an added font-style property set to italic. Lastly, the p element selector bumps up the standard font-size to 1.125rem, which is equal to 18px in this case. The adjustments to the overall styling of this text will remain the same as you change the font used in each section.

      Save the changes to styles.css, then return to your browser and refresh index.html. The overall text size has bumped up, with the heading styles gaining more distinction from one another. The following image shows how this will appear in the browser:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple thing sans-serif headings. The font sizing has increased overall.

      In this section, you used the font stack to load a series of possible fonts on the page in a ranked order. You also learned about the possible variations of a font family with the font-weight and font-style properties. In the next section, you will use a font from a font hosting service.

      Finding and Loading a Font File from a Hosted Service

      Hosted font services are a popular and effective way of finding and providing custom fonts to a websites. Services such as Google Fonts, Adobe Fonts (formerly Typekit), and Typography.com provide a large library of high-quality fonts that a client will temporarily download when viewing your page. This means that you no longer have to worry about which fonts are on the client’s system.

      Each font hosting service has its own process for loading fonts, and in many cases there is an associated cost. For this section, you will find and load fonts from Google’s service, as it hosts open-source and limited license fonts free of charge.

      To begin, open fonts.google.com. Search for the font named “Open Sans” using the search bar at the top of the page. The search results will list the matching term, which is a link taking you to the Google Fonts Open Sans page. On this page, there is a list of several font styles. Each one of these font weight and style combinations is a unique font file that the browser will download.

      Note: Each font-weight and font-style will need to be selected based on need, instead of selecting them all. More fonts selected means more fonts need to be downloaded, thus increasing the website load time. It is important to only load the font weights and styles that are used in your design.

      For this design, select Light 300, Light 300 italic, Regular 400, Regular 400 italic, Bold 700, and Bold 700 italic. The following image displays how this selection will look in Google Fonts:

      View of the Google Fonts interface with a listing of font weights and styles on the left. On the right is a listing of selected fonts weights and styles with code text below.

      Next, copy the <link> tags necessary to load the files from the Google Fonts service. To do that, select the <link> option instead of the @import option as the way to load the files in the Google Fonts interface. Copy the series of <link> tags presented. Then, return to index.html in your text editor. Go inside the <head> element and, after the <link> tag loading styles.css, paste the <link> tags from Google Fonts. The highlighted HTML in the following code block demonstrates where to add the copied code:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
          <link href="https://www.digitalocean.com/community/tutorials/styles.css" rel="stylesheet" />
          <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=Open+Sans:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap" rel="stylesheet">
        </head>
        <body>
          ...
        </body>
      </html>
      

      The first two <link> elements perform a task called a preconnect, which tells the browser to prioritize an external web connection. In turn, these two <link> elements prepare the browser to load the CSS file and font files from the third <link> as soon as possible.

      Now that the font is ready for the browser to load it on to the page, next you need to apply the font styling so the text is rendered with that font.

      Save your changes to index.html, then return to styles.css in your text editor. In your body selector, go to the font-family property. Prepend the value with the font name "Open Sans" in quotes before the "PT Sans" font, followed by a comma. The highlighted CSS in the following code block shows where the new font is placed in the font stack:

      styles.css

      body {
        margin: 0;
        background-color: hsl(0, 0%, 100%);
        color: hsl(0, 0%, 10%);
        line-height: 1.5;
        font-family: "Open Sans", "PT Sans", Calibri, Tahoma, sans-serif;
      }
      ...
      

      By adding Open Sans to the beginning of the font stack, the browser will fallback to the next available local font if the browser is unable to load the files from Google. It is important to always have a font stack of at least two, with the last font in the stack being sans-serif, serif, monospace, or another named value that most effectively resembles the intended font.

      Save your changes to styles.css and open index.html in the web browser. The text on the page will now render using the Open Sans font loaded from Google Fonts. The text with a font-weight set to 100 and 200 will instead use 300 since that is the closest available. The following image illustrates how this will appear in the browser:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple thin sans-serif headings.

      In this section, you loaded a font family from Google Fonts. You learned how each font weight and style is a different file loaded from the service, and that the number of loaded variations can impact site performance. In the next section, you will load the fonts by writing your own @font-face rule to populate self-hosted font files.

      Loading a Self-Hosted Font with @font-face

      Self-hosted fonts are font files that are stored on your server alongside the other web components, such as HTML and CSS files. A common reason to consider self-hosting your font files is when you want to use a font that is not provided by a hosting service. When self-hosting, there is more control over how the fonts relate to one another and what they are named, which you can set via the definitions of the @font-face rules. In this section, you will write your own @font-face rules and load a family of fonts onto your web page.

      For this section, you will need to download the example zip file containing open-source fonts. You can download this through your browser or use the following curl command:

      • curl -sL https://assets.digitalocean.com/articles/68060/fonts.zip -o fonts.zip

      Once you have downloaded the file, extract the fonts directory contained in the zip file and place it in the same directory as the index.html and styles.css file on your computer. On Linux, you can do this from the command line with the following unzip command:

      Next, open up index.html in your text editor. Since you will be loading a local font from the zip file, you can remove the Google Font code. In this section, you will be loading the font files from your existing styles.css file. Make sure the contents of your <head> element are set up like the following code block:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <title>A Demo Font Family Page</title>
          <link href="https://www.digitalocean.com/community/tutorials/styles.css" rel="stylesheet" />
        </head>
        <body>
          ...
        </body>
      </html>
      

      Save your edits to index.html, then open styles.css in your text editor.

      You can use the @font-face rule to load a custom font on a web page. The history of loading custom fonts has lead to a compound method to support the widest number of browsers. Unlike other at-rules, like @media or @supports, the @font-face rule has no additional arguments. Inside the rule block, only a set number of properties are accepted. The most important is font-family, which describes the name the browser will use to reference and load the appropriate font files. Then, the src property references the location of the font files. In order to support versions of Internet Explorer prior to version 9, two src properties are necessary, with the first only referencing the .eot font file format. The second src property will then be a comma separated list of font file formats. The browser version will select the appropriate format that it supports.

      To begin using the @font-face rule, open styles.css in your text editor. At the top of the file, before the body selector, create the following @font-face rule:

      styles.css

      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Regular.eot');
        src: url('fonts/fira/eot/FiraSans-Regular.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Regular.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Regular.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Regular.ttf') format('truetype');
      }
      
      body {
        ...
      }
      ...
      

      Inside this rule, you’ve added a font-family property with a value of "Fira Sans" in quotes. Since this code is defining an overall font-family, only one font name should be used. The comma separated list of font formats for src is two parted. The first is the url() that, like a background-image property, provides the path to the file format on the server. Then, the format() explains what type of file is being referenced, allowing the browser to select the supported format.

      The fira folder inside the fonts folder contains four folders with specific file formats of the Fira Sans font. EOT stands for Encapsulated OpenType, a format Microsoft developed for Internet Explorer to load custom fonts. TTF stands for TrueType Font, and is an older font format that wasn’t originally developed for the web. The WOFF and WOFF2 formats stand for Web Open Font Format, with the “2” signifying the second version of the format. The majority of modern browsers support TTF, WOFF, and WOFF2 equally. To create an @font-face rule that covers the most possible browser formats, you provided multiple sources for your font. The EOT is referenced in both src properties because version 9 and later of Internet Explorer use the comma-separated format instead.

      Now that you have the @font-face rule for Fira Sans created, go to the font-family property in the body selector. In the value for the font-family, replace "Open Sans" with "Fira Sans" to use the self-hosted font on your page. The highlighted portion of the following code block demonstrates this change:

      styles.css

      @font-face {
        ...
      }
      
      body {
        margin: 0;
        background-color: hsl(0, 0%, 100%);
        color: hsl(0, 0%, 10%);
        line-height: 1.5;
        font-family: "Fira Sans", "PT Sans", Calibri, Tahoma, sans-serif;
      }
      ...
      

      Even though the fonts are being loaded from the same place as the styles.css and index.html file, it is important to keep a font-stack of alternates. There are numerous unknown reasons a self-hosted font may not load, and if the browser runs into an issue, a sufficient backup helps to maintain a similar aesthetic for your site.

      Save your changes to styles.css and open index.html in a web browser. Notice that the bold and italics versions of the font do not look quite right. This is because in the @font-face rule only the regular font weight and style files were loaded and used. When the browser needs to apply a bold weight or italic style to a font, but lacks the appropriate font file, the browser creates the needed variation. This altered form of a font is known as a faux bold and faux italic. Faux bold is created by adding a stroke to the font, which often creates a wider spacing between characters that could interfere with your intended layout. Faux italic is created by slanting the font, which often does not use space as well as a true italic would.

      The following image shows how the faux bold, italic, and bold italic styles appear in the browser:

      Three lines of text, the first with a generated bold style, the second with a generated italic style, and the last with a generated bold italic style.

      In order to provide the browser with the appropriate variations of a font family, more details need to be provided in the @font-face rule, and you need to create more rules to load additional variation files.

      Return to styles.css in your text editor. In the @font-face rule, add a font-weight and a font-style property after the second src property:

      styles.css

      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Regular.eot');
        src: url('fonts/fira/eot/FiraSans-Regular.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Regular.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Regular.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Regular.ttf') format('truetype');
        font-weight: normal;
        font-style: normal;
      }
      ...
      

      Here you set the value for both properties to normal. For the font-weight, the normal value is equivalent to the 400 numerical weight value. These properties tell the browser to apply these font files for normal variations. Thus the FiraSans-Regular font file will be used when the text needs to be a normal weight and style.

      Next, to provide the variations needed to correct the faux bold and faux italic, add more @font-face rules to reference each font-weight and font-style combination:

      styles.css

      /* Fira Sans Regular */
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Regular.eot');
        src: url('fonts/fira/eot/FiraSans-Regular.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Regular.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Regular.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Regular.ttf') format('truetype');
        font-weight: normal;
        font-style: normal;
      }
      
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Italic.eot');
        src: url('fonts/fira/eot/FiraSans-Italic.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Italic.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Italic.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Italic.ttf') format('truetype');
        font-weight: normal;
        font-style: italic;
      }
      
      /* Fira Sans Bold */
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Bold.eot');
        src: url('fonts/fira/eot/FiraSans-Bold.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Bold.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Bold.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Bold.ttf') format('truetype');
        font-weight: bold;
        font-style: normal;
      }
      
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-BoldItalic.eot');
        src: url('fonts/fira/eot/FiraSans-BoldItalic.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-BoldItalic.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-BoldItalic.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-BoldItalic.ttf') format('truetype');
        font-weight: 700;
        font-style: italic;
      }
      ...
      

      As more variations are added, it is helpful to add comments to more easily identify the group of font weights. You therefore added a CSS comment above the first @font-face rule. Then, below the first rule, you created three more @font-face rules for the italic, bold, and bold italic variations of the font.

      Save these updates to your styles.css file, then refresh index.html in the browser. Your browser is now loading all the variations of the font family provided. The following image showcases the differences between the faux and true versions of bold, italic, and bold italic:

      A comparison of text with a list of browser generated bold, italic, and bold italic styles on the left and the true font styles on the right.

      The true bold is much thicker than the browser’s faux bold, and the text is closer together, accounting for the thicker font strokes. The true italic is more notable when comparing the lowercase a character in the word “Italic.” The font changes the style of the a character when italic. Additionally, the slant of the true italic is a lesser degree than the browser’s faux italic.

      Next, there are a few more font variations to load, since the heading elements use thinner weight versions of Fira Sans.

      Return to styles.css in your text editor and create four more @font-face rules above the regular version @font-face rule:

      styles.css

      /* Fira Sans Thin */
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Thin.eot');
        src: url('fonts/fira/eot/FiraSans-Thin.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Thin.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Thin.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Thin.ttf') format('truetype');
        font-weight: 100;
        font-style: normal;
      }
      
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-ThinItalic.eot');
        src: url('fonts/fira/eot/FiraSans-ThinItalic.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-ThinItalic.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-ThinItalic.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-ThinItalic.ttf') format('truetype');
        font-weight: 100;
        font-style: italic;
      }
      
      /* Fira Sans Light */
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-Light.eot');
        src: url('fonts/fira/eot/FiraSans-Light.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-Light.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-Light.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-Light.ttf') format('truetype');
        font-weight: 200;
        font-style: normal;
      }
      
      @font-face {
        font-family: "Fira Sans";
        src: url('fonts/fira/eot/FiraSans-LightItalic.eot');
        src: url('fonts/fira/eot/FiraSans-LightItalic.eot') format('embedded-opentype'),
             url('fonts/fira/woff2/FiraSans-LightItalic.woff2') format('woff2'),
             url('fonts/fira/woff/FiraSans-LightItalic.woff') format('woff'),
             url('fonts/fira/woff2/FiraSans-LightItalic.ttf') format('truetype');
        font-weight: 200;
        font-style: italic;
      }
      ...
      

      These new rules load the Thin and the Light variations of Fira Sans, mapped to the 100 and 200 font-weight values, respectively. Since there are not word values for these sizes, you changed the values for the regular and bold font-weight properties to their numerical values.

      Save these changes to styles.css, then return to your browser and refresh index.html. The heading elements are now using the thinner variants of Fira Sans, as shown in the following image:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple thin sans-serif headings.

      In this section, you loaded self-hosted font files with @font-face rules. You learned how faux bold and italic can impact the visual presentation of a font and how to link many font files together with a common font-family value. In the last section, you will use a variable font, which allows for many variations sourced from a single font file.

      Working with Variable Fonts

      Variable fonts are a relatively new addition to the options of web typography. Where in the previous section each font weight and style had to be loaded from an individual file, variable fonts contain information in a single file from which many variations can be calculated. Variable fonts can increase performance, as well as providing much more design possibilities than before. In this section, you will load a variable font using the @font-face rule and tweak the display of the font to find the right variation.

      To begin working with variable font, open styles.css in your text editor. First, remove all the @font-face rules from the previous section and replace them with the following new rule:

      styles.css

      @font-face {
        font-family: Raleway;
        src: url('fonts/raleway/Raleway.woff2') format('woff2');
        font-style: normal;
        font-weight: 300 800;
      }
      
      body {
      ...
      

      A variable font structurally looks the same as a standard @font-face rule. You first declare a font-family name, then supply a list of src values, although often with variable fonts only one format is necessary. The font-style property was set to normal for this font. A difference comes with the font-weight value. Instead of defining a single value, a range is written with the thinnest weight followed by the thickest weight. By defining this range, the browser can prepare for the possible variation calculations that will occur. Here you set the font-face rule for Raleway, with a font-weight range from 300 to 400.

      Next, you will need to establish Raleway in the font stack. Remove "Fira Sans" from the beginning of the font stack and replace it with Raleway. Since the name Raleway does not contain any spaces, it does not need to be in quotes:

      styles.css

      ...
      body {
        margin: 0;
        background-color: hsl(0, 0%, 100%);
        color: hsl(0, 0%, 10%);
        line-height: 1.5;
        font-family: Raleway, "PT Sans", Calibri, Tahoma, sans-serif;
      }
      ...
      

      Save your changes to styles.css and open index.html in your web browser. The browser produces true font weights instead of faux weights, but is not treating italics correctly due to a lack of defined italic style.

      To set up the italic version of the Raleway variable font, return to styles.css in your text editor. Below the first @font-face rule, create a new rule set:

      styles.css

      @font-face {
        font-family: Raleway;
        src: url('fonts/raleway/Raleway.woff2') format('woff2');
        font-weight: 300 800;
        font-style: normal;
      }
      
      @font-face {
        font-family: Raleway;
        src: url('fonts/raleway/Raleway-Italic.woff2') format('woff2');
        font-weight: 300 800;
        font-style: italic;
      }
      
      body {
        ...
      }
      ...
      

      The src has changed its font file name from Raleway.woff2 to Raleway-Italic.woff2, and the font-style value is now italic.

      Save your changes to styles.css and refresh the page in your browser. The browser is now rendering the italic version of the various weights of Raleway. The following image shows the updated version of the page with a full Raleway variable font set:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple thin sans-serif headings.

      The advantage of using variable fonts is that any whole numerical value defined in the font-weight range is available. While standard font weights increment by values of 100, variable fonts weights can increment by values as low as 1. This provides a method to fine-tune the visual design of the font in ways not possible before.

      To use the weight values from the range, return to styles.css in your text editor and make the following changes:

      styles.css

      ...
      h1 {
        font-size: 3rem;
        font-weight: 350;
      }
      
      h2 {
        font-size: 2rem;
        font-weight: 570;
      }
      
      h3 {
        font-size: 1.75rem;
        font-style: italic;
        font-weight: 450;
      }
      
      p {
        font-size: 1.125rem;
      }
      
      strong {
        font-weight: 600;
      }
      

      For the h1 selector, you changed the font-weight value to 350. Then, you set the h2 font-weight property to 570 and the h3 to 450. Lastly, you created a strong element select with a font-weight property set to 650.

      Be sure to save your changes to styles.css, then return to your browser and refresh index.html. The browser now renders various weights of the Raleway font throughout the page. The following image shows how this appears in the browser:

      Large purple block with white text in a sans-serif font inside. Below are several paragraphs of sans-serif text in a dark gray with purple bold sans-serif headings.

      In this final section, you loaded and used a variable font on your web page. Much more variation can come from one or two variable fonts than a dozen standard fonts. You also learned how to adjust a variable font to find the right variation for your design needs to a degree unlike before.

      Conclusion

      Fonts are a key component to the visual aesthetic of a design. They are highly sought after assets that help one website standout from another.

      Throughout this tutorial, you learned the main ways fonts can be used on a website. You used local fonts and a font stack to tell the browser which fonts to try loading. Then, you used a font hosting service to effectively load the font Open Sans from Google Fonts. Next, you set up your own series of @font-face rules and created your own family of self-hosted fonts. Lastly, you built on what you learned loading your own fonts to use variable font and try out the versatility and performance they provide. Remember that it is important to always have fallback fonts in the font stack regardless if the font is local, from a hosting service, or self-hosted, because the font may not load for unknown reasons.

      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

      Build and Deploy a Custom Droplet Image on DigitalOcean


      How to Join

      This Tech Talk is free and open to everyone. Register below to get a link to join the live stream or receive the video recording after it airs.

      Date Time RSVP
      November 10, 2021 11:00 a.m.–12:00 p.m. ET / 4:00–5:00 p.m. GMT

      About the Talk

      Have you ever wanted to preconfigure your Droplet — DigitalOcean’s scalable virtual machine — before you deploy it? Do you want to use an operating system not currently available on DigitalOcean? Packer is a tool that allows you to build your own custom cloud images and deploy them.

      In this Tech Talk, we’ll use Packer and Ansible to build our own custom cloud image and deploy it to DigitalOcean.

      What You’ll Learn

      • How to build a custom cloud image using Packer
      • How to configure a custom cloud image using Packer and Ansible
      • How to use Packer to deploy your custom cloud image to DigitalOcean

      This Talk is Designed For

      • Software developers
      • DevOps engineers/SREs
      • Anyone who wants to build your own custom image and deploy it to DigitalOcean

      Resources

      Packer documentation

      Ansible documentation

      Custom Images are Linux and Unix-like images you import to DigitalOcean. You can create Droplets based custom images, which lets you migrate and scale your workloads without spending time recreating your environment from scratch.



      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