Boost your page loads with pjax

pjax is a jQuery library that takes regular old page navigation links and turns them into triggers for fast and unobtrusive ajax content loading. Thanks to modern browser features, page URLs, titles and browser history are all updated as usual, even though the pages are not actually reloaded. Like magic!

pjax takes advantage of a recent addition to the browser toolbox: the HTML5 History API. This API allows a JavaScript driven web application to push paths into the browsing history, making it possible for the user to use the back and forward buttons on dynamic content changes, just like with regular page loads. Take a look at the pjax demo to get a quick idea of how it works!

Before the History API, the only way to keep history state and provide permalinks for dynamically loaded content was by using a hack that involved URL fragments, which is a common technique that has recieved some criticism recently.

How it works

With pjax, you define a number of links that you use to navigate between pages on your site (can be your whole navigation menu, or just a particular set of links), as well as a main content area where the actual content part of the pages live. With this information, pjax loads the requested page content from the server and inserts it in the container whenever one of the links is clicked. Since only the content part of the page has to be reloaded, and not the whole page, the result is faster page loads that require less resources, both on the server and the client side. (The difference won't always be that big though – it depends on how complex the side content is, among other things.)

In order for the web server to know that it's dealing with a pjax request, it is handed a special HTTP header. When the server application running the site sees that header, it knows to skip rendering everything on the page apart from the main content area. This means that in order for pjax to be a real performance win, the server application needs to support this. Thankfully, this is not a big hurdle. The pjax page mentions solutions for Rails, Django and ASP.NET – which is helpful, but not for the Drupal project I'm currently working on.

pjax for Drupal

Luckily, implementing pjax for Drupal is not that hard. The project work turned out to be kind of generic, and with just a little extra effort, pjax for Drupal was born! As an example, I've implemented pjax on the blog category navigation on the blog overview page on this site. When you switch between the categories, you should see that the content switches quicker than when you click on links in the main menu.

pjax example

The module implements the necessary HTTP header handling so that only the content that pjax needs is rendered and returned. This content is cached with the standard page cache (separately from the regular pages) to keep responses snappy. Additionally, it provides a configuration page where the content container and the navigation links can be defined. With this information, the module automatically enables pjax for these links. When a link is clicked, it adds loading and active classes, loads the new content, and finally attaches all the defined JavaScript behaviors to the content.

The goal is for the pjax page loads to work exactly like regular ones, only quicker. However, some pages in Drupal include specific JavaScript and CSS files, and those will not get included when loaded with pjax. This is one example of things that can potentially go wrong with pages that are somewhat complex. pjax is probably best suited for loading fairly simple pages, but it's easy to try and enable it selectively for different pages and evaluate the result.

Kommentarer

There are a number of possible reasons for why it could fail. A bug in the module is one of them, a configuration error is another. Another thing I forgot to mention in the text is that pjax only works with browsers that support the History API. With older browsers it falls back to standard page loads.

Are you talking about my example on this site, or a project of your own? If it's the latter, please revisit the README, and report any issues in the issue queue.

Hi,

I am running chrome which supports history and yes I was referring to your website at blogg page.

@Craig: I would say it doesn't affect responsive design at all. It just reloads the markup – all the css, including media queries, will work as normal. Accessibility should really not be affected either. Screen readers usually have the ability to detect content that is added dynamically, and pjax falls back to standard page loads if the client doesn't support it for some reason.

@Vikky: Hm. You're right. Occationally it seems to do full page loads, seemingly at random. Maybe it happens if you click a link before the page load is completely done?

@Vikky: The problem seems to be that sometimes the page doesn't respond fast enough. pjax sets a pretty short timeout (650 ms) and – hey – this is Drupal. :) I think I'll add an option for this in the module, or at least document it. Thanks!

Nice catch. Indeed, its pjax timeout problem. IMO thats pretty weird behavior, but may be there is a use case for such a timeout that I can't think of. Also I have noticed that after every click, the window browser scrolls up. I am not sure if that's a feature. I think the window scroll position should remain unchanged, else the user will get confused. Only for an entire page ajax shall the window scroll to the top. Thanks !

Nice work with the module

Is it possible to load content that isn't in ($page['content']). ? For example an exposed filter block that is positioned in another region, which belongs to a view that's loaded in ($page['content'])?

Thanks!

The module can only load the main content of a page at the moment, and I think that is conceptually what pjax is designed to do. In order to do what you want, the module would need to define a general page callback for blocks, which I think is probably outside the scope of the module. It's not a crazy idea though, and I wouldn't be surpriced if there was already a module that did that (serve blocks to ajax requests).

The way I've handled your particular problem myself is by embedding the exposed filter in the view itself, not as a block.

Hi,
I am trying to configure the Pjax module, but it doesn't want to work at all. Can you explain to me how to configure it? I think Pjax is the only module which can use.

Lägg till ny kommentar

More Kunskap

Några av våra kunder