Search

Sorry Dave - I thought about this some more and the above isn't accurate, in the case of retina screens the 250px wide image would automatically changed to 500px whilst the 350px would be served as 700px - so you'd still get the blank flash on retina devices. Non-retina would work as described. Sorry for the confusion, didn't occur to me until it had rattled around my head for a little bit. In order to prevent blank flash occurring reliably we would need to implement Brock's idea of a background preload and lazy reload.

Preloader

Have added the preloader as discussed yesterday and made a specific demo page with it enabled - before I merge this into the master github repo could people try it out and see how it works, especially on smartphones and tablets (I don't have access to either hardware at the moment so I can only simulate, would be great to know how it works on real hardware) a good way to test it on desktop is use a Incognito/Privacy mode window with a fresh/empty cache. I've changed the demo so that each image will show a red border for 3 seconds after it has just been updated/changed - thus depending on the speed of you connection you'll see images get red borders a few seconds after you resize, that's the new resolution image being replaced in the DOM.

Here's how it works - if the preload: true option is set (this is disabled by default) then the script creates an Image object in memory, sets the new src to it then sets a callback on the images' onload function that waits to update the actual DOM until it's been fully downloaded. Because each image is handled independently with its own callback/closure the images work asynchronously. I've also added a custom event emitter so that people can listen for when any image has been updated - I initially added this because it made making the new demo a hell of a lot easier, then I realised that the event would be a handy thing to have in lots of situations, you can enable events by passing settings events: true in your options. At the moment there's only a single event - simply add an eventListener for imagerjs.imageUpdated and and pass it a function that accepts a event parameter. This event object has two custom properties event.detail.image which is the actual img element DOM node and event.detail.newsrc which is the new resolution src string, e.g. /image/1/250/0/images/example.jpg. Have a look at the source of the demo page and it'll make obvious sense how it can be used. If anyone can think of any other good places in the code to emit an event that would be useful in interacting with the script do let me know.

I haven't updated the main dev-symphony branch on the github repo but I have added a preload branch so you can get at the code. If there aren't any killer bugs reported and people think it works OK I'll add it into the main branch next week. (Think I'll keep it disabled by default though)

One other thing to note - the demo page won't currently work with IE, because IE is still a piece of s**t and hasn't implemented the CustomEvent method - I will get to next week, there's just no way in hell I was going to spend a single second of my weekend making concessions to IE!! :D

Dude! You're smashing it! You're coming up with solutions quicker than I can find problems. :) This is some seriously nice work and I love the attention to detail in filling in even the edge cases. It's a great suggestion by Brock and from a quick test it looks like a great implementation—and much sooner than I expected.

I haven't had a proper look at the code yet but is the custom event emitter setup in the same fashion as pubsub so you can subscribe to the update event? That sounds pretty useful indeed.

With all the extra goodies packed in to this implementation in such a short space of time someone better tell the BBC that they don't need an expensive RESTful server to serve up on-the-fly images, they just need Symphony, JIT, and this extension on a cheap VM. :)

I'll give it some testing on my devices and browsers and let you know if I discover any hiccups.

Cheers ijy!! Many thanks for your support! :)

I know what you mean, I'm really stoked that as far as I can tell Symphony's JIT and the BBC's code is near the forefront when it comes to the (incredibly tricky) problem of responsive images, yet again shows how adaptable Symphony is to new paradigms etc. On a side note I'm constantly mystified how Symphony isn't the #1 goto solution for professional web-devs needing a CMS?? totally baffles me! :D

About the event, not completely familiar with PubSub but from a quickread on wikipedia I think the answer is yes, the exact code I used was to dispatchEvent a CustomEvent object named/titled imagerjs.imageUpdated to the window element, i.e. to subscribe you just have to add an event listener: -

window.addEventListener('imagerjs.imageUpdated', function(event) {
    console.log(event.detail.image + ' updated to src: ' + event.detail.newsrc);
});

As I understand PubSub from a very quickread this fits with it, only methods listening for imagerjs.* messages will receive them. Is this PubSub?

If you wanted to check on a specific element I think you might need to put that check within the window eventListener, we do have the option of emitting the event on each individual element but that felt to me as though it was overkill and might slow down the DOM too much. But if people have experience yes/no in such cases please let me know. I namespaced it under imagerjs. thinking there are probably other events within the scripts lifecycle that could be of use to peeps (also, didn't want to pollute global event scope with generic events like imageUpdated).

Dude, great job implementing the preloader! This is exactly what I had in mind— you totally killed it and then some.

I'll be putting this through the paces in the coming weeks, so I'll be sure to report any quirks.

Cheers Brock!! And many thanks for the idea! :)

Newly updated demo page and more detailed documentation

JIT Multi-Mode Support - Imager.js now understands and supports all of JIT's modes and settings, so you can crop like usual and it just works - see the updated demo page with cropping in action! Supports modes 0,1,2,3 & 4 - NOTE: Doesn't support external URLs or JIT recipes.

More Events - Well only two more actually, but now enough data that you can use the information to show a progress bar for the background preloader - again see updated demo using the NProgress nano progress bar on page resize. Also added a polyfill for IE so events should work in IE too, have yet to test though. More info in the new documentation.

Noscript David Oliver asked a good question over on twitter about non-JS users. The simple way to support that use-case is simply wrap a fallback img tag in noscript tags and put it inside the div. I've update the imager.xsl template so it does this for you. Example gist here showing the correct markup.

Next up I want to make it so you can have multiple different imager managers/rulesets on one page, I'm not sure if this is possible with the original imager.js and if it's something I've done has broken that functionality, or if it was never there to begin with (going to need to experiment). There's a alternative implementation of the project by another developer at the BBC which has some cool looking 'strategies' (??) support in his version so excited to see what might work well for multiple managers on one page :)

Great work firegoby. This looks and feels great.. Checking on Nexus7..feels boootiful :) Say if I wanted some more JIT recipes..I.e. Get it working with klaftertiefs image cropper extension... Is it just a case of adding some more regex pattern matches or was there a lot more to consider?

I haven't used the image cropper extension but from reading through the instructions it's using a modified JIT with an extra mode - what you'd need to to would be edit Imager.js in two places, 1) the regex and 2) where it generates the output string

  1. Update this.regexp to capture the mode 5 url pattern
  2. Change this anonymous function to accept the new extra parameters captured by your regex, and then add an extra case "5": switch statement here that uses those params to generates the correct output URL

Nice one! Will fork and dabble. ;)

Multiple managers! - You can now safely use multiple Imager.js objects on a single page. I've updated the demo page to show two example sets, as well as some sample code. Note: In order to use mutliple managers you need to pass a unique 'className' option to your 2nd and subsequent Imagers. Each Imager.js is its own object so they're completely independent of each other and have all their own options/settings etc.

Improved imageUpdated Event - This event now has an DOMcached property saying whether the image update was from the DOM cache (note NOT browser cache) - this means that the demo page now only highlights images with red borders when a new image URL is actually first requested from the server. Images highlit in green are ones that have already been requested in this lifecycle and are being refreshed direct from Imager.js' DOM cache.

IE 9+ - IE9+ is supported. IE8 will get the correct resolution images on initial page load but it doesn't understand the resize event so it just keeps those originals. But since IE8 doesn't natively support media-queries anyway this is hardly a great loss. Also, made a small change so that IE8 doesn't throw a fit when we polyfill IE9+'s still crap CustomEvent support. As per usual all the non-fun and painful parts of this project have been trying to get IE not to be a total piece of #@?!

XSLT Template - Now takes optional param jit (defaults to /image/1/{$width}/0) so you can easily make calls to JIT crop modes etc - see the demo page Example #2 for code sample.

I haven't delved into this much, but from what I'm gathering, this library is resizing images on the fly using JIT and the Imager.js library from BBC. Kirk Strobeck created a solution that is similar for this type of thing over a year ago called ResponsImage. It uses JIT to serve up images based on the appropriate device width, specifying on <img> elements or in CSS. It also supports Retina images using a CSS-based @font-face technique.

You can see ResponsImage in use in some of my Symphony projects here:

The image loading happens via JS in ResponsImage, so there isn't a flash when resizing images. Just curious as to how you guys think these two stack up. I've used ResponsImage heavily in my projects and am searching for a better solution if one exists.

@jdsimcoe - Thanks for the link, I hadn't seent this before. Yes, from a quick look over the project page (not the actual code) it looks like they're quite similar. My project simply came about because I was reading about Imager.js and noticed they use a URL image service and I thought to myself, hey, JIT! :)

As for differences: I couldn't get Kirk's demo pages to work in Chrome or Firefox this morning so can't say for certain but from reading the instructions (and please point out anything I've got wrong), the main advantages of my Imager.js fork appear to be: -

  • I don't think there's a background preloader in ResponsImage, so you might get the brief 'blank flash' as new images are downloaded that @davecoggins and @brockpetrie described earlier, espceically on orientation changes on mobile/tablet.
  • If you want to be able to report on image load/update events (e.g. a page load progress bar for big galleries etc) that what my events system is for.

Other than that it seems it's mainly just a difference in setup, config, markup etc - they both appear to work on the same basic principle, request new images from JIT when the resolution requirements change and update with JS.

One thing to note, if you've been using ResponsImage in production for a over a year then I would definitely say that it is a lot more battle-hardened/tested than Imager.js. The BBC say 'not ready for production yet' (though whether they mean BBC level of production = millions of hits etc!) and I haven't made any production sites with it yet, this fork is only a week old!, so ResponsImage has an excellent track record from your experience.

There's a whole load of alternative solutions to the Responsive Image problem, until we get a native browser solution (and then wait for everyone to update their browsers) it's all going to be just different attempts to patch the exisiting technologies. Here's a few other responsive image solutions I've heard of that should be worth exploring too: -

I think which is the best solution all depends on the requirements of each particular project, all have pros and cons

Quick follow up - Here's an interesting write-up by the team behind the Swedish news website Aftonbladet on how they solved the Responsive Images problem - a very creative solution to the reflow problem and all round a really good read, especially if you're considering which approach to take with your next project. Lots of cool work being done in this area! :)

Addressing The Responsive Images Performance Problem: A Case Study

CSS Backgrounds Support (Beta) - Demo page - Now I have mulitple managers on one page working (see above) it's possible to add support for switching CSS backgrounds too. It seems to working well from my testing here but obviously please report any errors/weirdness you might encounter. Will try and flesh out the demo with different uses of CSS backgrounds but so far in tests background-position, background-size, background-position all continue to work as expected, which is unsurprising since it's basically just switching out the background-image value. Background preloading seems to work a treat in this case, very seamless switchover between URLs. Note: The new CSS background stuff isn't on Github yet, will push it over the weekend once I've had a chance to write the accompanying docs.

The CSS Backgrounds support is out of beta and the code has been pushed to the main github repo - there's also a dedicated css backgrounds demo page that's linked to from the main demo page.

Even I found this easy to implement. Wows. This definitely saved me hours of web searching and deciding on the best solution.

Great job! Thanks!!

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details