HTML5, CSS3, jQuery, JSON, Responsive Design...

React Bootstrap Slider component

Michael Brown  March 1 2015 10:29:07 PM
I've just written a ReactJS, wrapper for the HTML5 input type=”range” slider component, but using [seiyria’s Bootstrap Slider component] ( as a polyfill where the HTML5 version is not available (IE 9) or otherwise suffers from a problematic implementation (any other version of IE).

The code and full documentation is available on Github.  There's a demo available too.


I like the HTML5 native range control, especially how easy it is manipulate via ReactJS, my current favourite JavaScript library.  (I'll be writing a lot more about React in future.)  You set up an HTML5 range control like so:

[input type="range" value="20" min="0" max="100" step="10"]

(Note: I've replaced the angled brackets with square ones to prevent the HTML from rendering.)  This will give a slider control, ranging from 0 to 100 in steps of 10, with a starting value of 20.  Nice and easy!

Here’s how the native JavaScript control is rendered in my ReactJS plug-in:
render: function () {
return (
<input id="mySlider"
    step={this.props.step} /]

It’s about as simple a rendering as you could want in React. You’d pass some props into your component, and render them as the corresponding attributes on the input field. Sweet as!
But knock me down with a feather if there aren’t problems with IE.

Internet Explorer Problems

The first problem is that input type="range" element simply isn't supported on IE 9 and below. It will actually display as a type=”text” element, so instead of slider, you’ll get a text box with a number in it.  This is what prompted me to create a React control that would fall back to the Bootstrap Slider for browsers that didn’t support the native HTML5 element.

The second problem is that IE10 and 11, where the control does display, doesn't respond correctly to right events when you need to track the slider value being changed.  I go into more detail on that on my Github page.  I probably could have worked around that one, but ran into my third and final problem with IE.

The third problem in IE is that the HTML5 range control looks like crap!  It’s not just ugly, IMHO. It’s inpractical too.  Its handler (the bit on the control that you actually slide) is the same height as the rest of the slider, making it to pick out with your eye, not to mention with your finger if you’re on a tablet. (Thankfully, the latter would only ever be an issue on Microsoft tablets, of which there's next to zero in the real world).

In the end, I made an executive decision in my React Bootstrap Slider component: I don’t display the native HTML5 slider control on IE. At least not for IE 10 or IE 11.  Maybe it looks better in the new, webkit powered IE 12?  I haven't test this myself.

How to use
You can follow the example code in the app.jsx file on the Github page to see how to use.  The component is called SliderNativeBootstrap. Here’s an example of how you might call it in your ReactJS’s render method:

min={this.state.min} /]

The value, step, max and min parameters should be self-explanatory. handleChange is the callback method that will be called when the slider actually changes. (NB: this is the onInput event for the native HTML5 control, and the “change” event for the Bootstrap slider.)

Forcing the Bootstrap version all the time
An optional parameter is polyfill. When set to true (the default if you leave the parameter out) the component acts as I’ve described it above, i.e. displaying the HTML5 native slider for these browsers that support it properly, and the Bootstrap version for those that don’t. If you want to force the use of the Bootstrap slider for all browsers then you should set this parameter to false, like so:

min={this.state.min} /]

Is here.
On load, the slider range is 1,000 to 20,000 with a step of 1,000.
Click on the Change axes! button, and the slider range changes from 0 to 2,000 with a step of 100.

Delegate your JavaScript events!

Michael Brown  February 20 2015 04:16:59 AM
I looked at a web project today where Allan Jardine's Visual Event plug-in reported nearly 20,000 event handlers on a single page app!

The app was generating a huge table of information, and every row in that table needed something to happen when the user double-clicked on that row.  So to achieve this, the developer had a added a separate event to each row of the table.  "The fool", I thought!  Doesn't the guy know about event delegation?

Well, I was wrong.  The developer did know about event delegation, and had added his events that way.  There was only one event on that table, not 20,000.  But the Visual Event plug-in is incapable of distinguishing between delegated events and individual events when doing its count.  The developer is aware of the problem.

So what's the difference between delegated events and individual events, and why should you be using the former in preference to the latter?

Individual Events

Here's a sample table with about 1000 rows in it:

Each row will pop-up a alert box when you click on that row.  To achieve this, I added events to each individual row in the table using jQuery, like so:
$('#myTable tbody tr').click(function () {
alert("hey " + $(this).attr("data-payload"));

Firefox's HTML Inspector tool (note: the built-in one, and not Firebug) shows you this:

Image:Delegate your JavaScript events!

See how each row in the table is marked with a separate "ev" tag?  That's because each row in the table has its own associated event tag.   This is bad.  Each event handler takes up browser resources.  Too many event handlers on your page and your app will slowly grind to a halt.

So, wouldn't it be good if we could achieve the same result, but with only a single event handing all of our tables?  Yes, it would - is, in fact!  This is what event delegation gives us.

Delegated Events

Here's that same 1000 row table again, but this time it's using a delegated event:

Here's how to add a single event handler for the table's rows, using event delegation:
// For jQuery before version 1.7
$('#myTable tbody').delegate('tr', 'click', function () {
alert("hey " + $(this).attr("data-payload"));

// For jQuery 1.7 and higher, where the .delegate() method is deprecated.
$('#myTable tbody').on('click', 'tr', function () {
   alert("hey " + $(this).attr("data-payload"));

Note that we're telling the select handler here to target the table's tbody, instead of targeting all of its tr rows, as we did in the first example.  This will give us a single click event, on the table's tbody.  The .on() call or the (now deprecated) delegate() call denotes which elements within that tbody we're actually interested in, which is all of its tr rows.  NB: the syntax of the .on() call is important here: it must contain our target element, "tr" in this case, as its second parameter, otherwise it won't delegate the event handler.

The Firefox HTML Inspector confirms that we have only a single event now:

Image:Delegate your JavaScript events!

What we end up with is a single event handler, at the tbody level, which is still able to ascertain which TR row within the tbody you the user actually clicked on.  Bingo!

Update 21/02/2015

Incorporated Mark Roden's comments below, to say that the .delegate() is now deprecated and that we should now be using the .on() method instead.

    How I predicted Tony Abbott’s demise a year ago!

    Michael Brown  February 7 2015 11:55:56 PM
    Why do people always say "I hate say 'I told you so'" when they actually love to say exactly that!  Well, I know I do anyway.

    So back in April 2014, I wrote the comment below on a post on Renai LeMay's Delimiter site.  Sadly, the site is no longer active, but the post and my comment are still there as read only.  In that comment, I predicted that sooner or later, our much maligned (and deservedly so) Prime Minister, Tony Abbott, would be kicked out of his job, to be replaced by the man that he originally knifed, Malcolm Turnbull.

    And blow me down if it isn't all happening exactly as I predicted!  (Okay, not quite how I predicted it: Joe Hockey's well out of the equation now.)  But the Libs' poll numbers are now "through the floor".  And as I write this, we are four days away from a Liberal Party leadership spill that could well see the back of Abbott.

    Here's what I wrote:

    "The real problem is that poor Malc doesn’t want to be doing this job at all. He wants to be Prime Minister. Thinks he *should* be Prime Minister, in fact.

    And in any fair world, he would be. Sadly though, while Leader of the Opposition, he supported Kevin Rudd’s Carbon Emissions Scheme, which marked him out as a Liberal with half a dozen brain cells – five more than his party’s normal prerequisite. Fed up with making the rest of them look *really* stupid like that, the Liberals knifed him. And just to make sure that their self esteem would never suffer in that same way again, replaced him with a borderline retard.

    Malc’s reaction? Why, what any normal member of the “grown ups” party would be: he spat his dummy. Big time. He said he’d serve out his current term as Earl of Wentworth, but would not seek re-election thereafter.

    Time passes…

    Malc has a change of heart, and in 2010 is re-elected, after all.

    Why bother? To spend the rest of his political career kissing the arse of a man that he clearly despises? Don’t think so. He’s about as happy a Vegemite as Communications Minister as Rudd was as Julia Gillard’s Foreign Minister.

    So try this on for size: Malc’s really waiting for the big job to come up again, as it most assuredly will. After all, there’s only so long that you can stand a gibbon up in a suit before the people say “that’s no Prime Minister – it’s just a gibbon that you’ve dressed up in a suit!”

    How best for Malc to achieve his goal though? Why, by fucking up every aspect of his current portfolio, of course! Let chaos reign and wait for their poll numbers to drop through the floor. Same goes to Joe Hockey raising the retirement age to 70 years old. Totally insane, you see? And when the polls drop, you know who gets the chop, the man at the top! (Wow, that even rhymed.) Another Liberal spill flushes Abbott away. Malc and Joe give us all their “mad Tony made us do it, and we’ll be normal from now on, honestly” speech, then get to duke it out for the Prime Ministership that, in their minds, should have been theirs all along.

    Sounds like a bonkers theory, I know, but you have to admit, it does fit the facts!"

    Citrix GeoTrust error on Macintosh

    Michael Brown  October 27 2014 04:23:12 AM
    Sometime in the last few days my Citrix login for work has stopped working on my home Macintoshes.  (Presumably, it still works on Windows; I haven't tried!)  The error I get is:  You have not chosen to trust "GeoTrust DV SSL CA", the issuer of the server's security certificate.
    GeoTrust Citrix error on Macintosh
    Quite right: I haven't trusted GeoTrust DV SSL CA because I've never heard of it before!

    In order to work around this problem, what I needed to do was install the missing certificate into my Macintosh Keychain application.  Here's how you do this:

    1. First, you need to download the certificate itself from

    2. Open the Macintosh Keychain application.  Type "keychain" in Spotlight Search to quickly find and open it.

    3. Within the Keychain app, make sure you have "System" highlighted under the "Keychains" section, and then "Certificates" highlighted under the "Category" section.

    4. Click on File->Import Items from the main Keychain menu.  Go and fine the .cer file that you saved in Step 1.  You'll need an admin password to actually import it.

    That's it.  You should now see the GeoTrust DV SSL CA in our list of Keychain certificates, like so:
    GeoTrust Certificate in Macintosh Keychain

    Many thanks to Peter Rowden on 24sevenIT for this info.  What I've posted here is really just a rewrite of his post there.  He's also hosting the GeoTrust certificate on that site.

    Android on ChromeOS - the revolution begins?

    Michael Brown  September 13 2014 12:49:34 AM
    Despite what you might read from pro-Microsoft trolls in the various forums about how "ChromeOS needs an always-on internet connection",  the OS actually boasts an increasing number of offline-enabled apps.  Check out Google's own word processor and spreadsheet apps, for example.  You can edit spreadsheets and documents locally, with not connection.  When ChromeOS does detect a connection, it syncs those changes up with your Google Drive, just as you'd expect.

    Still, far too many Chrome Apps are little more than jumped-up URLs that really do nothing if you're not online.  The Evernote ChromeOS "app" is just such a beast.

    But now there's an alternative.   You can now ... drum roll, please ... run the Android version of Evernote under ChromeOS! You can install it from the Chrome Web Store.

    And here's how it looks on my Samsung Chromebook (the ARM-based 2013 model):

    Android Evernote on ChromeOS

    The good news is, that it works!  And it works off-line, unlike "Evernote Web" (which is still available as a separate, Chrome App, FYI).

    The bad news:
    • It's slow in operation
    • The window is a fixed size and can't be maximised.   It remains at, what I guess is an "Android size".
    • The fonts are small and hard to read.  I could see no way of resizing them either.

    Still, it's a start!  There's three other such apps: Vine, Duolingo and Sightwords.  But Evernote was the only one that I was already using (or had even heard of).

    Note: you a need the full ChromeOS to get this to work.  It won't work on the Chrome browser for Windows, Mac or Linux.

    See Chrome Owners Get Access to Android Apps (PCPro).

    Responsive CSS Sprites

    Michael Brown  May 4 2014 02:36:00 AM
    On my earlier post Rocket your website speed with CSS sprites!, I showed (I hope!) how can really speed up your page load times by loading a single, combined sprite image instead of multiple individual images.  As I said at the near the end of that post, however, things get a little trickier when you have to take Responsive Web Design into consideration.

    Let's examine the two pages again.  This time I've added a media query to them both.  The media query kicks in when your browser width drops below 700px, so you just need to drag the edge of your browser in to see the effect.  Or if in Firefox, use Ctrl->Shift->M (Command->Alt->M to call up the Responsive Design View.

    Here's the CSS:

    @media all and (max-width: 699px) {
         .flag {
                 width: 32px;
                 height: 21px;

    All it does is set the elements to be half of their normal size.  Let's see how it works in the multiple img tag version first:

    No probs there.  The flags all reset to half size, and the flags are shrunk down nicely with them.  No let's try the CSS prite version with the same media query code:

    Woah!  What's going on here?  The flag div tags are resizing okay when I narrow the browser's width, but the sprite images aren't.  Suddenly, we have an abundance of Union Jacks!  That's because instead of resizing the images, the CSS code is cropping them instead.  So the Australian flag loses all its stars, and we're just left with the Union Jack at the top left.  (What's that at the back?  "That's actually an improvement", you say?  Well, you may have point there, but...)

    So is there way that we can resize the sprite divs and have their images resize correctly too?  Yes, there is, but it takes little bit of work.  The only way that I could find to do it is to specify the image sizes as percentages instead of pixels.

    Percentage for Sprites

    For the calculations on how convert pixel values into percentages, I followed this Stack Overflow thread.  Particular thanks to vals, who got me most of the way there, although there were some errors in his calcs.  I posted my corrections (as ChillyPenguin) on the same thread.

    First off, you have to add a new CSS attribute to your divs.  This is called background-size, and it has to be set as a percentage.  It takes X and Y values, and the percentage calculations go like this:
    x percentage width = (total image width / display image width) x 100
    y percentage width - (total image height / display image height) x 100

    My combined flags image is 1110px wide by 799 px high.  My flags sizes (handily, all the same) are 64px wide by 42px high.  So the background-size values go like this:
    x percentage width = (1110 / 64) x 100 = 1734.375%
    y percentage width - (799 / 42) x 100 = 1902.380952%

    Because all my flags are the same size, I can apply to background-size attribute to a flag class, which I add to all my flag divs:
    .flag {
          display: inline-block;
          background: url('../images/sprite.png') no-repeat;
          width: 64px;
          height: 42px;
          background-size: 1734.375% 1902.380952%;

    Now the hard bit: we have to reset the background-position attributes on all of the flags.  So here's the calcs for that:
    x percentage pos = (x pixel pos / (total image width - display image width)) x 100
    y percentage pos - (y pixel pos / (total image height - display image height)) x 100

    So for my first flag, which is Afghanistan, my absolute background size looks like this:
    .flag.flags-afghanistan {
          background-position: -5px -0px;

    So the percentage calc for the x dimension goes.  Note that the negative x pixel position is converted to positive when you do the percentage calculation:
    x percentage pos = (5 / (1110 - 64) x 100) = 0.4780114723%

    The y percentage is zero in this case, because the pixel y position is also zero.  Here's the resulting background-position code:
    .flag.flags-afghanistan {
          background-position: 0.4780114723% 0;

    Phew!  Got there.  Repeat and rinse for all the other flags, and here's the result: fully responsive sprite images!!

    Note: I've reduced it to only eight flags to try and prevent RSI!!  Yes, the calculations are fiddly but you ought to be able to set up a simple spreadsheet to help you.

    Internet Go Faster switch

    Michael Brown  May 4 2014 08:04:44 PM
    No, not a joke.  Not clickbait.  I just found out that my ISP does, quite literally, have a Go Faster switch for my ADSL2+ connection.

    It's called ADSL Line Profiles:

    The ISP seems to err on the side of caution when they first set you up.  My ADSL2+ Line Profile was set to Very High Reliability, which was giving me download speeds of 800/900 kb/s (on a good day).  After I switched it (in stages) all the way up to Very High Speed, I'm now getting 1.4 Mb/s downloads!!  Still a small fraction of the line's supposed maximum, but a massive improvement on what I had before.  Shame it took me seven and a half years to discover it!!

    I don't know which other ISPs in Australia offer this, let alone ISPs outside of Australia.  It's worth checking into if you have ADSL though.

    Rocket your website speed with CSS sprites!

    Michael Brown  May 3 2014 04:37:23 AM
    Here's two not very interesting web pages that show the national flags for various countries:

    At first glance. they look identical.  But did you notice how much faster the second one loads up?  For me at least, the second one loads pretty well instantaneously, whereas the first is so slow that I can actually see the individual flags slotting into place.

    The difference?  The first page uses bog-standard html img tags, whereas the second uses a CSS sprits.  So, the first page has to load 248 images.  The second loads only one, combined image (the sprite), and then uses CSS to display the correct part of that one image (i.e. the individual flags) over 248 div tags.

    When measured, the speed difference is a wee bit special.  For me, Google Chrome reports that that the img tag version loads up in 2.96 seconds, whereas the CSS sprite version takes only 631ms.  Yep, that's a 469% speed increase!!

    Why such a difference?

    When trying to increase page load speeds, Web developers quite rightly zero in on the size of their elements - smaller equals faster, after all.  But just as important is trying to decrease the number of connections that a page has to make to load up its constituent elements.  All those those individual image file loads have to go through the entire connection/hand-shaking routine before the download actually starts.  There's also limits on the number of concurrent downloads a browser will allow from a single server.  This seems to be six concurrent downloads for most browsers, although for IE 8 and below it's only two.

    Things get a little more complicated if you should need to resize the sprite-based images responsively, however.  And that will be the subject of a future post...

    Note: I borrowed this bit of AppleScript from a StackOverflow post , in order to generate the HTML img tags for the first version of the flags page:
    -- select multiple files, limited to images
    set filelist to choose file of type "public.image" with multiple selections allowed

    set html to ""

    -- make a loop that goes through each file
    repeat with imagefile in filelist
    tell application "Image Events"
      set img to open imagefile
      -- get dimensions of image
      copy the dimensions of img to {W, H}
      -- build / concatenate html string
      set html to html & "[img alt=\"\" src=\"" & name of imagefile & "\" width=\"" & W & "\" height=\"" & H & "\" /]
      close img
    end tell
    end repeat

    set the clipboard to html
    display dialog "html for " & length of filelist & " images copied to the clipboard!"


    (I changed the angled brackets to square ones to prevent the code from parsing on this page.)

    To combine the flag images into the single image for the sprites, I used  This site also generates all your HTML and CSS automatically as it combines your source images into the sprite.

    Faster mobile JavaScript click responses with fastclick.js

    Michael Brown  April 10 2014 04:39:07 AM
    As I pointed out in my post Speedier responses for iPhone web apps a couple of years ago, it's a little known fact is that iOS devices, and older Android devices too, are slow at responding to JavaScript click events.  This is because they have a built-in 300ms delay, due to them needing to respond to other types of tap, such as double tap (to zoom), drag and pinch to zoom.

    That 300ms might not sound like a long time, but it is noticeable when you're clicking web page controls that triggers hides and shows etc with JavaScript.  I'd say it's one of the main reasons why so many web apps seem so sluggish when compared to native iOS apps.

    Here's a sample page to demonstrate the issue:

    Open it on an iPhone or iPad and start tapping on the radio buttons.  Notice the short delay before the box colour changes?  Perhaps not.  Okay, so try this page instead:

    Much faster to respond to the radio buttons than the first page, yes?

    If you don't have an iOS device to test with, then I've done a video capture of my accessing the two pages with my own iPhone.  (The white circles that you see, correspond to my finger tapping on the screen.)

    There's only one difference between the two pages: the second page has the fastclick.js library loaded.  This library does some behind the scenes re-mapping of click events, so you can get that speedier response time without having to rewrite your click events to touchstart or touchend events, as I'd recommended in my original post.  (Using the touchstart event has the disadvantage of disabling drag for the element on which you have it set.)

    When, hopefully, the whole 300ms problem is fixed in a later version of iOS - as it already appears in more recent versions of Android - then all you have to do is remove the fastclick library from your apps.

    Serving HTML5 Video from Domino

    Michael Brown  February 14 2014 01:00:25 PM

    I'm looking at rolling out HTML5 video for a site that I'm working on.  The site is made up of Notes documents, and I would be storing the video files on Rich Text fields within those documents.  I last looked at this about six months ago, and well, things in the HTML5 Video world were something of mess.

    Six Months Ago

    There are three HTML5 formats:
    • H264 (.mp4 file), favoured by Microsoft and Apple
    • Theora (.ogv file), favoured by Mozilla
    • VP8 (.webm file) favoured by Google
    If you looked at the W3 Schools' HTML5 Video page, you would seen the major problem with the whole thing:  there wasn't a single one of those file formats that was supported by all 3 of the major browsers!  Furthermore, Internet Explorer requires at least version 9 to support any kind of HTML5 video, and my site needed to support IE7 and IE8.  So, we would have been forced to keep at least two versions of our video files converted to cover the big three browsers, plus a JavaScript/Flash fallback for IE8 and earlier.  I decided to keep using our Flash/JavaScript video solution, which has the major problem that it won't play on iPads or iPhones.


    Look at that W3 Schools' HTML5 Video page now though, and you'll see that there's been some major movement: Firefox now supports H264 .mp4!!  Only on Windows, and then only Windows Visa or higher at the moment, although Mac and Linux is supposed to be coming (maybe XP as well?)

    The second major change is an internal one: my site no longer needs to support IE8 or earlier.  So, yes, that means we can use only one file format!! .mp4 saves the day!

    That's when I ran into problems.  The videos would play on some browsers but not others.  

    MIME Type

    If you have such problems, then you need to check your MIME types are set up correctly for HTML5 video on the Domino server.   If the MIME type is missing on your Domino server, then you'll likely see the video as something like "application/octet-stream" in Chrome:
    MP4 with missing MIME type

    For .mp4, the browser should show a MIME type of "video/mp4" as shown below (in Chrome):
    MP4 with correct MIME type

    To fix this, you need to have your friendly Domino admin edit the httpd.cnf file, which should be somewhere in your server's Domino folder.  For .mp4, you need to add the following line to the that file:

    AddType .mp4 video/mp4

    Your admin will need to restart the HTTP task after saving the file.  (I don't think a refresh is enough.)

    Apple iDevices

    That fixed things on the desktop browsers, but there was still one major problem.  My .mp4 files wouldn't play on iPhones or iPads.  It worked fine on desktop, and most annoyingly, on a test Android phone!  On the iPhone though, it just showed with a line through it, and refused to play:
    MP4 video won't play on iPhone

    As iDevice compatibility was one of the big pay-offs for doing this project in the first place, so I had to simply get it working.

    At first, I thought it must be something to do with the video file encoding.  Apple's devices are very fussy about the .mp4 encoding for HTML5 web video.  It has to be H264 encoded for video, with AAC for audio.  But I couldn't get that to work on our internal network.  Oddly enough though, the same video file was served up fine to me iPhone by my own, personal Domino server.  Was it the company network messing things up then?

    Nope, it was something far more dumb than that.  It was Domino compression.

    Don't Compress Video in Notes!

    When I was adding the .mp4 files to my Notes Rich Text fields, I was doing it dragging and dropping them from the Windows File Manager.  But if you do that, the files are always compressed.   This was pointless because these kind of files are already compressed up to the eyeballs before they reach Domino.

    I knew all this, but didn't think it could possibly be the problem.  Almost out of desperation, I deleted the video from the Rich Text field, then reattached it using the paperclip icon, remembering to untick the Compress checkbox as I did it.  Bingo!   My .mp4 file now plays fine on my iPhone:
    MP4 video ready to play on iPhone

    Why this should be the case, and for iDevices only, I'm not really sure.  My guess is that when Domino serves up a compressed file, there's a short delay while the server decompresses it, and the iPhone is being over sensitive to that delay.