More Elegant Loading #container (like google chrome) - javascript

I have a piece of code to display a simple loading by clicking for example on an action (ajax facet search in my case)
so far it does the job.
/!\
Please don't be confused, read and look at the illustration carefully, there is no code or php file or html modified. we only inject a snippet and just specifying an empty #div in the page /!\
add_action( 'wp_head', function () { ?>
<style>
#loading-container {
display:relative;
}
.custom-loader {
z-index:999;
display:flex;
position:fixed;
padding:0;
margin:0;
top:0;
left:0;
width: 100%;
height:100%;
align-content:center;
align-items:center;
justify-content:center;
text-align:center;
font-size:18px;
font-weight:400;
color: white;
background-color:rgba(0,0,0,0.8);
background-size:cover;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.custom-loader i{
margin-right:5px;
margin-left:5px;
}
</style>
<script>
(function($) {
$(document).on('facetwp-refresh', function() {
if (FWP.loaded) {$('#loading-container').prepend('<div class="custom-loader facetwp-loading"><i class="fas fa-sync fa-spin"></i><a>Loading...</a></div>');}
});
$(document).on('facetwp-loaded', function() {
$('.custom-loader').remove();
});
})(jQuery);
</script>
<?php } );
I noticed on very rare occasions because of the network? or anything else unexplained, the loading freeze and we are left to watch fa-sync spinning forever...ouch!very bad for user experience ...
my question: how to make it more customizable? to show a message after x milliseconds for example.
imagine that the loading time will not exceed 4-5 seconds max otherwise there is a real problem...
(like google chrome no network error)
display an error message with a link or button to reset the page.
(in my case it will be reset button onclick = "FWP.reset" )
so the user knows that something wrong has happened to the current request.
I would also like to be able to modify it a little with personalized messages for each task for example :
action when Page Refresh = Loading...
action when clic Facet / search-btn = One moment...
action reset button = Page Reset...
so the dear user knows what exactly is going on.
for the moment this is how I make it work
Elementor Editor
you can see our hidden div section this is our #loading-container
I redo it in any page or section with facets, I feel that it is not practical..
I must think of a more elegant way than that maybe, can be added conditions like
if facets in the page then apply loadings.
thank you if you understand what I'm talking about and you have a more elegant solution to offer

I believe you are using the FacetWP plugin (please make sure that you mention the plugin name exactly so that we would be able to understand).
I did a quick look at their documentation and couldn't find any events/hooks that you can use for your requirements. But you can listen to the click events of the search button or the reset button to trigger the display of loading screen. Here's the link to the documentation of the jQuery's on() method which you can use to handle the click event: https://api.jquery.com/on/
If you are having doubt regarding how to pass the selector to this on(), just right click on the button and choose Inspect Element option in your browser(assuming you are using Chrome/Firefox or something). This will give you some idea on how to choose the selector.
Based on this example, the click event handler for the button would look something like this:
jQuery('.facetwp-icon').on('click', function(){
alert('button clicked');
});
Also, I would suggest prepending your loading screen only once. Then use the show() or hide() function of jQuery to display or hide the screen when needed, rather than removing and prepending again!
If you need custom events (rather listening to the click events like I said above), since this is a paid plugin, try pinging the developers. And they probably would help you with the additional code.
Hope I've given you some pointers to start. Cheers!

I noticed on very rare occasions ... the loading freeze ...
I've recently made a vanilla .js loader. I ran into that exact problem and managed to fix it by generating an <svg> spinner via javascript and animating it after.
The script create a container prepended to the <body> tag, and prepend the css to the closing <head> tag.
It's probably lighter than any plugins you're using and has no dependencies.
var t="#2774ab",u=document.querySelector("*"),s=document.createElement("style"),a=document.createElement("aside"),m="http://www.w3.org/2000/svg",g=document.createElementNS(m,"svg"),c=document.createElementNS(m,"circle");document.head.appendChild(s),(s.innerHTML="#sailor {background:"+t+";color:"+t+";display:flex;align-items:center;justify-content:center;position:fixed;top:0;height:100vh;width:100vw;z-index:2147483647}#keyframes swell{to{transform:rotate(360deg)}}#sailor svg{animation:.3s swell infinite linear}"),a.setAttribute("id","sailor"),document.body.prepend(a),g.setAttribute("height","50"),g.setAttribute("filter","brightness(175%)"),g.setAttribute("viewBox","0 0 100 100"),a.prepend(g),c.setAttribute("cx","50"),c.setAttribute("cy","50"),c.setAttribute("r","35"),c.setAttribute("fill","none"),c.setAttribute("stroke","currentColor"),c.setAttribute("stroke-dasharray","165 57"),c.setAttribute("stroke-width","10"),g.prepend(c),(u.style.pointerEvents="none"),(u.style.userSelect="none"),(u.style.cursor="wait"),window.addEventListener("load",function(){setTimeout(function(){(u.style.pointerEvents=""),(u.style.userSelect=""),(u.style.cursor="");a.remove()},100)})
Beside including the script, you have nothing to do. You can have a look the Github and documentation here # https://github.com/amarinediary/Sailor there is also a visual demo.
Google's best practice is to have a page speed index under 3 seconds. In 3 seconds you shouldn't be able to read anything. Instead of placeholders saying "wait", you should focus on optimizing your page loading times.
Regarding the "No Network" Google's warning, you can make a similar screen by switching your whole website to a webapp and setup an offline page. It's an easy switch, there is a tones of tutorial out-there.

Create your loading screen with SVG and some custom text underneath it. Wrap it inside a DIV.
Using CSS or <Style> set the display equal to block and give it a high Z-index so that it appears above all other HTML elements on the page. This will ensure that the loading screen is displayed when the webpage is first opened.
Use vanilla Javascript to hide the loading screen DIV when the page loads.
window.addEventListener("load", function(){
//this code will run after the page is fully loaded
// just use some javascript to set the loading screen DIV to display none.
document.getElementById("ENTER_DIV_ID_HERE").style.display = "none";
});
If you want to call the loading screen again for some other activity such as clicking a button just create a function with vanilla javascript that will toggle the display on and off this can be done with a timer or some other event that you want to use to hide the loading screen again, below example where will will pass the number of mili-seconds that we want the loading screen to display for.
function showLoadingScreenTemporally(numberofMiliSeconds){
//when this function is called we will show the loading screen first
document.getElementById("ENTER_DIV_ID_HERE").style.display = "block";
//then we will hide the loading screen after the specified numberofMiliSeconds has elapsed
setTimeout(function(){
document.getElementById("ENTER_DIV_ID_HERE").style.display = "none";
}, numberofMiliSeconds);
}
//then we just need to call this function and pass it the number of mili-seconds that we want to display the loading screen for
showLoadingScreenTemporally(4000);
//note I wrote all this just free hand, I have not ran the code coz I am too tired to do so, but thats the general gist of it. Note this is never the way I would implement a loading screen I would always try to tie it to a physical event such as a file upload being completed, etc, rather than just specifying a number of mili-seconds, reason being not all computers are equal some process more quickly than others.

If you want your UI to remain responsive even when network connections are lost then the timeouts you have suggested can help, but to consistently handle this you need a service worker.
Service workers are how you would implement a custom "You are offline!" message.
Basically, a service worker is a javascript proxy to all your network requests - it runs when someone visits your site, and can respond to requests from your site even when there is no network connection either by serving a cached copy, or by serving specific offline messages that your UI JS can handle this for users.
They can also retry poor connections, allowing the occasional drops to just be a slightly slower load by users (rather than asking them to reset/retry manually).
Service workers are a huge topic, but you there are plenty of simple off the shelf implementation (like Workbox) that you can plug in with minimal effort.
Wordpress has an official plug in, and they have examples how to implement offline and retry support.

Related

Chrome Extension: How do I get rid of the FOUC?

The essence of the problem is as follows:
There is a page, I need to modify the contents of the browser extensions, you can use jQuery.
Tried $(document).ready(), but then the contents are still displayed for a short period (FOUC). I can not make changes to the page styles on the server.
I'm using the kango framework to build the extension.
Using only ECMAscript, you can't reliably avoid it. You have like no shot if you wait for DOMContentLoaded event, because at that point the DOM is pretty much rendered and displayed (which is what you see for a short period).
Your best shot would be to modify the CSS as soon as possible. If the stylesheet definition gets loaded before the DOM gets rendered and you would have set like
body {
display: none;
}
you would not see anything. You could try like
<body>
<script>
document.body.style.display = 'none';
</script>
<!-- more html -->
</body>
if that is any viable / useable solution for you.
I suggest you to use a combination of CSS and JavaScript. I had the same issue using jQueryUI on a site I'm building and found that a lot of these solutions out there would make the content unavailable to those without JavaScript.
So, here is what I did:
CSS:
.flash #wrapper {
display: none;
}
This sets <div id="wrapper"> to hidden only if it is a decedent of the flash class. So, to keep it from being hidden from those without JavaScript I add the flash class to <html> element. So, it can only be physically hidden if an end-user has JavaScript enabled, otherwise they'll at least have access via the unstyled content.
JavaScript:
$('html').addClass('flash');
$(document).ready(function() {
/* Do all your stuff */
/* When done show the wrapper with the content styled */
$(#wrapper).show();
});
Depending on your pages time to load you might get a little flash, but it won't be a flash of unstyled content, which is rather ugly. In my case I had a jQueryUI menu item that would flash the normal <ul> element first then the menuUI item, and my <div> elements are resized with jQuery so that each <div> column is equal height, but it would flash the different heights first. This fixed it while still giving accessibility to non-JavaScript browsers.

Progressive enhancement - not hiding elements with CSS

I often find myself showing/hiding elements with jQuery, for example a simple tabbed content area where the first tab is visible and the others are not until they are displayed with the javascript. I know it's not good practice to hide the initially hidden ones using CSS (display: none) and then showing the correct ones with JS as non-JS users will never see a thing. So by default I show all and then hide the relevant ones with JS.
In doing this though, the hidden elements will load and then only hide when document is ready. How can I stop this happening? Is there a way of doing this in a way that will degrade gracefully but also not have elements appearing whilst loading, and then promptly disappearing as this looks a bit shoddy.
Unfortunately, the way that Javascript works, this doesn't seem to be possible. There will always be a fraction of a second between the first rendered frame and by the time the JavaScript to hide the element gets executed I was wrong about that, jQuery seems to be able to do that. So, CSS is the best means for this. Luckily, you can add an alternate CSS stylesheet within an infamous <noscript> tag:
<style type="text/css">
#jquery-thing {
display: none;
}
</style>
<noscript>
<style type="text/css">
#jquery-thing {
display: block !important;
}
</style>
</noscript>
Here's the JSFiddle link:
http://jsfiddle.net/kylewlacy/dbWuc/
a few thoughts...
If you don't mind jQuery being littered all over the page as opposed to being all in a separate file, you can call $('#divToHide').hide(); immediately after the element appears. Not very good practice though. Although it depends on the use case, if you are largely a designer/themer creating a 5 page brochure site, you should choose what is right for you!
Or if you're a bit more of a techie, you might like to mess around with .live()/.livequery() and catch the element's insertion with JS and hide is straight away. See this post Is there a jquery event that fires when a new node is inserted into the dom?

What is the cleanest way to disable postback controls until the page has fully loaded?

I have a website that has some intense graphics, and people with slow connections might require download time. While their browser is downloading, they have form options. And a lot of times they will fill the form out and hit submit.
This causes an event validation issue, because the page wasn't fully loaded. I can think of a lot of ways off the top of my head to fix this. I could go back and disable every single control, and then write javascript to enable these controls clientside when the page is loaded.
I also looked into blockui, but it will block the whole page or just a div. I am looking for something I can stick in my masterpage and forget about it.
Any ideas?
It seems like the correct approach would be to load in your intense graphics after-the-fact, so that users can still submit forms as soon as the critical DOM elements are rendered. (I'm assuming it's not vitally important that all the images be loaded before the form gets submitted?)
You could do this fairly easily by causing your images to be loaded as CSS-based backgrounds on div and body elements, based on a specific class, like this:
body.loaded {background: black url("http://us.battle.net/sc2/static/images/layout/body-bg-baked.jpg") center top no-repeat;}
Then have the following code to add that class after the page loads:
$(window).load(function() {$('body').addClass('loaded');});
It shouldn't produce any significant slow-down in the loading of the images, but it will allow all your page's DOM elements and javascript to run while those images are downloading if necessary.
(jsFiddle example)
I couldn't explain the answer myself. But I think this has the gist of what you need to do.
http://www.telerik.com/community/forums/aspnet/ajax/disable-or-gray-out-page-when-displaying-loading-panel.aspx

How can I make the browser wait to display the page until it's fully loaded?

I hate how you can actually see webpages load. I think it'd be much more appealing to wait until the page is fully loaded and ready to be displayed, including all scripts and images, and then have the browser display it. So I have two questions:
How can I do this?
Is this common practice? If not, why?
This is a very bad idea for all of the reasons given, and more. That said, here's how you do it using jQuery:
<body>
<div id="msg" style="font-size:largest;">
<!-- you can set whatever style you want on this -->
Loading, please wait...
</div>
<div id="body" style="display:none;">
<!-- everything else -->
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#body').show();
$('#msg').hide();
});
</script>
</body>
If the user has JavaScript disabled, they never see the page. If the page never finishes loading, they never see the page. If the page takes too long to load, they may assume something went wrong and just go elsewhere instead of *please wait...*ing.
I think this is a really bad idea. Users like to see progress, plain and simple. Keeping the page at one state for a few seconds and then instantly displaying the loaded page will make the user feel like nothing is happening and you are likely to lose visits.
One option is to show a loading status on your page while stuff processes in the background, but this is normally reserved for when the site is actually doing processing on user input.
http://www.webdeveloper.com/forum/showthread.php?t=180958
The bottom line, you at least need to show some visual activity while the page is loading, and I think having the page load in little pieces at a time is not all that bad (assuming you aren't doing something that seriously slows down page load time).
There is certainly a valid use for this. One is to prevent people from clicking on links/causing JavaScript events to occur until all the page elements and JavaScript have loaded.
In IE, you could use page transitions which mean the page doesn't display until it's fully loaded:
<meta http-equiv="Page-Enter" content="blendTrans(Duration=.01)" />
<meta http-equiv="Page-Exit" content="blendTrans(Duration=.01)" />
Notice the short duration. It's just enough to make sure the page doesn't display until it's fully loaded.
In FireFox and other browsers, the solution I've used is to create a DIV that is the size of the page and white, then at the very end of the page put in JavaScript that hides it. Another way would be to use jQuery and hide it as well. Not as painless as the IE solution but both work well.
Here's a solution using jQuery:
<script type="text/javascript">
$('#container').css('opacity', 0);
$(window).load(function() {
$('#container').css('opacity', 1);
});
</script>
I put this script just after my </body> tag. Just replace "#container" with a selector for the DOM element(s) you want to hide. I tried several variations of this (including .hide()/.show(), and .fadeOut()/.fadeIn()), and just setting the opacity seems to have the fewest ill effects (flicker, changing page height, etc.). You can also replace css('opacity', 0) with fadeTo(100, 1) for a smoother transition. (No, fadeIn() won't work, at least not under jQuery 1.3.2.)
Now the caveats: I implemented the above because I'm using TypeKit and there's an annoying flicker when you refresh the page and the fonts take a few hundred milliseconds to load. So I don't want any text to appear on the screen until TypeKit has loaded. But obviously you're in big trouble if you use the code above and something on your page fails to load. There are two obvious ways that it could be improved:
A maximum time limit (say, 1 second) after which everything appears whether the page is loaded or not
Some kind of loading indicator (say, something from http://www.ajaxload.info/)
I won't bother implementing the loading indicator here, but the time limit is easy. Just add this to the script above:
$(document).ready(function() {
setTimeout('$("#container").css("opacity", 1)', 1000);
});
So now, worst-case scenario, your page will take an extra second to appear.
Immediately following your <body> tag add something like this...
<style> body {opacity:0;}</style>
And for the very first thing in your <head> add something like...
<script>
window.onload = function() {setTimeout(function(){document.body.style.opacity="100";},500);};
</script>
As far as this being good practice or bad depends on your visitors, and the time the wait takes.
The question that is stil left open and I am not seeing any answers here is how to be sure the page has stabilized. For example if you are loading fonts the page may reflow a bit until all the fonts are loaded and displayed. I would like to know if there is an event that tells me the page is done rendering.
Also make sure the server buffers the page and does not immediately (while building) stream it to the client browser.
Since you have not specified your technology stack:
PHP: look into ob_start
ASP.NET: make sure Response.BufferOutput = True (it is by default)
obligatory: "use jQuery"
I've seen pages that put a black or white div that covers everything on top of the page, then remove it on the document.load event. Or you could use .ready in jQuery That being said, it was one of the most anoying web pages I've ever seen, I would advise against it.
in PHP-Fusion Open Source CMS, http://www.php-fusion.co.uk, we do it this way at core -
<?php
ob_start();
// Your PHP codes here
?>
YOUR HTML HERE
<?php
$html_output = ob_get_contents();
ob_end_clean();
echo $html_output;
?>
You won't be able to see anything loading one by one. The only loader will be your browser tab spinner, and it just displays everything in an instant after everything is loaded. Give it a try.
This method is fully compliant in html files.
You can hide everything using some css:
#some_div
{
display: none;
}
and then in javascript assign a function to document.onload to remove that div.
jQuery makes things like this very easy.
In addition to Trevor Burnham's answer if you want to deal with disabled javascript and defer css loading
HTML5
<html class="no-js">
<head>...</head>
<body>
<header>...</header>
<main>...</main>
<footer>...</footer>
</body>
</html>
CSS
//at the beginning of the page
.js main, .js footer{
opacity:0;
}
JAVASCRIPT
//at the beginning of the page before loading jquery
var h = document.querySelector("html");
h.className += ' ' + 'js';
h.className = h.className.replace(
new RegExp('( |^)' + 'no-js' + '( |$)', 'g'), ' ').trim();
JQUERY
//somewhere at the end of the page after loading jquery
$(window).load(function() {
$('main').css('opacity',1);
$('footer').css('opacity',1);
});
RESOURCES
CSS delivery optimization: How to defer css loading?
What is the purpose of the HTML "no-js" class?
How to get the <html> tag HTML with JavaScript / jQuery?
How to add/remove a class in JavaScript?
While I agree with the others that you should not want it I'll just briefly explain what you can do to make a small difference without going all the way and actually blocking content that is already there -- maybe this will be enough to keep both you and your visitors happy.
The browser starts loading a page and will process externally located css and js later, especially if the place the css/js is linked is at the 'correct' place. (I think the advice is to load js as late as possible, and to use external css that you load in the header). Now if you have some portion of your css and/or js that you would like to be applied as soon as possible simply include that in the page itself. This will be against the advice of performance tools like YSlow but it probably will increase the change of your page showing up like you want it to be shown. Use this only when really needed!
You could start by having your site's main index page contain only a message saying "Loading". From here you could use ajax to fetch the contents of your next page and embed it into the current one, on completion removing the "Loading" message.
You might be able to get away with just including a loading message container at the top of your page which is 100% width/height and then removing the said div on load complete.
The latter may not work perfectly in both situations and will depends on how the browser renders content.
I'm not entirely sure if its a good idea. For simple static sites I would say not. However, I have seen a lot of heavy javascript sites lately from design companies that use complex animation and are one page. These sites use a loading message to wait for all scripts/html/css to be loaded so that the page functions as expected.
Don't use display:none. If you do, you will see images resize/reposition when you do the show(). Use visibility:hidden instead and it will lay everything out correctly, but it just won't be visible until you tell it to.
Hope this code will help
<html>
<head>
<style type="text/css">
.js #flash {display: none;}
</style>
<script type="text/javascript">
document.documentElement.className = 'js';
</script>
</head>
<body>
<!-- the rest of your code goes here -->
<script type="text/javascript" src="/scripts/jquery.js"></script>
<script type="text/javascript">
// Stuff to do as soon as the body finishes loading.
// No need for $(document).ready() here.
</script>
</body>
</html>
Put text at the top of the page. While the user reads it, the rest of the page can load and it will be ready by the time the user scrolls down.
I am, frankly, a bit disturbed at many of the answers here. I'd say all of them are terrible. Although I share the skeptical reaction of the various top respondents, many answers give "solutions" that won't display anything at all to a user who has JavaScript disabled, and many others rely on a customized on-page loading notice, while signaling to the browser that the page is already loaded.
As a user, I hate both of these outcomes, so as a web-developer, I'd say these are both "non-solutions". You never want to anger your userbase and the solutions given here will anger a lot of users. I especially hate these approaches because if the user opens a webpage in the background in a new tab, the browser will display the page as loaded but the user might click over to it to find that it isn't loaded.
Independently of your question here, best practice is to make as much of your site work without JavaScript as possible, and best practice is to use the browser's built-in loading signals and never signal to the browser that the page is loaded before it actually is. So really, the only good way to do this is to make your page load so fast that there is never any moment of the user waiting.
The best way to achieve what you want is avoid use of Javascript to load elements of the page, and then optimize the page intensely. Here are the components of this approach:
Have JavaScript on the page if you like, but don't use it to load or otherwise modify any DOM elements after the initial request is fulfilled by the server. Use JavaScript to modify elements of the page only later, such as if triggered by user input, or perhaps to refresh an element after some time, but not in any way related to the page's initial loading. I.e. use JavaScript for what it was designed for (to make webpages interactive) and don't use it to do what HTML was designed for (to make the webpage in the first place.)
Avoid the use of any heavy JavaScript libraries and include as little JavaScript as possible. Never include JavaScript files generically, i.e. only include specific files / libraries in specific pages where you need them.
Specify the width and height of any images in the page code itself, so that the browser can know the exact layout before the image loaded. This reduces any "choppiness" as the page loads, i.e. elements moving around as the browser resizes the boxes in which images of unspecified width are contained.
Ensure that image files are in the exact dimensions being displayed on the page and are not being downsized by the browser. This minimizes file size and also minimizes CPU work the user's computer needs to do to resize images, both of which can affect load time.
Optimize the compression of images, which includes using a good lossy format like JPG and lowering the compression level to as low as you can go without affecting perception. Use lossless formats like PNG only where necessary and ideally keep them small in dimension so the filesize is also small.
Focus the intensity of your optimization efforts on any elements that load "above the fold" on a typical page, as these are what is going to affect what the user sees. Users rarely scroll down instantly, so if elements lower down on the page load a bit slower, almost no one will notice. But still optimize these lower elements reasonably because they also affect server load, bandwidth, and user CPU load.
If you use any elements at all in your page that are potentially very slow to load due to reasons beyond your control, such as content pulled from another server (ads, social media widgets, integrations with other websites, etc.), compartmentalize these in an element of fixed size, and ideally place it below the fold.
Avoid auto-ads, page-modifying AI (like Ezoic), or any other external add-ins that necessarily breaks or undermines one or more of these recommendations. For example, auto-ads are terrible because they rely on loading an external resource,they usually have heavy javascript libraries, and they also modify the page layout. Even the best-designed auto-ads are going to completely undermine all your other optimization efforts.
If you are running a company with multiple developers, quickly jettison any developers who are not fully committed to a lightweight, fast-loading web design. Ideally, don't ever hire such people to begin with. A lot of people get really vested in a certain philosophy or style of development that is at odds with lightweight design. The world would be a better place if these people were in a different line of work, rather than designing webpages.
So you've optimized your page.
This produces the outcome that, if the user clicks the link directly, they'll see the content above the fold fully loaded immediately or nearly-immediately, worst-case-scenario being that a couple images fill in in a second or two. By the time they scroll down, everything else will already be loaded. Any truly-slow-to-load content, such as Google Analytics tracking or other third-party services, will not be central to the appearance of the webpage itself, so the user will see a fully-loaded page even if there are still a few invisible elements loading behind the scenes.
On the other hand, if the user loads the link in a background tab, it will display as loading to the browser, showing the animated symbol in the tab, until it is truly fully loaded. Once it displays as loaded in the tab, if they click it, it will be fully loaded.
In addition, you will have made the page load really fast, which is a good thing in and of itself.
This is a win-win. The user sees a full-loaded page nearly instantly, there is almost never any waiting while looking at a half-displayed page, the loading symbol works as expected when loading a tab in the background, and on top of this you've netted a ton of side-benefits like reduced bandwidth and server CPU load, not to mention lessening the load on the user's CPU as well. (Many users HATE when your page cranks their CPU, and rightfully so.)
So yeah, your choice what to do, but there is only one real solution here and it is lightweight, efficient web design.

How does Facebook keep the header and footer fixed while loading a different page?

When browsing through Facebook pages the header and fixed footer section remain visible between page loads AND the URL in the address bar changes accordingly. At least, that's the illusion I get.
How does Facebook achieve that technically speaking?
Refer to Mark Brittingham's answer for how to style it, although I don't think that is what you are asking here. I will give you the technical details on how it works (and why it is fairly brilliant).
Take a look at the status bar when you hover over the Profile link in the header...
http://www.facebook.com/profile.php?id=514287820&ref=profile
That is where that <a> tag is pointed to. Now look at the address bar when you click it...
http://www.facebook.com/home.php#/profile.php?id=514287820&ref=profile
Notice the "#" fragment identifier/hash? This basically proves that you haven't left the page and the previous request was made with AJAX. They are intercepting the click events on these links, and overriding the default functionality with something of their own.
To make this happen with Javascript, all you have to do is assign a click event handler to those links like so...
var header = document.getElementById('header');
var headerLinks = header.getElementsByTagName('a');
for(var i = 0, l = headerLinks.length; i < l; i++) {
headerLinks[i].onclick = function() {
var href = this.href;
//Load the AJAX page (this is a whole other topic)
loadPage(href);
//Update the address bar to make it look like you were redirected
location.hash = '#' + href;
//Unfocus the link to make it look like you were redirected
this.blur();
//Prevent the natural HTTP redirect
return false;
}
}
One fabulous benefit to this approach is that it allows the back button to be functional (with a little added trickery), which has traditionally been a painful side effect of chronic AJAX usage. I'm not 100% sure of what this trickery is, but I bet it's somehow able to detect when the browser modifies the fragment identifier (possibly by checking it every ~500 milliseconds).
As a side note, changing the hash to a value that can't be found within the DOM (via element ID) will scroll the page all the way to the top. To see what I'm talking about: you scroll down about 10 pixels from the top of Facebook, exposing half of the top menu. Click on one of the items, it will jump it back up to the top of the page as soon as the fragment identifier gets updated (without any window repaint/redraw delay).
One way to provide headers and footers that appear invariant is via CSS - here is an example of a fixed footer (notice the "position: fixed;"):
#Footer {
font-size:xx-small;
text-align:left;
width:100%;
bottom:0px;
position:fixed;
left:0px;
background-color: #CCCCCC;
border-top: 1px solid #999999;
padding:4px;
padding-right:20px;
color:#666666;
}
You'll want to make sure that you add some Margin-Bottom to your page divs (those that fill the main portion of the page) to leave room for the fixed footer (same with a header using Margin-Top).
This does not actually stay on the page but, because the positioning is so tight and invariant, it will appear as if it does unless your page loads take too long. I don't know if this is what FaceBook does but it will give you much the same effect.
With CSS absolute/fixed positioning, the div tags containing the headers and footers can be anywhere in the HTML. Like at the top!
On most current browsers there is a render delay, one quarter second for Firefox I believe, so that the page will not display partially rendered content in quick flashes and waste a lot of time drawing as network data comes in.
So what can happen is that the new page quickly returns HTML containing the styles and header and footer. This content can be rendered immediately by the browser, so when it displays the next page, it appears as if those didn't change.
If the page is generating dynamic content, a good trick is to put all the static information at the top, output that and flush the data buffer. Then do the dynamic database queries and such.
Well, the way to accomplish such a thing would be through AJAX, but as far as I can see, facebook in fact doesn't do this... I just checked, and it refreshes the header like most sites...
Edit: When I first answered this, I was looking at Facebook with Google Chrome (2.0), which for whatever reason, doesn't actually do it this way-->when I click on My Profile from the homepage, it gives me this in the address bar: http://www.facebook.com/profile.php?id=1304250071&ref=profile
and therefore refreshes the whole page... Strange
To augment Josh Stodola's answer: In my understanding the YUI Bookmark Manager does exactly this job.

Categories