Before and After Image Viewer Part 3b: Exploring Adding Touch Interactivity

Published Jul 11, 2023
Updated Jul 11, 2023
By Simon

This is only an iOS solution that ends up being an Android solution. Read on to find out how to make this work on both iOS and Android.

This article is part of series on how to make a before and after image viewer. If you arrived here from a search  engine then you might be better jumping back to a least part 3a. Follow the link below to get there.

See part 3a for instructions on where the code is kept and how to get it. 

If you want to get the code from where I left off, you'll need to checkout Commit: [basic-touch-with-hover cd52667] switch mouse events and event properties to touch

Welcome back!

If you have been following along then you'll know where we are at. But just for a refresher we have been making our before and after image viewer work on touch screens using touch events. To do this we used the viewer from parts 1 and 2 which is desktop specific and uses a hover pseudo-class to show the handle controller when you hover over the active area. However, this setup causes some issues on touch which we are currently working our way through.

The issue with the way it is currently set up is that the element that is used to adjust the width of the top image, the handle, is set to display none when the document is loaded.

If you test what we have just done you will notice that hover is triggered on touch but you then need to touch a second time to make it useable. This behaviour is not what we want and is something we will fix. So let's do that now.

My idea around this, for now, is to add a message on touch screens to get people to touch the screen to initiate the touch functionality.

How to add a message for usage on small screens and touch screens using media queries

Let's fix it or at least make it usable for now.

Touch event and hover fix

The solution or you could say a workaround, is to touch the screen once for touch devices. For this reason, I decided to add instructions on a help screen. I did this by adding an overlay for smaller screens.

First, add the HTML for the overlay.

 <div class="mobile-initiation">
    <div class="mobile-initiation-inner">
      <ol>
        <li>Touch the Screen to Initiate Slider</li>
        <li>User Green bar to reveal and hide</li>
      </ol>
    </div>
  </div>

I add the code at the bottom of the page markup. It has 2 divs and I have added classes to the divs. 

  • The first div will cover the whole screen but you could make it only cover the image viewer (something I will do in a refactor). We add the width and height with CSS in the next step.
  • The inner div has instructions on what to do.

Next, we need to add the CSS.

  .mobile-initiation {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding-top: 40px;
  }
  .mobile-initiation-inner {
    width: 240px;
    height: 60px;
    padding: 0.5em;
    color: black;
    font-size: 0.8em;
    background: rgba(55, 184, 34, 0.90);
    border-radius: 2px;
    box-shadow: 1px 1px 1px black;
  }
  .mobile-initiation-inner ol {
    list-style-position: outside;
    margin-left: -15px;
  }
  • The CSS of the first div positions the whole component and makes it cover the full screen. It also uses flex to centre the inner div on the horizontal.
     
    • I add the top: 0 to remove the scroll bars.
    • I needed to add padding to the top since the main element has a margin.
      Since the wrapper div covers the full screen I couldn't use flex align-items center as on screens that have larger vertical size than horizontal the inner div will drop below the image. We will fix this is a re-factor.
       
  • The second div is then positioned and styled.
  • Finally, I add a bit of styling for the ordered list.

Using a media query to restrict the display to any device under 1001px

This will show on all screens so let's now add a media query for small screens. I used 1000px as the max-width which in fact might not cover all touch devices. But let's go with it for now. Wrapper the above code in the media query.

@media screen and (max-width: 1000px)  {
}

However, if you view this on a desktop now all you have done is remove all the CSS from the component and it will show un-positioned and un-styled again.

Just above the media query add a rule to hide the component.

.mobile-initiation {
  display: none;
}

Good, but let's let's change the media query to something else.

Using @media(pointer: coarse) to better target touch devices

As such, using a media query for screen size isn't the best method as touch screens can be larger than the arbitrary size of 1000px I had used. 

Enter Media Query 4 pointer coarse!

To cover all touch screens we can use Media Query 4 pointer. It has 2 values; coarse and fine. For touch devices, we can use coarse as the finger doesn't have the same accuracy as a mouse.

@media(pointer: coarse)

Ah, that's better.

Commit your code and pat yourself on the back.
Commit: [basic-touch-with-hover c34bc4b] add mobile message HTML and CSS

Adding Interactivity with JavaScript to remove the message from the Screen on touch

Now we have a message on the mobile we need to remove when someone touches the screen. To do this we will use JavaScript.

First, we need to select the element that will be used to remove the message. This will be the outer wrapper.

const mobileInitiation = document.querySelector(".mobile-initiation");

Next, we need to create a function that is initiated using an event listener that listens for when the document is loaded. Add the document.addEventListener("DOMContentLoaded", function() {} event listener below the variables at the top of your JavaScript file. 

Inside this use a click or touch event to remove the element. I use click as shown in the code below.

document.addEventListener("DOMContentLoaded", function() {
  mobileInitiation.addEventListener("click", function () {
    mobileInitiation.style.display = "none";
  });
});

That's it, now when you touch the screen anywhere the message will disappear.

But you will notice that the handle doesn't appear. what's with that?

The issue is that when you touch the screen you are touching the cover we have added so you are having no interaction with the hover pseudo-class. There are 2 ways you could fix this. 

  1. Is to tell people to double-tap the screen.
  2. Add another line of JavaScript to make the handle appear.

Since hover doesn't really work on touch devices consistently, and we will always need to deal with turning on and off the handle element to get the same effect as the hover, I am going to go with the second option.

Add this one line to the click event.

  mobileInitiation.style.display = "none";
+ handle.style.display = "block";

Cool, now when you touch the screen the handle also appears and is ready to use.

It is this that makes this work on Android as well as iOS. On Android, the hover event only works when you touch the screen whereas on iOS it remains active. It kind of seems that the Android implementation of this is more correct but I did like the iOS implementation until I had to fix it for a client recently.

So that's it except for a small feature that is optional but I kind of like it. That is to turn off the handle so it does not cover the picture when you disengage with it. I feel this is a nice feature for the UI element no matter how it is designed, granted presently it is pretty obnoxious, as it takes away from the purpose of the component. 

Bonus: One small feature that might be nice is to disable the handle on touch-end (Coming soon)

Commit: [basic-touch-with-hover [e874835] Add JS to remove help message on mobile device

Summary

Even though I set up the code for screen sizes you will see that for touch I am also using the same logic in a whole new block. Yip that's right there is actually no correlation between the screen size and mouse and touch. Once finished I will see if I can re-factor the code but for now I think this is good as I have learnt something and if you are reading this so have you. That something might actually be useful knowledge and that's the idea.

Also, part 3b specifically looked at adding a message to the viewer to give guidance on how it works. This was a sort of workaround but this sort of feature could be added to the desktop as it may not be clear how the component works. 

Then, we looked at screen accuracy media queries to display the help message on screens that are primarily touch. And then we use JavaScript to remove the help message. 

Final Thoughts

This final solution still seems a little hacky and it is not fully tested on all devices, but it works. However, I wouldn't use this in a production environment and for now sitting here on design kojo as a way to help others learn from my mistakes and learning process is the best place for it.

In an upcoming article, I will re-factor the touch functionality to use a setup function on document load and I will remove the need to tap the screen to initiate the component but I will probably leave the message as I do feel this enhances the user experience. What do you think?

Well, that's it for now, If you want to be the first to know when I write about touch events be sure to sign up for the newsletter. I write about front-end web development and design. Thanks for reading and catch you soon.