Clicking Off Things to Close Them

There’s a common design pattern these days where a bit of content is shown over the main screen. It might be a modal window or maybe a fly-in menu or sidebar. It’s also common, especially in native apps, that we can just click or tap in the space not used by these elements to close them. So, how can we do this?

I think there are 2 approaches, one which is pure JavaScript and another which involves an overlay element. Let’s look at both.

JavaScript Document Click Event Method

We can detect that a click is not on the content element using JavaScript. As all click events bubble up or propagate through the DOM tree they eventually reach the top document level. We can listen for a click on the document and then use the event target to check what was clicked. For this example let’s assume our content element has a class of ‘modal’, like <div class=”modal”></div>.

// JavaScript

function handleClick(event) {
  if (!event.target.closest('.modal')) {
    console.log('close');
  }
}

document.addEventListener('click', handleClick);

event.target gets the element that was clicked. This could be the modal element itself, another element inside it or another element outside of it. event.target.closest(‘.modal’) checks if the element clicked is the modal or is an antecedent of the modal element, an element within it. If the element clicked is not (!) in the modal we can close it.

It’s maybe worth noting that .closest() doesn’t work in IE11 if you need to support this but there is a polyfill available.

Using an Overlay Element

The other approach, and the one I tend to use, is to use an overlay element. This means adding an element that covers the whole screen area, slipped in between the modal and the main screen content. The idea is that this overlay will appear and disappear along with the modal and will pick up any click events which are not on the modal. It’s a bit like a safety net that will catch any stray clicks.

The CSS for the overlay would typically look something like this:

/* CSS */

.overlay {
  background-color:#000;
  bottom:0;
  left:0;
  opacity:.5;
  position:fixed;
  right:0;
  top:0;
  z-index:1;
}

.modal {
  /* styling */
  z-index:2;
}

The overlay has fixed display and goes to each edge so it fills the screen.

The overlay has z-index set to 1 so it’s over the main screen content, and the modal has it set to 2 so it’s over the overlay. These can increase as needed but the modal always needs to be higher.

I’ve given the overlay a background colour and 50% (.5) opacity so that it veils the main screen content underneath giving the modal a “lightbox” effect but these are not needed and our overlay can be effectively invisible.

You then just add a click event to the overlay which will close the modal and hide the overlay.

The reason I like this approach is that by covering the main screen we prevent any interactions with it. If the user tries to click on a button under the overlay their first click will just close the modal. We don’t need to worry about any other interactions – while the modal is showing it becomes the sole focus.

Extra tip. If you use a visible overlay it’s nicer not to show and hide it immediately but fade it in and out with a transition on the opacity, taking it between 0 and .5. This feels much smoother and less jerky.

Google Maps – The Bits They Don’t Tell You

I’ve done quite a lot of work with the Google Maps JavaScript API in the last year or so. I think I’ve picked up quite a bit along the way, which you won’t find in the official reference guide.

When I first started working with it, one of my favourite things was the excellent documentation that came with it. Sadly, since the shift to Material Design, it’s now very difficult to navigate and find anything. In fact, I’ve pretty much given up on it. It’s a lot easier to just use Stack Overflow.

Here are some fairly basic things I found, which, depending on your project, might make life easier.

Use a map object
Using an overarching object to hold anything map related – data arrays, functions, etc. really helps when you’re using dynamic data or lots of other JavaScript. It’s basically just a namespace, package or module.

Push overlays into arrays
When you add any overlay, for example a marker or polygon, the normal process is to read the geo data out of an object or array and use it to add the overlays. However, if you then want to interact with those overlays you have no way of selecting them. When you create an overlay push it into an array. That way you can loop through the items or select one by its index.

Add key or id property to get an overlay easily
In addition to adding an overlay to an array you can give it its own custom property like an id or key so that you can select it without knowing its index. The Google Maps overlay objects, which can have properties like fillColor, map, position, etc. are actually just JavaScript objects so you can add your own properties. You can then use filter() to access an individual overlay from the array or you can alias it with a variable.

Use polygons appropriate for zoom range
If you define a polygon it will work at any zoom range. For your map usage it’s worth considering if you need to allow the full zoom range to be used. It might be easier to limit it. Imagine a polygon for the outline of France. If you’re zoomed right out, looking at the world you can get away with just a hexagon shape. If you zoom in close you need to pick out each little twist and turn in the coastline. See what you need and use simplified polygons for speed and performance where possible.

Use dynamic SVGs as icons
You can use your own image files as markers instead of the standard pin. However, these don’t have to be static image files. You can create your own function which takes parameters for colours or values and uses these to return an SVG including these details. You can then set this function as the icon image.

Set bounds and extend them
When you create a map, also create a bounds object. This holds location data for the top right (NE) and bottom left (SW) of a box, which determines the portion of the map shown on screen. It manages the zoom level for you. Whenever you add a new overlay to your map you can extend these bounds so that all of your overlays will always be shown.