Salesforce, Python, SQL, & other ways to put your data where you need it

Need event music? 🎸

Live and recorded jazz, pop, and meditative music for your virtual conference / Zoom wedding / yoga class / private party with quality sound and a smooth technical experience

Let's build responsive, accessible navigation: 11ty baseline code

15 Dec 2020 🔖 jamstack web development
💬 EN

Table of Contents

TO DO: FIX, IN SOURCE AND HTML, THE FIX-THIS CANONICALS, BEFORE PUBLISHING

I am really struggling to build an attractive theme for a personal project with a responsive, accessible, attractive 2-level navbar.

So I’ll work in public. This particular article in this series doesn’t actually over making a navbar – it just lays out the scaffolding I’m putting into the 11ty static site generator (and building into a site / hosting with Netlify), into which I will actually start building some front-end styling.


Posts In This Series


Files

See the source code on GitHub

.
├── src
│   ├── _data
│   │   ├── flexipages.js
│   │   └── site.js
│   ├── _includes
│   │   ├── components
│   │   │   └── sections
│   │   │       ├── functions
│   │   │       │   └── section_component_picker.liquid
│   │   │       ├── section_feature.liquid
│   │   │       └── section_plain.liquid
│   │   ├── layouts
│   │   │   ├── base.liquid
│   │   │   ├── head_seo.liquid
│   │   │   ├── html_head.liquid
│   │   │   ├── nav.liquid
│   │   │   └── scripts_end.liquid
│   │   └── scss
│   │       └── main.scss
│   ├── css
│   │   └── style.11ty.js
│   ├── filters
│   │   ├── getSectionBodyClassText.js
│   │   ├── getSectionClassText.js
│   │   ├── getSectionStyle.js
│   │   ├── removeSlashes.js
│   │   └── validateSection.js
│   ├── static
│   │   └── js
│   │       └── main.js
│   └── loop_flexi_pages.liquid
├── .eleventy.js
├── .gitignore
├── netlify.toml
└── package.json

package.json, .gitignore, & netlify.toml

The 3 Node.js module dependencies I specify in my package.json, so that executing npm i (to install the dependencies) before executing npm run build (to run 11ty using Node.js), are:

  1. @11ty/eleventy
  2. sass
  3. slugify

The Netlify CLI and Node.js put a lot of junk I don’t need tracked in source control into this folder on my computer, so I have my standard basic-11ty-project .gitignore file.

To help the Netlify CLI do its job, I have a netlify.toml file.

flexipages.js & site.js

_data is a magic folder name in Eleventy. When I “export” nested-list-shaped data from flexipages.js, that data is available to every page-building template in my site configuration under a variable name of flexipages. Ditto for site.js and the variable name site.

In flexipages.js, I’ve defined a list of objects, each object representing one “web page” I’d like to generate. Each object always has a plaintext slug property (for helping build the URL its data flow into), a plaintext title property, and a sections property holding a list of objects, each of which in turn has a sectionType property and perhaps some other data.

I’ll loop over the flexipages data using the loop_flexi_pages.liquid 11ty template file.

In site.js, I’ve defined a single object with “site-wide” data such as title, homeTitle (sometimes I like the title in the browser bar when you visit a page to look different on the “home” page vs. every other page), description, and finally, mainNavLinks, which contains a list of objects representing URLs and labels for the 2-level navigation menu I’d like to have at the top of every page in my web site.

I’ll refer to site data from several 11ty template “include” files, including base.liquid, html_seo.liquid, and most importantly to this project (but not yet in this starter), nav.liquid.

Templates, includes & filters

I don’t know why, but I’m really fond of Shopify’s Liquid templating language. Familiarity, I suppose. That’s probably one reason I keep coming back to 11ty.

HTML generation

loop_flexi_pages.liquid is the heart of my static page generation.

In its front matter, I specify that it should “paginate” the globally available flexipages variable into single-unit chunks, giving a local loop variable name of documentData to each chunk, and saving the resulting output HTML file in a folder that uses the text found in the chunk’s slug property.

I don’t bother writing boilerplate <html> tags and such here – instead, I delegate that to the base.liquid template-include file I’ve saved elsewhere.

The codebase below my “front matter” in loop_flexi_pages.liquid gets injected into the {{ content }} placeholder of base.liquid at build time.

However, loop_flexi_pages.liquid doesn’t actually have a lot of HTML in it. Instead, it loops over the sections property of a given flexipage and delegates rendering its contents to a different template-include file, such as section_plain.liquid.

base.liquid is the template-include file that delegates rendering HTML for my masthead (the content at the top of every page) to yet another template-include file, nav.liquid.

There are some other supporting template-include files and “filter” files (JavaScript code that 11ty lets you use as shortcode functions in your template files, as long as you specify that you want to do so in your .eleventy.config file), all of which help me modularize my codebase for easier maintenance in the future, but none of which merit a deep dive in this post.

CSS generation

style.11ty.js is the heart of my CSS generation. Thanks to Adam K. Dean for the code.

It looks for a file called main.scss in /src/_includes/scss, parses it with Node.js’s sass module, and saves the resulting output CSS file to a file called style.css in a folder called css.

That way, https://example.com/css/style.css as referred to in the HTML rendered by html_head.liquid actually exists.

The scss folder doesn’t live in _includes to take advantage of 11ty’s “magic” treatment of files in the _includes folder – I just felt like _includes was a nice place to tuck it out of the way.

I’ll build out several more files and folders there, and actually put something more than a comment into main.scss, as I beautify my site.

Pass-through JavaScript

scripts_end.liquid included an HTML <script> tag looking for https://example.com/static/js/main.js.

Unlike /css/style.css, I don’t need 11ty to build the contents of this file for me. I’m happy to just write them in a file called main.js.

I told my .eleventy.config file to simply pass through this JavaScript file to the built site.

At the moment, main.js only contains a comment, but it’s good to know I have the scaffolding in place in case I need some client-side JavaScript (as is common with responsive, accessible drop-down navigation menus).

.eleventy.js

My .eleventy.js file is the main configuration file to control the way Eleventy runs. It’s a little cluttered since I’ve customized the configuration quite a bit, but every 11ty project should at least have a small one.


Output

Here’s a screenshot of the resulting web page, https://example.com/index.html (a.k.a. https://example.com):

Screenshot of resulting web page

And here’s the HTML that Eleventy built me and stored in the file /index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- Begin sync CSS -->
    <link rel="stylesheet" href="/css/style.css" />
    <!-- End sync CSS -->
    <!-- Begin pre-connect to certain 3rd-party domains like Cloudinary and Google Fonts -->
    <link rel="preconnect" href="https://res.cloudinary.com" crossorigin />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <!-- End pre-connect to certain 3rd-party domains like Cloudinary and Google Fonts -->
    <!-- Begin some asynchronous CSS includes -->
    <!-- End some asynchronous CSS includes -->
    <!-- Begin no-JS fallback for async CSS includes -->
    <noscript> </noscript>
    <!-- End no-JS fallback for async CSS includes -->
    <link
      rel="icon"
      href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%3E💄%3C/text%3E%3C/svg%3E"
      type="image/svg+xml"
    />
    <title>Beautiful site - no, really</title>

    <meta name="description" contents="Meta description" />
    <meta name="generator" content="Eleventy - 11ty - https://11ty.dev" />
    <link rel="canonical" href="" /><!-- TO DO:  FIX THIS -->

    <!-- OG cards -->
    <meta property="og:title" content="Beautiful site - no, really" />
    <meta property="og:description" content="Meta description" />
    <meta property="og:site_name" content="Beautiful site - no, really" />
    <meta property="og:locale" content="en_US" />
    <meta property="og:url" content="" /><!-- TO DO:  FIX THIS -->
    <!-- End OG cards -->
  </head>
  <body>
    <div id="site-wrap">
      <header id="masthead">Masthead goes here</header>
      <main id="content">
        <p>Beginning of a flexi-page (sections below)</p>

        <div class="flexi-sections">
          <section class="section section--gibberish">
            <div class="section__body">Hello world</div>
          </section>
        </div>
        <!-- End div.flexi-sections -->
        <p>End of a flexi-page (sections above)</p>
      </main>
      <!-- Current page: / -->
    </div>
    <script src="/static/js/main.js" defer></script>
  </body>
</html>
--- ---