The BlackBerry Bramble

BlackBerry 10 Developer Blog

WebView and HTML anchor tags

Anchor tags in HTML are a way to mark locations on a page that the browser can jump to automatically. If the name of the anchor is attached to the end of the URL after a pound character (#anchor), sometimes called an anchor hash, the browser will load the page, then scroll down so the location of the anchor is visible on the screen. Anchor tags look like link tags but have no “href” attribute, just an “id”. For instance, let’s say you have an HTML page like this:

The anchor tags here are topic01 to topic06. Anchors take up no actual screen space, they just serve as target points on the rendered page.

In this example I used nonsense text in each paragraph, but assume that on your real page each paragraph is considerably longer and that the full page is several times longer than your screen can display. If your user is on another page and follows a link that you want to take them directly to topic paragraph  #5, real browsers will do this if the URL they navigate to looks like this:

Note that older versions of HTML used the name attribute to identify anchor tags rather than id, but this was deprecated with XHTML1.0 and removed completely for XHTML1.1 and HTML5 in favour of id. This actually makes sense since an id must be unique on a page, whereas there can be many tags with the same name. WebKit based browsers such as Google Chrome and the BlackBerry 10 Browser will not jump to the anchor if you identify it by name. If you really want to play it safe in your HTML for even very old browsers that use the old syntax, you can always insert both attributes:

Note too that in this example I moved the closing </a> tag to the end of the paragraph. It makes no difference, the anchor will work the same way since the anchor navigation target is at the <a> end of the tag pair.

All well and good if you are using a real web browser, navigating to a URL with an anchor hash on the end will jump straight to the anchor. Unfortunately, though it is very powerful, WebView is not a full browser, and ignores the anchor hash completely. All is not lost however.

With just a little extra code in QML or C++ you can easily coax your WebView to honour the anchor hash and scroll correctly to the anchor location on the rendered page. The basic technique is to load the page, then check the URL for an anchor hash, and scroll to it with JavaScript if found.

When researching a solution for this, I found many, many online posts by JavaScript experts declaring that the way to make a browser scroll to an anchor with JavaScript is:

The problem with this is that it relies on the browser correctly honouring the anchor hash by itself, which we already know WebView doesn’t. All this does in a WebView is reload the page at the top as if the hash isn’t there. The real answer is slightly more complicated:

This JavaScript finds the element with the target anchor id, then scrolls to it. We can put this to work in our WebView like this:

We want to work our magic right after a successful load of the page so we put it in the loadingChanged signal handler then check for a successful load on line 4. Lines 5 and 6 are used to find the anchor hash, and line 7 determines if one was found. If there was an anchor hash on the end of the URL lines 9 and 10 extract it and then execute the JavaScript to scroll to it. Note that in this example the result of the JavaScript execution is stored into the token variable, but if you don’t care about this you can remove line 3 and the “token =” on line 10.

If you know for sure you will only encounter anchor tags identified by the id attribute, then you are done, and WebView will handle the anchor hashes just like real browsers do. However, if you might run into any older style anchors that are identified with the name attribute then you will need to use the following block of JavaScript instead:

In this case we first look for the anchor tag element by id, but if we don’t find it we search again by name. Notice the array index at the end of line 3. Whereas getElementById() always returns a single element (or null), the name attribute is not unique on a page, so getElementsByName() must return an array. By the time we get to line 4, element either points to the anchor tag, or is null, in which case the call to scrollIntoView() does nothing. So now let’s add this to our WebView JavaScript for a complete solution:

And there you have it! I won’t cover the C++ version of this method since I suspect the vast majority of developers will implement this in QML, but if you are building your entire app without benefit of Cascades everything described above can be done with pure C++ code instead. While extremely capable, WebView is not a full web browser implementation, but by adding a few lines of JavaScript you can make it handle anchor tags just like its big brethren.

Leave a Reply