63

I've noticed when I'm watching a video and I click on the logo or a related video that a red progress bar (above the logo) dashes across the screen. At the same time there is a slight overlay to "grey" out the content then it fades in the new page. FYI, the URL changes to the new URL before the progress bar and transition happens.

The div ID of that bar is progress. Looks like some kind of cool jQuery ajax load but changing pages. I don't know.

enter image description here

kel
  • 1,579
  • 4
  • 18
  • 31

3 Answers3

47

YouTube is using the HTML5 History API to add and remove page URLs to the history stack. This results in the URL changing in the address bar, and the back/forward buttons working, while still actually loading the page via JS (ajax).

The easiest way to implement the API with backwards compatibility at this point is by using History.js. By backwards compatibility I mean falling back to the hash tag method for older browsers that do not support the HTML5 History API yet.

Check out the History.js demo!

I think Twitter is probably the best known example of a website using hashed URLs. For example twitter.com/#!/username has been a common sight for years. The problem with this method is that hash tags are client side, thus you need JS to read them and serve the proper content. Any non-JS user clicking a hashed URL will just land on Twitter's homepage.

Beatport was one of the first major websites using the HTML5 History technique by the way. SoundCloud has recently implemented it too. Both sites needed HTML5 History badly, to ensure audio playback while visitors browse through pages.

Robbert
  • 5,063
  • 6
  • 36
  • 44
  • What is the user enters the url into the address bar manually, I don't think they will be able to intercept the url change then and will load the page normally, is this right? – Timo Huovinen Oct 08 '13 at 19:25
  • 1
    Correct - being able to intercept manual URL changes, or history states from other websites for that matter, would cause major security issues. Your website should always assume the user has JS disabled and is visiting the URL manually. Once JS is loaded you can hijack any in-page clicks (or history state changes) and load the appropriate content via JS/ajax. Make sure the ajax'd page has the exact same content as the page would have for a direct non-JS visitor. – Robbert Oct 13 '13 at 13:01
  • 3
    @IderAghbal XMLHttpRequest2 supports progress events (see this blog post for an example: http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/). So all YouTube does is something like `...addEventListener("progress", function(e) {bar.style.width = (e.loaded / e.total)+"%"}` along with a CSS transition: `#bar {transition:all 200ms}`. – Robbert Dec 22 '13 at 10:26
  • 1
    They use: https://github.com/youtube/spfjs here: https://youtube.github.io/spfjs/ – mayankcpdixit Jan 12 '16 at 06:18
10

Youtube has open-sourced the library they use for dynamic navigation called spfjs.

Structured Page Fragments — or SPF for short — is a lightweight JS framework for fast navigation and page updates from YouTube.

Using progressive enhancement and HTML5, SPF integrates with your site to enable a faster, more fluid user experience by updating just the sections of the page that change during navigation, not the whole page. SPF provides a response format for sending document fragments, a robust system for script and style management, an in-memory cache, on-the-fly processing, and more.

Community
  • 1
  • 1
Olim Saidov
  • 2,796
  • 1
  • 25
  • 32
7

looking at this demo, maybe could help you, and look at the comments, some say nice while some say too complicate to achieve it

html:

<div>
  <dt></dt>
  <dd></dd>
</div>

css:

#progress {
    position: fixed;
    z-index: 2147483647;
    top: 0;
    left: -6px;
    width: 1%;
    height: 2px;
    background: #0088CC;
    -moz-border-radius: 1px;
    -webkit-border-radius: 1px;
    border-radius: 1px;
    -moz-transition: width 500ms ease-out,opacity 400ms linear;
    -ms-transition: width 500ms ease-out,opacity 400ms linear;
    -o-transition: width 500ms ease-out,opacity 400ms linear;
    -webkit-transition: width 500ms ease-out,opacity 400ms linear;
    transition: width 500ms ease-out,opacity 400ms linear;
}


#progress dd, #progress dt {
    position: absolute;
    top: 0;
    height: 2px;
    -moz-box-shadow: #0088CC 1px 0 6px 1px;
    -ms-box-shadow: #0088CC 1px 0 6px 1px;
    -webkit-box-shadow: #0088CC 1px 0 6px 1px;
    box-shadow: #0088CC 1px 0 6px 1px;
    -moz-border-radius: 100%;
    -webkit-border-radius: 100%;
    border-radius: 100%;
}

#progress dt {
    opacity: .6;
    width: 180px;
    right: -80px;
    clip: rect(-6px,90px,14px,-6px);
}

#progress dd {
    opacity: .6;
    width: 20px;
    right: 0;
    clip: rect(-6px,22px,14px,10px);
}  

js:

$(document).ajaxStart(function() {
//only add progress bar if added yet.
  if ($("#progress").length === 0) {
    $("body").append($("<div><dt/><dd/></div>").attr("id", "progress"));
    $("#progress").width((50 + Math.random() * 30) + "%");
  }
});

$(document).ajaxComplete(function() {
//End loading animation
    $("#progress").width("101%").delay(200).fadeOut(400, function() {
      $(this).remove();
    });
});
xguox
  • 721
  • 8
  • 13