Skip to content

Mobile

Battery Status API experiment

Screenshot of JavaScript battery API experiment
Battery UI element

The JavaScript Battery Status API offers some interesting additional functionality that we can leverage for UI elements. Browser support is getting better—at the time of writing (Feb, 2017), Chrome, FireFox and Opera are good to go, but leaves glaring omissions of Safari/iOS.

This little experiment creates a simple battery UI element, with its background an indicator of battery percentage remaining (plus percentage text): CodePen Experiment

The API provides a bunch of events we can hook into:

  • chargingchange – is the battery charging?
  • levelchangepercentage of battery remaining
  • chargingtimechangeamount of time until battery is charged (estimate)
  • dischargingtimechangeamount of time until batter is discharged (estimate)

All we need to do is check that we have support for the API and off we go:

navigator.getBattery().then(function(battery) { ... });

Once we know we have battery API support, we can go ahead and add some listeners for the new events and update our UI as we need. Note, we don’t use any libraries here, this is raw JavaScript:

const $batteryPercentage = document.querySelector(".js-guage");
const $batteryPercentageDisplay = document.querySelector(".js-percentDisplay");
const $batteryStatusDisplay = document.querySelector(".js-statusDisplay");

navigator.getBattery().then(function(battery) {
 
 function initBattery(){
   updateChargeInfo();
   updateLevelInfo();
 }
 
 battery.addEventListener('chargingchange', function(){
   updateChargeInfo();
 });
 
 battery.addEventListener('levelchange', function(){
   updateLevelInfo();
 });
 
 function updateChargeInfo(){
   let _batteryChargeStatus = battery.charging ? "Battery Charging" : "Battery Draining"; 
   $batteryStatusDisplay.innerHTML = _batteryChargeStatus;
 }

 function updateLevelInfo(){
   let _batteryLevel = Math.round(battery.level * 100) + "%";
   $batteryPercentage.style.width = _batteryLevel;
   $batteryPercentageDisplay.innerHTML = _batteryLevel;
 }
 
 initBattery();

});

What could we use the Battery Status API for?

  • Intensive or full-screen scripts could warn the user if the battery was low before beginning, such as Canvas, WebGL or media handling.
  • Coupled with up-coming CSS selector prefers-reduced-motion we could trigger low-animation CSS when the battery is getting tight.

Details of support for the Battery Status API can be found on Can I Use.

Responsive navigation UX experiment

Mobile navigation frequently consists of a burger menu placed in the top right of the viewport. But consider this: a user with a large phone using just one hand, can their thumb stretch that far? This is particular issue on the larger format phones such as an iPhone 7 Plus.

Some of the UX niggles in mobile navigation:

  • Awkward one handed navigation
  • Fiddly menu and links
  • Inappropriate menu items for context of device
  • Little room for styled menus or call to actions

The following experiment explores an alternative to the hamburger menu, with a focus on improving the UX. I’m using a tiny bit of JavaScript to handle the mobile navigation toggle, but the layout is entirely through CSS.

Screenshot of mobile menu opened (links to demo CodePen)
Mobile UI

The experiment

  • Move the navigation to the bottom. By placing the menu toggle where it is easily reached in one-handed use. It also keeps the navigation controls for your site close to the control UI provided by most mobile browsers (bottom of the web view).
Screenshot of mobile menu
Mobile, menu located at viewport bottom

We reposition the menu with CSS, meaning the underlying HTML document remains logically (seminally) ordered for screen readers and document parsers.

Screenshot of desktop menu
The same menu, but on a desktop

Ultimately it’ll be worth considering an additional breakpoint for portrait tablets—one that follows a more traditional burger pattern. Why? Tablets are generally not held in one hand, but the screen remains practically too small for the full extent of a desktop-ish navigation. A combination of burger + shortened desktop menu could work here, but that would require a JavaScript solution based on viewport width (which is less attractive).

  • Leave the brand where it is (top). We don’t want to waste our precious mobile screenspace, so we avoid making it “sticky” or “fixed” or anything else that obscures the content. In this example the brand is fairly large, but we should try to keep it small and out of the way. On visiting a site on a mobile, I want to know what that site is about quickly and without scrolling, so lets promote the content and not waste screen space with branding.
  • Screenshot of expanded menu
    Mobile, menu expanded

    Tiles, not links. Links can be hard to tap on a mobile. We can significantly increase the hitbox for each menu entry by making them tiles. This also provides a lot of opportunity for branding or colourful styling—but not at the expense of a clear, readable label.

  • You don’t have to show everything. I’ve noticed many mobile menus try to show all the things, which may not actually be that useful for different devices. Why not hide the menus we don’t want? In this experiment, we can tag menu elements with menu-item--hide-desktop class to hide (natch) content from the desktop. We could equally do that for mobile.
  • Don’t be afraid to repeat links, sometimes it’s fine. Here, I’ve taken what I think are the three most important menu entries and explicitly called them out as additional ’tiles’ to display along side the mobile navigation button. Quick access for the user, without distraction.

What’s next

This experiment could be taken much further if we start introducing more JavaScript. I’ve also barely touched on accessibility, but this experiment is ‘fairly accessible’. There are additional tricks that I’ll address in some future post. Best tip, fork the demo on CodePen and have a play.

View this experiment on CodePen.

Dev notes

Encountered a strange issue with Safari while building this one. An absolutely positions display:fixed element (the mobile nav, viewport bottom) was not being rendered at all. Chrome and FireFox were displaying the menu perfectly. This was due to Safari ignoring width: 100% on the menu wrapper. Replacing width with left: 0; right: 0 resolved the issue.

This experiment is reliant on flexbox (display: flex) support in your browser. These days that covers most browsers, but if you do need to support older browsers, consider adding a fallback to CSS tables.