bigfoot.js

A jQuery plugin for empowering footnotes1

on
off

javascript

Solitude and Leadership

Like the manager1, the head of my department had no genius for organizing or initiative or even order, no particular learning or intelligence, no distinguishing characteristics at all. Just the ability to keep the routine going, and beyond that, as Marlow says, her position had come to her — why?

It means gathering yourself together into a single point rather than letting yourself be dispersed everywhere into a cloud of electronic and social input. It seems to me that Facebook and Twitter and YouTube2 are all ultimately just an elaborate excuse to run away from yourself. To avoid the difficult and troubling questions that being human throws in your way. Am I doing the right thing with my life? Do I believe the things I was taught as a child? What do the words I live by—words like duty, honor, and country—really mean? Am I happy?


  1. — and I’m sorry to say this, but like so many people you will meet as you negotiate the bureaucracy of the Army or for that matter of whatever institution you end up giving your talents to after the Army, whether it’s Microsoft or the World Bank or whatever —  ↩

  2. And just so you don’t think this is a generational thing, TV and radio and magazines and even newspapers, too.  ↩

download

Note: this style requires the positionContent option to be set to true when running the script.

Styles

The Default style shown below comes with the script by default, but I figured I'd throw together a few more example styles to show off the kind of variety you can build into the button/ popover combination.

Try One! →

Introduction

Footnotes on the web are a pain in the ass. You click on a tiny number, get transported somewhere near the bottom of the page, find the footnote you were looking for, and click on a link to go back to where you were on the page4.

This script looks to make that whole process painless. It automatically detects the footnote link and content5, turns the link into an easy-to-click button, and puts up a popover when the reader clicks on the footnote button.

The script and default styles are built to work great on any size viewport; the popover will be positioned on the top/ bottom automatically (based on the relative amount of space), will update its location as the viewport changes size, and will ensure that the popover never scrolls offscreen. All of that adds up to a much-improved user experience.

Usage

The script will work with a wide array of markup, but you will need to make sure that your footnote content/ link markup at least resembles the markup shown below2:

link

content

<p>
    <sup id="fnref:1">
        <a href="#fn:1" rel="footnote">1</a>
    </sup>
</p>
<div class="footnotes"><ol>
    <li class="footnote" id="fn:1">
        <p>footnote.<a href="#fnref:1" title="return to article"> ↩</a><p>
    </li>
</ol></div>

Once you've set up the appropriate markup, adding bigfoot.js to your webpages is easy. By default, all you need to do is include the following anywhere on the page:

index.html

<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="js/bigfoot.js"></script>
<script type="text/javascript">
    $.bigfoot();
</script>

You can also configure the available options by passing an object literal3, and you can store the return object to make use of some of the methods it makes available:

index.html

<script type="text/javascript">
    var bigfoot = $.bigfoot(
        {
            deleteOnUnhover: false,
            preventPageScroll: false,
            hoverDelay: 250
        }
    );
</script>

You'll also want to include styles for the button and popovers, a number of which come with the script (for details, see the Styles section). Copy or import the code in the provided stylesheets into your own stylesheets (both css and scss versions are included) and you should be good to go.

Options

actionOriginalFN

Determines what action will be taken on the original footnote markup: hide (using display: none;), delete, or ignore (leaves the original content in place). This action will also be taken on any elements containing the footnote if they are now empty.

default: "hide"

activateCallback

Specifies a function to call on a footnote popover that is being instantiated (before it is added to the DOM). The function will be passed two arguments: $popover, which is a jQuery object containing the new popover element, and $button, the button that was clicked to instantiate the popover. This option can be useful for adding additional classes or styling information before a popover appears.

default: function(){}

activateOnHover

Specifies whether or not the footnote content will be activated when the associated button is hovered over.

default: false

allowMultipleFN

Specifies whether or not multiple footnote popovers can be active simultaneously.

default: false

anchorPattern

Specifies the pattern that must be matched by the anchor element's href attribute for it to be considered a footnote link. This is used in filtering all links down to just those with a footnote.

default: /(fn|footnote|note)[:\-_\d]/gi

anchorParentTagname

The tagname of the (possible) parent of the footnote link. This is really only necessary when you want to also get rid of that element — for instance, when the link is inside a sup tag. This tag and the link itself will be joined together for attribute from which you can drawn in your markup for footnotes/ buttons.

default: "sup"

appendPopoversTo

Determines where the footnote popover element will be placed in the DOM. If the option is any falsy value, the element will be appended to the nearest block-level element relative to the position of the footnote button that was activated. Otherwise, the element will be appended to the (string) selector you provided9.

default: undefined

breakpoints

An object containing information about breakpoints specified for your set of popovers. These breakpoints should be manipulated only by using the bigfoot.addBreakpoint() and bigfoot.removeBreakpoint() methods discussed in the methods section.

default: {}

deleteOnUnhover

Determines whether footnotes that were instantiated by hovering over the footnote button are removed once the footnote button/ footnote popover is un-hovered.

default: false

footnoteParentClass

The class name for the containing element of the original footnote content. Typically, this will be a class on an li that contained the footnote. This element may be removed/ hidden, depending on the option specified for actionOriginalFN. This string does not have to be an exact match — the class names will simply be tested for whether they include this string.

default: "footnote"

footnoteTagname

The element that contains the footnote content. As noted above, this element may be hidden or deleted, and will be given the footnote-processed class once Bigfoot has finished with it.

default: "li"

hoverDelay

If deleteOnUnhover is true, this specifies the amount of time (in milliseconds) that must pass after the footnote button/ content is un-hovered before the footnote is removed.

default: 250

numberResetSelector

A string representing the selector at which you would like the numbering of footnotes to restart to 1. For example, you may be using the numbered style of footnote and wish to have the numbers restart for each <article> on your main page with a class of "article-container". In this case, you would set this option to "article.article-container" (or an equivalent CSS selector). Leaving the option as undefined will simply number all footnotes on a given page sequentially.

default: undefined

popoverDeleteDelay

When the footnote content is being removed this option specifes how long after the active class is removed from the footnote before the element is actually removed from the DOM6.

default: 500

popoverCreateDelay

Sets a delay between the activation of the footnote button and the activation of the actual footnote content.

default: 100

positionContent

Specifies whether or not the footnote popovers (and the popover tooltip, if it is included in the markup) should be positioned by the script.

If this option is true, the popover top of the footnote popover7 will be positioned at the middle (vertically) of the footnote button, while the left of the popover will be placed a distance from the (horizontal) middle of the button proportional to the footnote button's horizontal position in the window.

default: true

preventPageScroll

Determines whether or not, when scrolling past the end of a footnote whose content is taller than the vertical space available, the scroll event will propagate to the window itself.

default: true

scope

If any truthy value is provided, only the footnotes within the scope you define will be affected by the script. The scope should be a selector string, as you would typically use in jQuery. For example, setting a scope of ".bigfoot-active" would work only on those elements with an ancestor that has a class of bigfoot-active.

default: undefined

useFootnoteOnlyOnce

Determines whether or not a footnote can be used as the content for multiple footnote buttons. Many content management systems will, on a blog's main page, load every article chronologically without any adjustments to the article markup. This can cause issues if multiple footnotes have the same ID: the footnote content is identified by the fragment identifier in the href attribute of the footnote link, so multiple identical IDs can result in the same footnote content being used for different footnote links. This option prevents this by using a footnote as the content for at most one footnote button.

default: true

contentMarkup

A string representation of the markup of the footnote content popovers. It's best not to change this too much; the script relies on the class names and hierarchy of the default markup to do its work. However, you can add information to the rendered markup by adding string literals or one or more of the following variables:

  • {{FOOTNOTENUM}}: inserts the footnote number (sequential ordering of all footnotes within an element matching the numberResetSelector option).

  • {{FOOTNOTEID}}: inserts the footnote identifier (sequential ordering of all footnotes on the page, starting from 1).

  • {{FOOTNOTECONTENT}}: inserts the html markup of the original footnote with all relevant characters escaped.

  • {{BUTTON:attr}}: inserts the attribute of the associated footnote button attribute (attr). For example, {{BUTTON:id}} will insert the id of the footnote button that instantiated the popover.

default

<aside class="bigfoot-footnote is-positioned-bottom"
  data-footnote-number="{{FOOTNOTENUM}}"
  data-footnote-identifier="{{FOOTNOTEID}}"
  alt="Footnote {{FOOTNOTENUM}}">
    <div class="bigfoot-footnote__wrapper">
      <div class="bigfoot-footnote__content">
        {{FOOTNOTECONTENT}}
      </div>
    </div>
    <div class="bigfoot-footnote__tooltip"></div>
</aside>

buttonMarkup

A string representation of the markup of the footnote button. Again, try not to remove any elements from the markup, but add as much as you like. In addition to the first two variables shown in contentMarkup, the following variables are available:

  • {{SUP:attr}}: Inserts the attribute from the superscript/ anchor tag pair that formed the original footnote link.

  • {{FN:attr}}: inserts the attribute from the original footnote container element.

default

<div class="bigfoot-footnote__container">
  <button href="#" class="bigfoot-footnote__button" rel="footnote"
     id="{{SUP:data-footnote-backlink-ref}}"
     data-footnote-number="{{FOOTNOTENUM}}"
     data-footnote-identifier="{{FOOTNOTEID}}"
     alt="See Footnote {{FOOTNOTENUM}}"
     data-footnote-content="{{FOOTNOTECONTENT}}">

     <svg class="bigfoot-footnote__button__circle" viewbox="0 0 6 6" preserveAspectRatio="xMinYMin"><circle r="3" cx="3" cy="3" fill="white"></circle></svg>
     <svg class="bigfoot-footnote__button__circle" viewbox="0 0 6 6" preserveAspectRatio="xMinYMin"><circle r="3" cx="3" cy="3" fill="white"></circle></svg>
     <svg class="bigfoot-footnote__button__circle" viewbox="0 0 6 6" preserveAspectRatio="xMinYMin"><circle r="3" cx="3" cy="3" fill="white"></circle></svg>
     
  </button>
</div>

Methods

Running the function will return an object that can be stored and used to manipulate the footnote buttons/ content. The following methods are available in this return object:

close([footnotes, timeout])

This function will close any footnote popovers matching the (string) selector provided for footnotes. timeout specifies the amount of time after the footnote's active class is removed before the element itself is removed. Either of these can be excluded; footnotes will default to all active footnotes, while timeout will default to the popoverDeleteDelay option.

activate([button])

This will activate the footnote button (and its associated popover) matching the (string) selector provided for button. If the option to allow multiple footnotes is false, only the first matching footnote will be activated. By default, the first footnote button on the page will be activated.

addBreakpoint(size, [deleteDelay, removeOpen, trueCallback, falseCallback])

This method creates a breakpoint at which time a function is to be run. The most common use for this is to change the footnotes from being positioned by the script to being bottom-fixed to the page (as is the case for this page). As such, the function is meant to make this particular use case as simple as possible.

Only the size parameter is required. You can pass it "iPhone" or "iPad" for those devices' pixel values, a simple string, like "<2em", a string representing a valid media query, like "(min-width: 300px)", or a pre-created MediaQueryList object.

deleteDelay determines how long (in milliseconds, as an integer) should be waited after removing an active popover on a breakpoint before reopening that footnote, and will default to the popoverDeleteDelay option value. removeOpen (boolean) specifies whether this removal should be performed at all. The final two arguments are the callbacks to run when the media query changes to matching and non-matching status, respectively. These callbacks will be passed the removeOpen parameter and a copy of the bigfoot object (for further footnote manipulation). The defaults will simply change the activateCallback option to a function that adds the fixed-bottom class to all footnote popovers.

The method will return an object specifying whether the breakpoint was added, the MediaQueryList object that was created, and the function that was attached as a listener to the media query.

removeBreakpoint(target[, callback])

This function will remove the specified breakpoint. Breakpoints are identified by the target parameter, which can be either the string with which the breakpoint was initially created, or the MediaQueryList object returned as part of the addBreakpoint function.

Optionally, you can provide a callback to execute before the breakpoint is removed. If no callback is provided, the method will run the false callback function from when the breakpoint was initially created.

reposition()

This function repositions all footnotes relative to their button.

getSetting(setting)

Returns the script setting matching the string provided for setting, if such a setting exists.

updateSetting(setting[, newValue])

Updates the script setting matching the string provided for setting with newValue, or adds the option if none exists. In either case, the old value for the setting will be returned.

Alternatively, you can pass in an object of option-new value pairs. In this case, an object of option-old value pairs will be returned.

License

This script is provided under the MIT License. In a nutshell, that means you can do whatever you like with the code and distribute the derivatives however you see fit. I'd love a little attribution if this script plays a major role in whatever derivative you end up creating, but I won't lose any sleep if you don't.

  • Inspired by Instapaper. Built for mobile devices and responsive designs. back

  • Strangely enough, there doesn't appear to be a standard for footnote markup. I went with the closest I could find: the MultiMarkdown output format. The algorithm for identifying footnote link/ content pairs works for most of the major blogs I tried it on without any HTML adjustments.

    The script will place the footnote directly after the nearest block-level element and will remove the li tags when creating the footnote popovers. So, if you want the styles applied to normal paragraphs to apply to the footnote contents, you'll have to wrap them in a p tag in the original footnote markup. back

  • You can learn about all of the configurable options in the Options section. back

  • If the author had the foresight to include such a link; otherwise, you're on your own to get back to the spot in the article where you left off. back

  • The script will try to be as smart as possible when determining what is meant to be a footnote. However, if you're looking for good markup for your footnotes, you can find an example in the usage section below. back

  • This leaves time for any transitions you would like to perform on the footnote as it is being deactivated. back

  • Or the top of the popover, if there is not enough space to position the popover on the bottom and there is more room on top of the footnote button than there is on the bottom. back

  • This is the full version of the script, including comments and other information. It's here for folks who want to see where everything comes from. For production use, make sure to include the minimized version. back

  • For example, setting this option to "body" will append all footnotes to the body element. This may be hepful when complex styles from elsewhere in your stylesheet are overriding the popover styles you have selected. back

  • This is a minified version of the script (all whitespace and comments removed to minimize file size). back

  • This contains the default styling for the footnote button and popovers as a ready-to-go css file. If you don't use SASS or don't plan on changing the default styles, this is the file to import/ copy into your existing stylesheet. back

  • This file contains the default styles written in SASS. It is commented in detail and provides numerous variables with which you can easily change the styles I have chosen. Anyone looking to create a custom button/ popover style would probably want to start with this as a template. back