Prototyping with SVG

Our guide to overcoming the issue of on-screen keyboard implementation with SVGs.

During a project we needed to implement an on-screen keyboard. We first went into the obvious direction and looked for libraries that would allow us to implement this easily. However, after reviewing the possibilities, we found all of them had one problem: they already included styling very much different from our design vision. And as anyone who has been using Bootstrap knows: overwriting styling in CSS is a pain.

Then we had a revelation! We already had the designs, we just needed to put them into the browser. This "just" has been a problem of web design for decades, but in this specific case there was an easy solution: SVG.

To make this a bit more hands on, we will reimplement the iPhone lock screen with SVGs. We will move this from a relatively straightforward use of SVGs to wrapping it in an AngularJS directive. The advantage of that? By encapsulating parts of our screen, we can later switch out the implementation without affecting the rest of the screen.

Step 1: An SVG for the whole screen

So let's get started! Download the free template and export it as SVG. There are three ways to use SVGs in a html page:

  • Using an image tag <img src="/image.svg" />,
  • As background image in CSS .lockscreen { background-image: url('image.svg'); } or
  • Inline in the document <div><svg …>…</svg></div>.

​Pasting the image inside a page at first might seem rather dirty but it has one big advantage: elements are part of the DOM, which means elements inside the files are accessible via JavaScript and CSS.

Yet, when we take a look at our SVG, we see that the elements are grouped by styling and not by logical groups. Why is this a problem? A naive approach would be to just look at the target property of the event. This will give us the node that was clicked or touched. We could then look at the content of that node (e.g. "2") and then use that as output. However, there is one problem that becomes more pronounced when testing this with touch: when the interaction event is on the circle or on text like "abc", we would expect the button to still be pressed. But by using this approach it won't, the target would be a circle or a tspan with a value of abc. We would need to introduce a lot of checking and mapping elements to values:

  • If the click hits "abc", we need to map it to 2, etc.
  • If the click hits Circle_2_2, we need to map it to 2, etc.
  • If the click hits Circle_1_2, we need to map it to 2, etc.

To make our lives easier, we will need to change the SVG's structure.

For the editing we open it in Illustrator or Sketch and group the items logically. (There are some caveats when using Illustrator: Illustrator has problems; e.g., exporting blur effects and renders them as images. This is not only a problem for our SVG workflow but also changes the look of it slightly.)

Now that we have a logical grouping, we just paste the file into a CodePen. Our strategy will be to walk up the DOM tree until we find an element that has an ID that starts with "Button-".

See the Pen Prototyping with SVG - Step 1 by Marten Biehl (@martenbiehl) on CodePen.

Step 2: Styling SVGs with CSS

There is still one problem: if the touch events hit the empty space between the circle and the number, our current algorithm says the element we clicked is the background. The most straightforward strategy now would be to just edit the SVG again and add a square that acts as a catcher below. However, there is a quicker way: by setting the fill of the circles to transparent, they now register as surfaces for the click events.

#PASSCODE circle[id^="Circle"] {
  fill: transparent;
}

With this CSS selector we select all elements whose ID starts with "Circle" and which are children of the element with the ID "PASSCODE". This way we select all circles of buttons but not the circles that are below the enter passcode text and not the reception circles in the status bar at the top.

This was just CSS to make our prototype work better, now for the next step: make our screen react to the inputs and fill the circles at the top. For this we will use the same strategy as with our CSS fix. We will assign classes based on how many elements have been pressed to change SVG properties.

See the Pen Prototyping with SVG - Step 2 by Marten Biehl (@martenbiehl) on CodePen.

Now we're done with our first version, we can do a quick usability test and find out if there are any issues with the design. To recap, we were able to use a design right out of Sketch and Illustrator. We had to regroup the layers a bit but only to do a logical grouping, we did not need to introduce extra elements. If a file is structured in a logical way there should not be an issue.

Step 3: Build components out of the SVG

Now imagine the test results come back and all is good. We just need to add some feedback for wrong codes and go to the next screen if the code was correct.

Yet, if we continue working in the current way, implementing more screens will quickly create issues: we don't really have an application structure, all of our code is global and not extensible. We are using SVGs to style the whole way but SVGs exported from Sketch and Illustrator are not accessible. We will have to inline all SVGs for all states into our current setup, so even if a user will not go to a certain state they have to load all of them. This won't work.

So how do we proceed? We could now just rewrite the whole screen in HTML and CSS, or we can refactor! We are going to create components out of the elements on our screens. This will allow us to continue using SVGs where feasible and encapsulate the state. For this we are using AngularJS but the same approach can be used with React or Angular 2.

Let's go!

We split up the SVG into five parts:

  • Status bar
  • Passcode
  • Buttons
  • Bottom
  • Background

We then create AngularJS directives for the passcode and for the buttons. Instead of pasting the SVG code of the compenents into the file, we will add them as templates. This way we can use them as normal directives and no one who uses them needs to know that they only consist of SVGs. This way we have a defined API and if we decide to switch the SVG for HTML and CSS we can do so without breaking anything.

See the Pen Prototyping with SVG - Step 3 by Marten Biehl (@martenbiehl) on CodePen.

Pros and Cons of this approach

Compared to using a combination of Sketch and Framer, this probably looks a bit rough. However, this approach has one big advantage: we can actually try out multiple designs very easily and then turn one of them step by step into production ready code. It is very important to not be too attached to your work, but on the other hand reducing waste is even more important!