New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document load order requirements (when anchors.add() should be called) #69

Closed
k-funk opened this Issue Aug 16, 2016 · 8 comments

Comments

Projects
None yet
2 participants
@k-funk
Contributor

k-funk commented Aug 16, 2016

Took me a while to figure out the usage, but in my webpack-built application, I included anchor-js like this:

import anchorJS from 'anchor-js';

/* view wrapper */

    var anchors = new anchorJS();
    anchors.options.placement = 'left';
    anchors.add('article h2, article h4');

    // OR

    var anchors = new anchorJS({placement: 'left'}).add('article h2, article h4');

/* end view wrapper */

I think it would be helpful to add this example to the README, or if it's incorrect, an example of how you think it should be used correctly.
@bryanbraun

This comment has been minimized.

Show comment
Hide comment
@bryanbraun

bryanbraun Aug 17, 2016

Owner

@k-funk, this is a great idea. We forgot to include more usage examples when we added support for modules (webpack, etc). I think the best place for something like this is on the gh-pages branch, under the "Basic Usage" section, if we can keep it concise, or "Advanced Usage" if we want a full example with options, like yours above.

Owner

bryanbraun commented Aug 17, 2016

@k-funk, this is a great idea. We forgot to include more usage examples when we added support for modules (webpack, etc). I think the best place for something like this is on the gh-pages branch, under the "Basic Usage" section, if we can keep it concise, or "Advanced Usage" if we want a full example with options, like yours above.

@k-funk

This comment has been minimized.

Show comment
Hide comment
@k-funk

k-funk Sep 14, 2016

Contributor

@bryanbraun Turns out that my example doesn't actually implement all of anchorjs functionality. Linking someone to anchors doesn't work since the id isn't on the page at load time. I actually don't understand how AnchorJS does this in the first place. If the fragment isn't part of the initial html, how does AnchorJS navigate to an ID that it created, after the page is done loading? I don't see any of that in your source files.

Contributor

k-funk commented Sep 14, 2016

@bryanbraun Turns out that my example doesn't actually implement all of anchorjs functionality. Linking someone to anchors doesn't work since the id isn't on the page at load time. I actually don't understand how AnchorJS does this in the first place. If the fragment isn't part of the initial html, how does AnchorJS navigate to an ID that it created, after the page is done loading? I don't see any of that in your source files.

@bryanbraun

This comment has been minimized.

Show comment
Hide comment
@bryanbraun

bryanbraun Sep 14, 2016

Owner

@k-funk, the IDs don't need to be in the original HTML payload. Browsers need to complete a number of actions in the loading lifecycle before they trigger the "jump" behavior based on the URL fragment. For example, they can't jump before the DOM is fully loaded, otherwise they might not find the ID. Also, if they jump too early in the rendering process, they might jump to the wrong place on the page.

All of this gives you time to run JS and add the IDs into the markup.

Different browsers jump at different times, but the recommended way to include AnchorJS is before the closing body tag of your HTML document. This means it'll run early in the process, before DOMContentLoaded is complete.

I've done some rough testing to see "how late" I can run AnchorJS in various browsers and have it "still work". In case you are curious, here's what I found (the browser name is listed where they last successfully jumped to the anchor):

on DOMContentLoaded on window.onload on arbitrary setTimeout
Chrome
Firefox
Safari
IE
Opera

In short, you're good if you run AnchorJS before or on DOMContentLoaded.

The last thing I'll say, is that there's a number of people who use AnchorJS without adding IDs to the page. They often have tools that generate IDs on the backend but they use AnchorJS as an easy way to sprinkle the UI links onto the page. That's a valid use-case that ignores the load-time situation altogether.

Owner

bryanbraun commented Sep 14, 2016

@k-funk, the IDs don't need to be in the original HTML payload. Browsers need to complete a number of actions in the loading lifecycle before they trigger the "jump" behavior based on the URL fragment. For example, they can't jump before the DOM is fully loaded, otherwise they might not find the ID. Also, if they jump too early in the rendering process, they might jump to the wrong place on the page.

All of this gives you time to run JS and add the IDs into the markup.

Different browsers jump at different times, but the recommended way to include AnchorJS is before the closing body tag of your HTML document. This means it'll run early in the process, before DOMContentLoaded is complete.

I've done some rough testing to see "how late" I can run AnchorJS in various browsers and have it "still work". In case you are curious, here's what I found (the browser name is listed where they last successfully jumped to the anchor):

on DOMContentLoaded on window.onload on arbitrary setTimeout
Chrome
Firefox
Safari
IE
Opera

In short, you're good if you run AnchorJS before or on DOMContentLoaded.

The last thing I'll say, is that there's a number of people who use AnchorJS without adding IDs to the page. They often have tools that generate IDs on the backend but they use AnchorJS as an easy way to sprinkle the UI links onto the page. That's a valid use-case that ignores the load-time situation altogether.

k-funk added a commit to k-funk/simple-webpack-react-starter that referenced this issue Sep 14, 2016

@k-funk

This comment has been minimized.

Show comment
Hide comment
@k-funk

k-funk Sep 14, 2016

Contributor

I've created a sample repo using webpack/jquery/anchorjs for you to see my behavior.

From what I'm gathering, using jquery's

var anchorJS = require('anchor-js');
var $ = require('jquery');

$(function() {
  new anchorJS({placement: 'right'}).add('h3');
});

is going to be too late?

A lot of web applications start after that event.

If it's required to use

window.addEventListener('DOMContentLoaded', function(){
  new anchorJS({placement: 'right'}).add('h3');
});

then it seems like that should be well documented, since it's very uncommon to listen to that particular event, in my experience.

Contributor

k-funk commented Sep 14, 2016

I've created a sample repo using webpack/jquery/anchorjs for you to see my behavior.

From what I'm gathering, using jquery's

var anchorJS = require('anchor-js');
var $ = require('jquery');

$(function() {
  new anchorJS({placement: 'right'}).add('h3');
});

is going to be too late?

A lot of web applications start after that event.

If it's required to use

window.addEventListener('DOMContentLoaded', function(){
  new anchorJS({placement: 'right'}).add('h3');
});

then it seems like that should be well documented, since it's very uncommon to listen to that particular event, in my experience.

@bryanbraun

This comment has been minimized.

Show comment
Hide comment
@bryanbraun

bryanbraun Sep 19, 2016

Owner

@k-funk, I haven't experienced any issues testing it in a DOMContentLoaded callback, so that's why it hasn't been documented as a requirement thus far.

Thanks for putting together that sample repo. I'm in the middle of a busy couple of weeks right now (ran a marathon yesterday, going to a wedding in a couple of days), but I'll test it out the next time I get a chance.

Owner

bryanbraun commented Sep 19, 2016

@k-funk, I haven't experienced any issues testing it in a DOMContentLoaded callback, so that's why it hasn't been documented as a requirement thus far.

Thanks for putting together that sample repo. I'm in the middle of a busy couple of weeks right now (ran a marathon yesterday, going to a wedding in a couple of days), but I'll test it out the next time I get a chance.

@k-funk

This comment has been minimized.

Show comment
Hide comment
@k-funk

k-funk Oct 1, 2016

Contributor

Correct me if I'm wrong, but it seems like the sam issue is happening in your jsfiddle: https://fiddle.jshell.net/bryanbraun/nc6rL9hk/show/light/#return-of-the-jedi
If you view the source of that page, you'll see that it's inside a window.onload=function(){ anchors.add('h2'); }, and that upon refreshing the page with the hash in the url, it doesn't jump to the expected header.

Contributor

k-funk commented Oct 1, 2016

Correct me if I'm wrong, but it seems like the sam issue is happening in your jsfiddle: https://fiddle.jshell.net/bryanbraun/nc6rL9hk/show/light/#return-of-the-jedi
If you view the source of that page, you'll see that it's inside a window.onload=function(){ anchors.add('h2'); }, and that upon refreshing the page with the hash in the url, it doesn't jump to the expected header.

@bryanbraun bryanbraun changed the title from Docs for using anchorjs in node. to Document load order requirements (when anchors.add() should be called) Oct 5, 2016

@bryanbraun

This comment has been minimized.

Show comment
Hide comment
@bryanbraun

bryanbraun Oct 5, 2016

Owner

@k-funk, ok, I checked out your repo and confirmed that it's not working as expected (and yep, I'm seeing it in that JSFiddle as well). Thanks for putting those together. You're right, we're going to need to add some documentation for this. I've updated the issue title to reflect that (since @afeld put in a PR for the node/commonJS documentation).

I'd like to dig into the details a bit more so we can document it right. A few questions I have are:

  • Is there any concern with triggering this inside jQuery's $(function() { ... }? I was under the impression that it was the same as window.addEventListener('DOMContentLoaded under the hood.
  • When in the event cycle is anchors.add being triggered in your webpack/react demo app? If after window.onload, is that a common usecase?

I'll see what I can find.

We should probably get a better demo than that jsfiddle too... 😆 😞 .

Owner

bryanbraun commented Oct 5, 2016

@k-funk, ok, I checked out your repo and confirmed that it's not working as expected (and yep, I'm seeing it in that JSFiddle as well). Thanks for putting those together. You're right, we're going to need to add some documentation for this. I've updated the issue title to reflect that (since @afeld put in a PR for the node/commonJS documentation).

I'd like to dig into the details a bit more so we can document it right. A few questions I have are:

  • Is there any concern with triggering this inside jQuery's $(function() { ... }? I was under the impression that it was the same as window.addEventListener('DOMContentLoaded under the hood.
  • When in the event cycle is anchors.add being triggered in your webpack/react demo app? If after window.onload, is that a common usecase?

I'll see what I can find.

We should probably get a better demo than that jsfiddle too... 😆 😞 .

@bryanbraun

This comment has been minimized.

Show comment
Hide comment
@bryanbraun

bryanbraun Oct 22, 2016

Owner

I'm doing a more accurate round of testing (and adding the test files to the repo). Here's what I found:

before closing body tag on DOMContentLoaded on $(document) .ready on window .onload on arbitrary setTimeout
Chrome
Firefox ✓ (unless it runs after window.onload
Safari
IE ✓ (I can force failure with delays on the page, though (large img)
Opera

The results were consistent with the last set of results, but more detailed. Big takeways:

  1. DOMContentLoaded is consistently successful. $(document).ready (which you used in your demo app) was not.
  2. These events were pretty dependable. I can introduce arbitrary delays into the process and still have the ✓'s and ✘'s hold true. For example, in Chrome it will work for DOMContentLoaded at 2000ms (on a page with lots of DOM processing), but not for window.onload at 200ms (on a very simple page).
  3. I found that triggering on setTimeout wasn't consistent, because it depended on which events had passed at the moment setTimeout fired. Also, $(document.ready), wasn't a consistent event; sometimes it occurred before window.onload and sometimes after. I'd chalk that up to it being a third-party event based on multiple factors, and not a pure browser event.

I've pushed these tests up to the anchorjs repo so people can try them out, if desired (see load-order-1.html, load-order-2.html, and load-order-3.html). Maybe some day, we can automate them.


All-in-all, this is enough to convince me to add documentation, instructing users to trigger the add():

  1. Before the closing body tag, or
  2. on DOMContentLoaded

We can add a warning that including it on $(document).ready or later, could result in the links not jumping properly.

Owner

bryanbraun commented Oct 22, 2016

I'm doing a more accurate round of testing (and adding the test files to the repo). Here's what I found:

before closing body tag on DOMContentLoaded on $(document) .ready on window .onload on arbitrary setTimeout
Chrome
Firefox ✓ (unless it runs after window.onload
Safari
IE ✓ (I can force failure with delays on the page, though (large img)
Opera

The results were consistent with the last set of results, but more detailed. Big takeways:

  1. DOMContentLoaded is consistently successful. $(document).ready (which you used in your demo app) was not.
  2. These events were pretty dependable. I can introduce arbitrary delays into the process and still have the ✓'s and ✘'s hold true. For example, in Chrome it will work for DOMContentLoaded at 2000ms (on a page with lots of DOM processing), but not for window.onload at 200ms (on a very simple page).
  3. I found that triggering on setTimeout wasn't consistent, because it depended on which events had passed at the moment setTimeout fired. Also, $(document.ready), wasn't a consistent event; sometimes it occurred before window.onload and sometimes after. I'd chalk that up to it being a third-party event based on multiple factors, and not a pure browser event.

I've pushed these tests up to the anchorjs repo so people can try them out, if desired (see load-order-1.html, load-order-2.html, and load-order-3.html). Maybe some day, we can automate them.


All-in-all, this is enough to convince me to add documentation, instructing users to trigger the add():

  1. Before the closing body tag, or
  2. on DOMContentLoaded

We can add a warning that including it on $(document).ready or later, could result in the links not jumping properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment