Race Conditions

One commit at a time

Mobile Web App Prototyping With Flask

A big chunk of traffic for any modern web application comes from mobile devices and so developing with smaller screensizes and touch screen controls in mind is imperative when building a startup MVP. This was my first mistake when I started developing the visual colour search engine lipcolourmatch.com. As a developer my work environment is the desktop and so naturally the first iteration of the Flask application was built with the desktop in mind. However, most users of modern beautytech applications are on mobile and that share will probably only increase in the future. In fact, now, after running lipcolourmatch.com in production for over two months, the number of non-mobile visits probably account for less than a fifth of the traffic the colour search engine receives on a daily basis.

An additional complication is that my technical expertise prior to building lipcolourmatch.com was mostly in the domains of machine learning and data engineering, with a few large scale server side applications. I had never built, deployed and managed an external consumer facing application. Although a user is a user (whether an external consumer or an internal company consumer), there is usually more flexibility when working with internal users, because you are usually onsite providing support and seeing your UX disasters first hand (UX is important!). Given my experience is primarily busting out a commandline and my trusted Linux shell commands when things get hairy, many mistakes (of which not being mobile-first from the beginning) were made in the initial prototypes for lipcolourmatch.com. For the benefit of anyone else (or for future me), I’m writing up notes on mobile prototyping with Flask.

Using Different Templates for Desktop and Mobile

Interacting with a web app on the desktop is usually done with a mouse or the equivalent in assistive technologies, whereas interacting with an application on mobile usually happens through touch-enabled interfaces (for example a touch screen). This means that some elements which are easy to navigate with a mouse, can be extremely frustrating to do on a touch screen (or with assistive technologies - colour search engine accessibility is something I am still researching and I hope to write up my findings at a later time!). A prime example of this when it comes to colour search engines is the colour picker. Most open source jQuery colour pickers are meant for desktop interaction and come with very small “active areas” (the areas you’re supposed to click on to get the colourpicker to do what you want) and so are unsuitable for mobile.

Given these two different modes of interaction, it’s sometimes necessary to write two different Jinja templates - one for the mobile app and another for desktop users. This is probably not How One Should Do It In Production ™ and I’m still doing lots of research on how to approach building desktop+mobile webapps, but can be suitable for an MVP for beta users. After you have written up separate templates for mobile and web - you need to decide how to redirect requests from mobile clients to the mobile version and desktop clients to the desktop version.

A Flask extension that I found useful for this is Flask_Mobility. It detects whether the request is coming from a mobile user agent and redirects the request to the correct mobile template.

A given Flask view function normally only returns one template file, so keeping separate files for mobile and non-mobile user agents would mean lots of code duplication. However, Flask_Mobility provides decorators that allow you to specify the location of the mobile template. When the view functions detects that a mobile user agent is requesting a view, it will return the mobile template instead of the desktop template. In practice, when using Flask_Mobility, a sample mobile-desktop dual view function would look something like this

@app.route('/someviewfunc', methods=['GET', 'POST'])
@mobile_template('{mobile/}index.html')
def index(template):
    # your view function logic goes here
    return render_template(template)

Your mobile templates would go into templates/mobile and your regular desktop templates will stay in the templates folder.