Project 3 writeupEdit
Scrolling through a long webpage can be awkward, and forces the eye to jump around from one location to another, as the location of various elements change. Similarly, many webpages want to display long lists by breaking them up into a series of pages connected by next page and previous page links. These links are difficult to find, and usually have a small target area.
The purpose behind this project was to improve this experience through keyboard shortcuts without needing to drastically change the page itself. The interaction allows you to navigate through a set of specified elements in a page through keyboard shortcuts that scroll to the next and previous elements. In addition, you can also navigate between one page and the next through keyboard shortcuts.
The aim was to make the interaction as modular as possible, so that keyboard shortcuts can be added to any webpages, regardless of how they are structured, by including a script and calling a few functions. Everything is done browser-side, rather than server-side. I chose this because it allows you to run the script from the user side, if you use a particular site often and want to add your own shortcuts without waiting for the site's owner to add it. This can be done through Greasemonkey on Firefox.
In terms of performance, it makes more sense for this interaction to be implemented server-side because iterating through the elements and modifying the DOM tree for each additional element is inefficient. Thus, pages that are static on the server would benefit from adding the keyboard shortcuts feature before they are served. However, dynamically generated pages (which are the most frequent type) would benefit less from doing the computation on the server side, since the user still has to wait for the server to finish the computation. Since the target for this interaction is mainly webpages that display long lists of items, most of these would fall under the dynamically generated category.
How To Use (User)Edit
j - next element (post, image, etc) k - previous element n - next page p - previous page
When the user is focused on a text area or an input box, keyboard shortcuts are disabled. This is to avoid accidentally triggering the keyboard shortcuts when the user intends to type.
The current element is tracked by a global variable, so it will ignore any manual scrolling by the user. It is possible to find the element that the user is currently at by comparing the window location to the boundaries of elements through the DOM and scroll to the next/prev element relative to that. However, this would need to be done each time a scrolling keyboard shortcut is used. This would not scale well to a webpage with a large number of elements, and reaction times would be slower. Therefore, I chose to not add this as a feature.
How To Add To a PageEdit
Before using KeyboardNav, the script file needs to be included:
There are two options for adding navigationg by page. The first is specifying a link element by their ID:
Another method is to specify the link element by class name:
In order to add navigation by post, you first add a series of elements by tag name, class name, or ID prefix:
kn_addElementsByTagName("img"); kn_addElementsByClass("date"); kn_addElementsByIdPrefix("comment");
These functions can be called any number of times, if you want to specify many different elements. When the user navigates by element, the scroll will stop at each of the specified elements in the order that they appear on the document, not in the order that they were added in. When this is finished, the navigation needs to be finished off with:
The last navigation method is for a custom order of navigation, rather than in document order. This allows you to specify, for a particular keystroke, what element it will navigate to, given the current element.
1. Add elements using the same functions as in navigating by page, and finalize.
2. Create arrays such that
A[i] is the destination element's index, when the current element has index
var one = new Array(1, 2, null, 5, 2);
A[i] to the desired keystroke.
For this example: pressing the '1' key at element 0 will advance to element 2. If the current element is index 1, then it will advance to element 2. At index 2, pressing '1' will do nothing because the entry is null. Also, if the array is too short and the index of the current element is not defined in
A, no change is be made.
There are a couple of ways to customize the behavior. The first is to customize the keyboard shortcuts that are used for next/previous elements/pages:
kn_setNextElementKeystroke("f"); kn_setPrevElementKeystroke("b"); kn_setNextPageKeystroke("g"); kn_setPrevPageKeystroke("h");
The animation for scrolling down the page can be changed as well, if the animation is not smooth enough. To change the number of steps (increase to make the animation smoother):
To make the animation last longer, increase the length of time (given in milliseconds):
To disable the keyboard shortcuts on any tag elements that are not included in the disabled list (
textarea), you can specify elements by tag name, by calling:
For navigating by post, the script works by wrapping each specified element in a new div, with a special class name (which is prefixed by "kn_" to avoid collisions). When kn_finalize() is called, the elements of that class name (the wrapper divs) are all assigned a numbered ID, in the order that they appear in the document (where the prefix for the ID also starts with "kn_"). A variable tracks the index of the current element. This index is incremented/decremented when the next/previous element keyboard shortcut is triggered. It then looks for an element with an ID that matches the index (using getElementById() through the DOM), and the window is scrolled to the top left coordinate of that element. If an element with that ID does not exist, then no scrolling occurs and the index is reset to its previous value.
The keyboard shortcuts are handled by a function that is bound to window.onkeypress. It checks the character of the key against the set keys, first for the navigation in custom order, and then for navigation by page and post, so that navigation in custom order can override the keyboard shortcuts for the other two methods.
The scrolling is performed through the window object, based on the location of the destination element and the current scroll location of the window. It uses a series of timeout functions to animate the scrolling as a series of steps where smaller scrolls are performed.
From the user's perspective, this type of keyboard interaction is easier and less tiring to use than scrolling through many items on a page. Next/previous page links are often at a different place for every webpage, making it hard to find it. The links can also be very small, and they appear frequently as just a ">" image link, which is a tiny target for a mouse click. Rather than searching for the navigation links every time, the user can navigate much more quickly by using the keyboard shortcuts.
From the web developer's perspective, this implementation of the keyboard interaction is easy to add, requiring only a few function calls once the keyboardNav.js script is added. In some cases, changing the way that a dynamic webpage is generated may not be easy or trivial, so having the flexibility of specifying elements in a number of different ways makes it easier to use. It also takes care of minor details, such as disabling the keyboard shortcuts when the user is typing in a text box, and animating the scrolling.
The main weakness is that setting up for the interaction is slow, particularly if the page is a large one (in terms of number of elements). As discussed above, this may be alleviated by moving the computation to the server side, but not necessarily.
Another weakness is that the interaction is invisible to the user, since the user would not know about the presence of the keyboard shortcuts unless they accidentally pressed a key. This is fixable by adding a popup to the page with a legend of what keyboard shortcuts are available.
The script itself resides at http://www.stanford.edu/~jingc09/KeyboardNav/keyboardNav.js.
Here is an example of navigating by page and navigating by post. This example only goes up to page4, but the back and forward are set up for all of these pages. The navigation by post is set up to stop at the date, h2 elements, and images.
Here is an example of navigation in custom order. The text in this example was taken from here. To avoid setting up an exponentially large choose-your-own adventure tree, the results from certain actions were not included. In that case, pressing the corresponding key will not do anything.