Tweaking the Page Structure

User Guide → Tweaking the Page Structure

Tweaking the Page Structure

MarkBind offers several ways to easily tweak the overall structure of a page, for example, using headers, footers, scripts, or stylesheets.

Frontmatter

You can use a frontmatter section to specify page properties such as the title and keywords of the page. To specify frontmatter for a page, insert a <frontmatter> tag in the following format at the beginning of the page.
You can use YAML-style frontmatter syntax --- as well.

Frontmatter YAML-style Frontmatter Syntax
<frontmatter>
  property1: value1
  property2: value2
</frontmatter>
---
  property1: value1
  property2: value2
---

Example Here, we set the page title attribute as Binary Search Tree.

Frontmatter YAML-style Frontmatter Syntax
<frontmatter>
  title: Binary Search Tree
</frontmatter>
---
  title: Binary Search Tree
---

Should you need more expressive formatting, or encounter any issues when formatting the frontmatter, note that the frontmatter follows the YAML spec.

If a page has multiple frontmatters, it will take the last frontmatter by default. You may make use of omitFrontmatter, which is an attribute of MarkBind's <include> feature to omit the frontmatters that are not needed.

Page properties:

  • title: The title of the page. Will be used as the <title> attribute of the HTML page generated.
  • Other properties such as keywords, layout, etc. will be explained in other places of this user guide.

Page properties that are defined in site.json for a particular page will override those defined in the frontmatter of the page. For example, if we declare a title within the frontmatter of the page (say index.md) like such:

<frontmatter>
  title: Hello World
</frontmatter>

But the title property in the corresponding site.json is set as such:

{
  "pages": [
    {
      "src": "index.md",
      "title": "Landing Page",
    }
  ],
}

Then, the title of index.md will be set as "Landing Page" instead of "Hello World".

In this manner, setting the property title in site.json will always override the title declared within the frontmatter of the page.

<frontmatter>
  title: Binary Search Tree
  pageNav: 2
</frontmatter>

Layouts

MarkBind layouts can be used to provide structure and content around pages easily.

To add a layout, first add any source file to the _markbind/layouts folder. Then, specify the layout the page will use using one of the following:

If no layout is specified, the page defaults to the default layout (default.md).

When using markbind init, a default layout is provided in the _markbind/layouts folder.

Next, edit the layout file to your liking, and add the {{ content }} variable where you want the page content to be rendered.

<head-bottom>
  <!-- Use head-top and head-bottom tags to insert content into the HTML <head> tag -->
  <link rel="stylesheet" href="{{baseUrl}}/css/main.css">
</head-bottom>

<!-- Create a sticky header using the sticky attribute in a <header> tag -->
<header sticky>
  <navbar type="dark">
    <a slot="brand" href="{{baseUrl}}/index.html" title="Home" class="navbar-brand">
      <img src="{{baseUrl}}/images/logo-darkbackground.svg" height="20">
    </a>
    <li>
      <a highlight-on="exact" href="{{baseUrl}}/index.html" class="nav-link">HOME</a>
    </li>
    <li tags="environment--ug environment--combined">
      <a highlight-on="sibling-or-child" href="{{baseUrl}}/userGuide/index.html" class="nav-link">USER GUIDE</a>
    </li>
    <li tags="environment--dg environment--combined">
      <a highlight-on="sibling-or-child" href="{{baseUrl}}/devGuide/index.html" class="nav-link">DEVELOPER GUIDE</a>
    </li>
    <li slot="right">
      <form class="navbar-form">
        <searchbar :data="searchData" placeholder="Search" :on-hit="searchCallback" menu-align-right></searchbar>
      </form>
    </li>
  </navbar>
</header>

<div id="flex-body">
  <nav id="site-nav">
    <div class="site-nav-top">
      <div class="fw-bold mb-2" style="font-size: 1.25rem;">User Guide</div>
    </div>
    <div class="nav-component slim-scroll">
      <site-nav>
* [**Getting Started**]({{baseUrl}}/userGuide/gettingStarted.html)
  * **Authoring Contents** :expanded:
  * [Overview]({{baseUrl}}/userGuide/authoringContents.html)
  * [Adding Pages]({{baseUrl}}/userGuide/addingPages.html)
  * [MarkBind Syntax Overview]({{baseUrl}}/userGuide/markBindSyntaxOverview.html)
  * [Formatting Contents]({{baseUrl}}/userGuide/formattingContents.html)
  * [Using Components]({{baseUrl}}/userGuide/usingComponents.html)
      </site-nav>
    </div>
  </nav>
  <div id="content-wrapper">
    <!-- Insert the page's content into the layout using the {{ content }} variable -->
    {{ content }}
  </div>
  <nav id="page-nav">
    <div class="nav-component slim-scroll">
      <!-- Insert a page navigation menu using the <page-nav /> component -->
      <page-nav />
    </div>
  </nav>
</div>

<footer>
  <div class="text-center">
    <small>[Generated by {{MarkBind}} on {{timestamp}}]</small><br>
    <small>This site is powered by <a href="https://www.netlify.com/">Netlify</a>.</small>
  </div>
</footer>

<!-- Insert content after the HTML <body> tag using the <script-bottom> tag -->
<script-bottom>
  <script>
    alert('Hi!')
  </script>
</script-bottom>

The rest of this section explains the other convenient features MarkBind provides in its layouts system, and references the above code snippet.


Inserting content into the <head>

You can insert code into the <head> section of the generated HTML page, for example, to add links to custom JavaScript or CSS files.

You may do so by inserting the HTML <head> content into <head-top> and <head-bottom> tags in the layout file, which are inserted at the top and bottom (after MarkBind's assets) of the <head> tag respectively.

The above example shows the use of the <head-bottom> tag to insert a custom stylesheet (main.css).


Inserting scripts after the <body> tag

You may also insert HTML code after the <body> section of the generated HTML page. This is useful for including custom scripts. Simply insert the code / <script> tags into a <script-bottom> tag.

The above example shows the use of the <script-bottom> tag to show a browser alert box with the message 'Hi!'.

The scripts inserted here are processed last, after all of MarkBind's processing.

If you wish insert scripts at the bottom, before MarkBind's scripts, simply insert them into the bottom of the layout file.


Sticking the header to the top

A sticky header can be implemented by simply adding the sticky attribute to a <header> element.

Using this attribute as opposed to setting position: sticky manually in your stylesheets comes with several conveniences:

  • When scrolled to, page anchors will line up below the sticky header, and not hidden behind it.
  • To preserve screen real estate, the header is hidden on devices with a width of less than 767px when the user scrolls down, and automatically re-shown when the page is scrolled up.
Offsetting elements with the header height

MarkBind also exposes the css variable --sticky-header-height which contains the height of your header.

It's primary intended use case is to offset secondary layout elements (e.g. your site navigation menu) so that they are not hidden behind the sticky header, as the reader scrolls down your page's main contents.

Example Here's how it is used in the default layout's site and page navigation menus

#site-nav,
#page-nav {
    position: sticky;
    /*
     Offset the top sticky position,
     such that the menus are not hidden behind the header.
     */
    top: var(--sticky-header-height);
    /*
     Limit the height of the menus so that the reader is able to scroll
     through the menus individually, without having to scroll to the bottom of the page.
     */
    max-height: calc(100vh - var(--sticky-header-height));
    ...
}

Constructing a site navigation menu easily


A Site Navigation Menu (siteNav for short) can be used to show a road map of the main pages of your site.

Steps to add a siteNav:

  1. Format your siteNav as an unordered Markdown list
  2. Include it under a <site-nav> element.
  3. (Optional) To make siteNav accessible on smaller screens, you can use the <site-nav-button /> component in the navbar.

CODE:

<site-nav>
* [**Getting Started**](/userGuide/gettingStarted.html)
* **Authoring Contents** :expanded:
  * [Overview](/userGuide/authoringContents.html)
  * [Adding Pages](/userGuide/addingPages.html)
  * [MarkBind Syntax Overview](/userGuide/markBindSyntaxOverview.html)
  * [Formatting Contents](/userGuide/formattingContents.html)
  * [Using Components](/userGuide/usingComponents.html)
</site-nav>

OUTPUT:

MarkBind has styles nested lists with additional padding and smaller text sizes up to 4 nesting levels. Beyond that, you'd have to include your own styles.

Expanding menu items by default

You can append the :expanded: to a to make it expand by default. In the example above, * Authoring Contents :expanded: makes the menu item Authoring Contents expand by default.


Constructing a page navigation menu


A Page Navigation Menu (pageNav for short) displays a list of the current page's headings. Page navigation menus are typically configured in layouts, but can also be utilized in individual pages.

Adding a pageNav

  1. Specify the smallest heading level you want to be included within the <frontmatter> of a page with or a .

    The default level uses the headingIndexingLevel property of your site configuration file.

  2. (Optional) You may also specify a page navigation title within <frontmatter> that will be placed at the top of the page navigation menu.

  3. Position the page navigation menu within your layout using the <page-nav /> component.

  4. (Optional) To make pageNav accessible on smaller screens, you can use the <page-nav-button /> component in the navbar.

  5. (Optional) To make pageNav available on print, you can position the page navigation menu on individual pages with the <page-nav-print /> component.

Additional details on printing pageNav

You can specify the location of the page navigation menu on print by using either of the following syntaxes:

  • <page-nav-print />
  • <page-nav-print></page-nav-print>
    • This is useful if you want to include a custom title (or any other content) before the page navigation menu. For example, <page-nav-print>Table of Contents</page-nav-print>

You can specify multiple <page-nav-print /> components in a page and they do not have to be at the top of the page. They also do not appear when viewed on a browser.

Example In the page that you want to have page navigation printed (i.e. to serve as a table of content when viewed on PDFs), use the <page-nav-print /> component to position the pageNav like so:

<frontmatter>
  pageNav: 2
  pageNavTitle: "Chapters of This Page"
</frontmatter>

<page-nav-print />

# Overview
Content of the page...

To view the pageNav on print, open the print preview of the page using the browser's print function.

If you are using Chrome, you can right-click on the page and select "Print" to open the print preview. You can try it out by going to our CLI Commands page and printing it.



Plugin: Tags

With this plugin you can use tags to selectively filter content when building a site.

Toggling alternative contents

Tags are specified by the tags attribute, and can be attached to any HTML element. During rendering, only elements that match tags specified in the site.json files will be rendered.

Example Attaching tags to elements:

# Print 'Hello world'

<p tags="language--java">System.out.println("Hello world");</p>
<p tags="language--C#">Console.WriteLine("Hello world");</p>
<p tags="language--python">print("Hello world")</p>

You need to specify the tags to include in the pluginsContext, under tags:

{
  ...
  "plugins" : [
    "filterTags"
  ],
  "pluginsContext" : {
    "filterTags" : {
      "tags": ["language--java"]
    }
  }
}

All other tagged elements will be filtered out. In this case, only the element with the language--java tag will be rendered. This is helpful when creating multiple versions of a page without having to maintain separate copies.

If the filterTags plugin is not enabled in site.json, all tagged elements will be rendered.

You can also use multiple tags in a single HTML element. Specify each tag in the tags attribute separated by a space. An element will be rendered if any of the tags matches the one in site.json.

Example Attaching multiple tags to an element:

# For loops

<p tags="language--java language--C#">for (int i = 0; i < 5; i++) { ... }</p>

As long as the language--java or language--C# tag is specified, the code snippet will be rendered.

Alternatively, you can specify tags to render for a page in the frontmatter.

Example Specifying tags in frontmatter:

<frontmatter>
  title: "Hello World"
  tags: ["language--java"]
</frontmatter>
<p tags="language--java advanced">System.out.println("Hello world");</p>
<p tags="language--C# basic">Console.WriteLine("Hello world");</p>
<frontmatter>
  title: "Hello World"
  tags: ["language--java"]
</frontmatter>

Tags in site.json will be merged with the ones in the frontmatter, and are processed after frontmatter tags. See Hiding Tags for more information.

Advanced Tagging Tips

You can use a * in a tag name to match elements more generally. A * in a tag will match any number of characters at its position.

Example Using general tags:

<frontmatter>
  title: "Hello World"
  tags: ["language--*"]
</frontmatter>

<p tags="language--java">System.out.println("Hello world");</p>
<p tags="language--C#">Console.WriteLine("Hello world");</p>
<p tags="language--python">print("Hello world")</p>

All 3 <p>s will be shown.

Hiding Tags

Using - at the start of a tag hides all tags matching the expression. This is helpful for disabling a group of tags and enabling a particular tag.

Example Using general tags:

index.md
<frontmatter>
  title: "Hello World"
  tags: ["language--java"]
</frontmatter>

<p tags="language--java">System.out.println("Hello world");</p>
<p tags="language--C#">Console.WriteLine("Hello world");</p>
<p tags="language--python">print("Hello world")</p>
site.json
{
  ...
  "plugins" : [
    "filterTags"
  ],
  "pluginsContext" : {
    "filterTags" : {
      "tags": ["-language--*", "language--C#"]
    }
  }
}

language--java is overridden by -language--*, so only language--C# is shown.

This only works because tags are processed left to right, so all language--* tags are hidden before language--C#. Tags in site.json are processed after tags in <frontmatter>.

# Print 'Hello world'

<p tags="language--java">System.out.println("Hello world");</p>
<p tags="language--C#">Console.WriteLine("Hello world");</p>
<p tags="language--python">print("Hello world")</p>
{
  ...
  "plugins" : [
    "filterTags"
  ],
  "pluginsContext" : {
    "filterTags" : {
      "tags": ["language--java"]
    }
  }
}