We can think of our regex as comprising three subpatterns. In the first, we use noncapturing parentheses and a trailing ? to specify an optional match:
(?:; ([^;)]+) Build\/.*)?
This pattern will match the build ID (for example, KFTHWI Build), if it's available. The inner parentheses capture one or more characters that are not ; and ). Thus, these parentheses will capture KFTHWI or another build ID. The entire pattern group needs to be optional because 1st Generation Kindle Fire devices don't have a build ID.
Following this first subexpression is a pattern that matches the Silk browser version:
\bSilk\/([0-9._-]+)
The character set to be captured includes digits, dot, underscore, and dash, with which we can capture either the browser version (for example, 44.1.54).
The final pattern is comparatively straightforward:
\b(.*\bMobile Safari\b)?
We match the string Mobile Safari, preceded by any character 0 or more times. If Silk requests a mobile view, the user agent will include the string Mobile Safari. So this final pattern does exactly what you'd expect: It identifies the browser as a mobile client.
To access the captured substrings, we can use the array object returned by the exec() method. In our example, we call .exec(navigator.userAgent) on the entire regular expression literal. The exec() method tries to match the regex object against a string passed in as a parameter. In this case, the string to be matched is the user agent object (navigator.userAgent). The exec() method returns the captured matches as elements of an array. In our example script, we use the returned array elements to build a string for an alert message.
if (match) {
alert("Detected Silk version "+match[2]+" on device "+(match[1] || "Kindle Fire")+" in mode "+(match[3] ? "Mobile" : "Default (desktop)"));
}
We use logical OR || and the conditional operator ? to provide appropriate default values in case of nonmatches. Of course, if you're doing user agent detection in a production website, you probably want to do something other than call the alert() method.
To learn more about the Silk user agent, see User Agent Strings and Detection (p. 15). To learn more about regular expressions in JavaScript, see Regular Expressions and RegExp at the Mozilla Developer Network.
Create Drop-down Menus for a Touch Screen
Because Amazon Silk runs on a touch-screen device, it doesn't handle the CSS pseudoclass :hover the same way that a desktop browser does. On a desktop browser, :hover becomes a match when you move the pointer over an element on which :hover is set. This behavior is useful for drop-down menus, as you can create a menu that's hidden until the user hovers over the parent element. But on a touch screen, this sort of hover-based menu design can lead to problems.
Let's look at an example. The following HTML document contains two unordered lists, one nested within the other. Each <li> element contains a link.
Create Drop-down Menus for a Touch Screen
<html>
<head>
<link rel="stylesheet" type="text/css" href="dropdown.css">
</head>
<body>
<div class="nav">
<ul>
<li><a href="http://example.com/">Home</a></li>
<li><a href="http://example.com/">About</a></li>
<li class="more"><a href="http://example.com/">Nav</a>
<ul>
<li><a href="http://example.com/">Item 1</a></li>
<li><a href="http://example.com/">Item 2</a></li>
<li><a href="http://example.com/">Item 3</a></li>
</ul>
</li>
<li><a href="http://example.com/">Contact</a></li>
<li><a href="http://example.com/">Press</a></li>
</ul>
</div>
</body>
</html>
By applying CSS to this markup, we can create a simple drop-down navigation. Here's our style sheet:
div.nav ul {
background-color:#335A7F;
width: 110px;
}
div.nav ul li a { color: #FFF;
text-decoration: none;
}
div.nav li:hover {
background-color: #4C88BF;
}
div.nav ul li ul { display:none;
}
div.nav ul li:hover ul { display: list-item;
position: absolute;
margin-top: 14px;
margin-left: -15px;
}
div.nav ul li:hover ul li {
Create Drop-down Menus for a Touch Screen
float:none;
}
div.nav ul li ul li:hover { float:none;
background-color: #66B5FF;
}
li.more:after { content: "\00BB";
float: right;
margin-right: 7px;
}
Notice how the display property is used. First, we use display:none to hide the nested <ul>, and then we use the :hover state to trigger display:list-item, which overrides the first display and shows us the nested <ul>. The result, rendered on a desktop browser, is shown below.
A single <li> contains both a hidden list and a link. To display the drop-down menu, you hover over the appropriate <li>. To follow a link, you click the <a> element within the appropriate <li>. In other words, you need to register two different events under the same parent element. This works fine as long as you're using a mouse, which supports both hovering and clicking. But Silk relies on a single gesture—a tap—to represent both hovering and clicking. As a result, a user might tap an element with the intention of showing menu items, and the effect would be to follow the link. That's a potentially frustrating user experience.
There are several ways to avoid this problem. One possibility, given the prevalence of touch-screen devices, is simply not to use menus that are dependent on a hover state. Another option is to detect touch-screen devices and then deliver a different, touch-optimized menu. Similarly, you can use scripting to alter the way that the menu responds to touch events. Superfish, a jQuery plugin, provides such a solution.
In the following example page, which is distributed by Superfish and is shown here rendered by Silk on a Kindle Fire HDX, the drop-down menus open on tap.
Create Drop-down Menus for a Touch Screen
To follow a top-level menu item (for example, menu item 3), you'd tap it a second time. On a desktop browser, the drop-down menus unfold on hover, and you follow links by clicking. Thus, the menus are navigable on both touch-screen and desktop browsers.
Superfish is just one option among many, and it may not be the best solution for your site. The point is that it's important to create drop-down navigations that provide a good experience for both desktop and touch-screen visitors. To do so, you'll need to ensure that the :hover pseudoclass is not hiding content from touch-screen users.
For more on drop-down menus and touch screens, see the following resources.
Additional Resources
• Touch and Mouse: Together Again for the First Time
• Mozilla Developer Network :hover