emGee Software Solutions Custom Database Applications

Share this

Web Design

Search at Google I/O 2019

Google Webmaster Central Blog - Thu, 05/16/2019 - 09:12
Google I/O is our yearly developer conference where we have the pleasure of announcing some exciting new Search-related features and capabilities. A good place to start is Google Search: State of the Union, which explains how to take advantage of the latest capabilities in Google Search:

We also gave more details on how JavaScript and Google Search work together and what you can do to make sure your JavaScript site performs well in Search.

Try out new features todayHere are some of the new features, codelabs, and documentation that you can try out today:

Be among the first to test new featuresYour help is invaluable to making sure our products work for everyone. We shared some new features that we're still testing and would love your feedback and participation.
Learn more about what's coming soonI/O is a place where we get to showcase new Search features, so we're excited to give you a heads up on what's next on the horizon:

We hope these cool announcements help & inspire you to create even better websites that work well in Search. Should you have any questions, feel free to post in our webmaster help forums, contact us on Twitter, or reach out to us at any of the next events we're at.

Posted by Lizzi Harvey, Technical Writer
Categories: Web Design

SVG Web Page Components For IoT And Makers (Part 2)

Smashing Magazine - Wed, 05/15/2019 - 04:30
SVG Web Page Components For IoT And Makers (Part 2) SVG Web Page Components For IoT And Makers (Part 2) Richard Leddy 2019-05-15T13:30:16+02:00 2019-05-23T09:05:51+00:00

So, we already have ways of dynamically loading a menu of SVG icons made to react by loading panels if we so desire, but the icons were not actual components. We were able to use a simple trick of bringing in the SVG for each icon and passing it into the Vue application. It was simple enough to generate a list of icons, and each icon reacted in a similar way except for small data differences. The data difference made it possible to bind the name of a panel to each icon in such a way that the handler for the icon’s button click could pass it on.

When a panel is loaded in the form of Vue component, everything about the panel and its components has to be loaded, templates, JavaScript, and more. So, the job of just managing loading the panel is bigger than what we have encountered so far in this discussion.

Let’s look at Vue’s way of providing a hook for async loading. The following snippet is from the Vue guide.

Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // Pass the component definition to the resolve callback resolve({ template: '<div>I am async!</div>' }) }, 1000) })

The guide tells us that the setTimeout function is an example of how to use the synchronicity with Vue components. Notice that where before there had been an object as the second parameter to Vue.component, there is now a function, which is referred to as a factory function. Within the resolve callback is a component definition, that would have been the second parameter to Vue.component before.

So, I had to stare at this example a while before it made sense to me. Here is another example, which suits me better:

Vue.component('async-example', function (resolve, reject) { // Vue will call this function and promise itself to handle // it when it gets back with data. // this function can then call a promising object loader // here the 'loader' function is some abstract function. // Most likely the application will use 'fetch' // but it could be something else. loader('/my/resource/on/server.json'). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } );

It seems like the right thing to do to make a more general function to go around this form.

function componentLoader(c_name,resource_url) { Vue.component(c_name, function (resolve, reject) { loader(resource_url). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } ); }

So, in general, to load a component, we would just need a line like the following:

componentLoader('ThermoPanel','./JSON/thermo-panel.json');

So now, just what is the JSON that is being loaded? It can include everything about the component. In this case, as a panel component, it can include thermometers, machine switches, sliders, gauges, and more. While it seemed nicer to keep the components parts on the web page, it may actually work better to use the subcomponent field that is in the longer example for ‘thermo-panel’ that we made before and also for the other similarly constructed panels. The JSON will contain a complete panel structure.

However, if the reader will notice the inclusion of the function call to transformJSONToJSObject, he will understand that JSON might be coded in some way to make transport easier and to make it easier for a server to handle the definition. After all, the definition will include complete SVG templates, function definitions, and other JavaScript expressions. Also, the JSON object may contain more than just the panel definition because some information may simply aid in bookkeeping or validation. So, one can expect that there will be some treatment of the object upon receipt.

As for the encoding, the data coming in from the server may be encoded in a number of ways. Perhaps it will be simply URL encoded. Or more securely, it might be enciphered. For this discussion, we can just use URL encoding.

Some of the tools that are available for creating Vue applications no doubt take care of the JSON transformation. But, this discussion has so far avoided the use of command line tools. This omission is not that bad as we have also used Vue with the minimum of resources, using only one script tag for the referring to the CDN. However, I certainly do recommend looking into the command line tools especially for organizing projects.

When the JSON arrives at the page, given the component is completely assembled with subcomponents, no more work has to be done to fetch the parts. We can make the assumption that all components will come in fully defined for the rest of this discussion. But, assembling complete component hierarchies will require command line tools at some point.

The SVG editing process will also require some work. The SVG editing processes allow a designer to draw a panel and all the components on it. But, each subcomponent has to be identified, called out in a group, or given a place holder. Any approach to using the drawing requires some treatment of the SVG so that Vue component tags can replace the groups or graphic elements. In this way, any artist rendering can become a template. And, the drawn subcomponents will have to be disassembled into templates for Vue subcomponents.

This sort of parsimony is contrary to the workflow of most of the JavaScript frameworks. The frameworks are about assembling pages. But, editing or drawing, results in something already assembled by an artist. In practice, the result of editing does not provide a text file that corresponds directly to a framework component definition.

More about the editing process may be considered in some other discussion. There is a lot to it. But, for now, we have the tools we need in order to load hierarchal components and make them come alive.

The Lazy Application

For our IoT panel construction, we already have a selection bar that responds to searches. And, we have a way of loading components when we need them. We just need to connect up these parts. And, at last, we have to make sure that the panels appear and that they start working when they do.

The lazy loading of panels done by the async code above provides a sketch of an idea. But, thankfully, some people have experimented to find ways of making sure that all kinds of components can be loaded. There is one codepen entry that shows how to update Vue apps with new components of varying types. That is the mechanism that is needed for updating a designated part of the page with different types of panel.

With the ability to add in different kinds of panels and with a simple mechanism to load their definitions, we can, at last, have our panel searching page.

Here is the HTML that we need in our page so that the Vue app can place components in dynamically:

<template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name"></component> </template>

The component tag is a Vue meta tag. See the reference for dynamic components. The properties, special attributes, used for the component tag in this case are is and key. The is attribute exists for dynamic components. And, the key ensures that the new children will have different identities from each other and helps Vue to decide what to draw.

“Children of the same common parent must have unique keys. Duplicate keys will cause rendering errors.”

The template tag will loop through components that are provided in the panelList data field of the application.

So, starting with the application level Vue definition for the icon app, we can make changes to include the panelList in the data elements. (Let’s now call it the panelApp).

var panelApp = new Vue({ el: '#PanelApp', data: { iconList: [ // Where is the data? Still on the server. ], panelList: [ ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: function (pname) { // var url = panelURL(pname); // this is custom to the site. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = decodeURIComponent(text); eval(pHat); // widgdef = object def, must be assignment pHat = widgdef; var pnameHat = pname + pcount++; pHat.name = pnameHat; // this is needed for the key this.panelList.push(pHat); // now it’s there. }).catch( error => { /* handle it */ }); } } });

Besides adding in the panel, goGetPanel is now in a form required for getting a component definition from a database or other store. The server side must be careful about delivering JavaScript code in the correct format. As for what the object looks like coming from the server, we have already seen it. It is the kind of object used as a parameter to Vue.component.

Here is the complete body of the Vue app that provides a menu as a search result and a place to put panels fetched from the server when the user clicks an icon.

<div id="PanelApp"> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <button onclick="GetIcons(11)">Find All</button> <button onclick="GetIcons(5)">Find 5 Point</button> <button onclick="GetIcons(6)">Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart" style="padding:4px"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> <div class="entryart" style="padding:4px" > <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name" :ref="panel.name" ></component> </template> </div> </div>

In the last div, the component tag now has a ref parameter bound to the panel name. The ref parameter allows Vue app to identify which component to update with data and keeps components separate. The ref parameters also allow our application access to the new dynamically loaded components.

In one test version of the panel app, I have the following interval handler:

setInterval(() => { var refall = panelApp.$refs; // all named children that panels for ( var pname in refall ) { // in an object var pdata = refall[pname][0]; // off Vue translation, but it’s there. pdata.temp1 = Math.round(Math.random()*100); // make thermos jump around. pdata.temp2 = Math.round(Math.random()*100); } },2000)

The code provides a little animation, changing thermometers randomly. Each panel has two thermometers, and the app allows the user to keep adding panels. (In the final version, some panels must be thrown away.) The refs are being accessed using panelApp.$refs, a field that Vue creates given the refs information in the component tag.

So, this is what the randomly jumping thermometers look like in one snapshot:

A collection of animated panels for one type of panel (or component). (Large preview) Connecting The Panel To The IoT Device

So, the last piece of code is a setInterval test updating thermometers with random values every two seconds. But, what we want to do is read in real data from real machines. In order to do that, we will need some form of communication.

There are a variety of ways. But, let’s use MQTT which is a pub/sub message system. Our SPWA can subscribe to messages from devices at any time. When it gets those messages the SPWA can direct each message to the appropriate data handler for the panel mapped to the device identified in the message.

So, basically what we need to do is replace the setInterval with a response handler. And, that will be for one panel. We probably want to map panels to handlers as they are loaded. And, it is up to the web server to see that the correct mapping is delivered.

Once the web server and the SPWA have the page ready for operation, the web server no longer needs to take care of messaging between the page and the device. the MQTT protocol specifies a routing server to handle pub/sub. A number of MQTT servers have been made. Some of them are open source. One very popular one is Mosquito, and there are a few developed on top of Node.js.

The process for the page is simple. The SPWA subscribes to a topic. One good version of a topic is an identifier for an MCU such as a MAC address or a serial number. Or, the SPWA could subscribe to all temperature readings. But, then the page would have to do the work of filtering the messages from all devices. Publication in MQTT is essentially a broadcast or multicast.

Let’s take a look at how the SPWA will interface with MQTT.

Initializing MQTT On The SPWA

There are several client libraries to choose from. One, for instance, is a MQTT.js. Another is eclipse paho. There are more of course. Let’s use Eclipse Paho since it has a CDN stored version. We just need to add the following line to our page:

<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>

The MQTT client has to connect to a server before it can send and receive messages. So, lines setting up the connection also need to be included in the JavaScript. We can add in a function MQTTinitialize which sets up the client and the responses for connection management and message receipt.

var messagesReady = false; var mqttClient = null; function MQTTinitialize() { mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId"); mqttClient.onMessageArrived = onMessageArrived; // connect the client mqttClient.connect({ onSuccess: () => { messagesReady = true; } }); // set callback handlers mqttClient.onConnectionLost = (response) => { // messagesReady = false; // if (response.errorCode !== 0) { console.log("onConnectionLost:"+response.errorMessage); } setTimeout(() => { MQTTinitialize() },1000); // try again in a second }; } Setting up Subscription

With the connection ready, the client can subscribe to message channels, send messages on them, etc. Just a few routines can do most of the work necessary to connect panels with the MQTT pathways.

For the panel SPWA, the moment of subscription can be used to establish the association between the panel and the topic, the MCU identifier.

function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic); }

Given that an MCU is publishing on its topic, the SPWA will receive a message. Here, the Paho message is unpacked. And, then the message is passed on into the application mechanics.

function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message); }

So, now all we need to do is create deliverToPanel which should be somewhat like the interval handler that we had before. However, the panel is clearly identified, and only the keyed data sent in the particular message may be updated.

function deliverToPanel(panel,message) { var refall = panelApp.$refs; // all named children that panels var pdata = refall[panel][0]; // off Vue translation, but it’s there. var MCU_updates = JSON.parse(message); for ( var ky in MCU_updates ) { pdata[ky] = MCU_updates[ky] } }

This deliverToPanel function is abstract enough to allow any panel definition with any number of data points for animation.

Sending Messages

To complete the application loop between the MCU and the SPWA, we define a function to send a message.

function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage); }

The sendPanelMessage function does no more than sending the message out on the same topic pathway that the SPWA subscribes to.

As we plan to make the icon buttons responsible for bringing in some number of panels for a single cluster of MCU’s, there will be more than one panel to take care of. But, we keep in mind that each panel corresponds to a single MCU, so we have a one-one mapping, for which we may use two JavaScript maps for the map and the inverse.

So, when do we send messages? Usually, the panel application will send a message when it wants to change the state of the MCU.

Keeping The View (Vue) State In Sync With Devices

One of the great things about Vue is that it is very easy to keep the data model synchronized with the activity of the user, who may edit fields, click on buttons, use sliders, etc. One can be sure that button and field changes will be reflected immediately in the components’ data fields.

But, we want changes to fire off messages to the MCU as soon as the changes occur. So, we seek to make use of the interface events that Vue may govern. We seek to respond to such an event, but only after the Vue data model is ready with the current value.

I created another kind of panel, this one with a fairly artistic looking button (perhaps inspired by Jackson Pollock). And, I went about turning it into something whose click reports the state back to the panel that contains it. That was not so simple a process.

One thing that threw me off is that I had forgotten some of the oddities in managing SVG. I first tried to change the style string so that the display field of the CSS style would either be “None” or “something”. But, the browser never rewrote the styles string. But, as that was cumbersome, I tried changing the CSS class. That also had no effect. But, there the visibility attribute, which most of us recall from old HTML (version 1.0 perhaps), but that is very up to date in SVG. And, that works well. All, I had to do was to get the button click event to propagate.

Vue has designed properties to propagate in one direction, parent to child. So, to change data in the application, or in the panel, you have to send a change event to the parent. Then, you can change the data. The change of the data element controlling the button causes Vue to update the property affecting the visibility of the SVG element we have chosen to indicate state. Here is an example:

Finally, a collection of different types of panels each with instances assigned to separate MCU’s. (Large preview)

Each instance of the squiggly button panel is independent. So, some are ON and some are OFF.

This snippet of SVG contains the odd-looking yellow indicator:

<path :visibility="stateView" style="opacity:0.98000004;fill:#faea4a;fill-opacity:1;stroke:#eecd5c;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sunthing" d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z" transform="translate(78.340803,6.1372042)" />

The visibility is populated by stateView, a computed variable that maps the state boolean to a string for SVG.

Here is the panel component definition template:

<script type="text/x-template" id="mcu-control-panel-template"> <div> <control-switch :state="bstate" v-on:changed="saveChanges" ></control-switch> <gauge :level="fluidLevel" ></gauge> </div> </script>

And, this is the JavaScript definition of the Vue panel with its children as subcomponents:

var widgdef = { data: function () { var currentPanel = { // at the top level, values controlling children bstate : true, fluidLevel : Math.round(Math.random()*100) } // return currentPanel }, template: '#mcu-control-panel-template', methods: { saveChanges: function() { // in real life, there is more specificity this.bstate = !this.bstate relayToMCU(this.name,"button",this.bstate) // to be defined } }, components: { 'control-switch' : { // the odd looking button props: [’state'], template: '#control-switch-template', // for demo it is in the page. computed: { // you saw this in the SVG above. stateView : function() { return ( this.state ) ? "visible" : "hidden" } }, methods : { // the button handler is in the SVG template at the top. stateChange : function () { // can send this.$emit('changed'); // tell the parent. See on the template instance } } }, 'gauge' : { // some other nice bit of SVG props: ['level'], template: '#gauge-template' } } }

So, now the mechanism for a single button embedded in a panel has been laid out. And, there has to be a hook for telling the MCU that something has taken place. It must be called immediately after the data state of the panel component has been updated. Let’s define it here:

function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message) }

There is the state change on it’s way to hardware in just two lines of code.

But, this is a fairly simple case. Any switch can be viewed as a function call to a piece of hardware out in the world. So, the string might contain the switch name and several other data elements. So, the component method that registers change will have to have some custom handling in it in order that it might gather together all the pieces of data set on the panel and send them along in one command string. Even the command string is a little simple. If the MCU is quite small, the command string might have to be translated into a code. If the MCU has a great deal of capability, the command string might actually be a JSON structure or perhaps all the data that the panel hosts.

In this discussion, the buttons on the icon panel contain the name of the panel to fetch. That may also be fairly simplified as well. It seems to make sense that that parameter can stand for any panel that might be stored in an enterprises databases. But, perhaps it is some formula. Perhaps, information about the panel should be wrapped around the panel definition that we receive from the server. In any case, the basics can be easily expanded upon once certain headaches are out of the way, like making the SVG respond to clicks properly.

Conclusion

This discussion has laid out some basic steps and decisions that lead to the realization of a Single Page Web App (SPWA) that can interface with IoT devices. We now know how to get panels from a web server and turn them into MCU interface.

There is much more to this discussion with quite a few other discussions that may follow. Starting with Vue is one thing to think about. But, then there is the whole MCU story, which we have only briefly touched upon.

In particular, by selecting MQTT as a communication substrate, we assume that IoT devices on the other end can somehow be ruled by MQTT. But, that may not always be the case. Sometimes gateways are needed if MQTT is to gain access to a device with serial links or Bluetooth. Or, perhaps all one ever needs from on the web page is WebSockets. Nevertheless, we used MQTT as an example to show how Vue could both receive and send data while keeping its data state in sync with devices.

Once again we only have part of the story. This time it is for synchronization because the page should be able to deal with alerts and bother the user if something critical is happening. Sometimes messages can get lost. So, we have to have a mechanism for acknowledgments.

Finally, it is my opinion that Vue makes updating data upon receipt quite elegant. But, sending the state changes is not so straight forward. It does not seem to make the job much simpler than can be done with vanilla JavaScript. But, there is a way and it makes sense.

Perhaps a clean library can be built to make a universal set of components for all panels. The elements for making such libraries and having them stored in a database have been briefly mentioned. Tools that go beyond just making SVG pictures may have to be developed. In any case, there are likely many things that can be done for the next steps.

(dm, yk, il)
Categories: Web Design

How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers

Smashing Magazine - Tue, 05/14/2019 - 03:30
How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers How Frontend Developers Can Help To Bridge The Gap Between Designers And Developers Stefan Kaltenegger 2019-05-14T12:30:59+02:00 2019-05-23T09:05:51+00:00

Within the last nine years, almost every designer I used to work with expressed their frustration to me about them frequently having to spend days giving feedback to developers to correct spacings, font sizes, visual as well as layout aspects that had simply not been implemented correctly. This often lead to weakening the trust between designers and developers, and caused unmotivated designers along with a bad atmosphere among the two disciplines.

A lot of times developers still seem to have the bad reputation of being overly technical and ignorant when it comes to being considerate about details the design team came up with. According to an article by Andy Budd, “[…] a lot of developers are in the same position about design — they just don’t realize it.” In reality though (as Paul Boag points out), “developers [need to] make design decisions all the time.”

In this article, I’ll provide practical points of advice for frontend developers to avoid frustration and increase productivity when working with their creative counterpart.

Looking Through The Eyes Of A Designer

Let’s for one moment imagine you were a designer and spent the last weeks — if not months — to work out a design for a website. You and your teammates went through multiple internal revisions as well as client presentations, and put a solid effort into fine-tuning visual details such as white space, font styles, and sizes. (In a responsive era — for multiple screen sizes, of course.) The designs have been approved by the client and were handed off to the developers. You feel relieved and happy.

A few weeks later, you receive an email from your developer that says:

“Staging site is set up. Here’s the link. Can you please QA?”

In a thrill of anticipation, you open that staging link and after scrolling through some of the pages, you notice that the site looks a little off. Spacings are not even close to what your design suggested and you notice some kinks in the layout: wrong font faces and colors as well as incorrect interactions and hover states. Your excitement starts to slowly fade and turn into a feeling of frustration. You can’t help but ask yourself, “How could that have happened?”

The Search For Reasons

Maybe there were just a lot of unfortunate misunderstandings in the communication between the designers and developers. Nevertheless, you continue asking yourself:

  • What did the the handover of designs look like? Were there just some PDFs, Photoshop or Sketch files shared via e-mail with some comments, or was there an actual handover meeting in which various aspects such as a possible design system, typography, responsive behavior, interactions and animations were discussed?
  • Did interactive or motion prototypes that help to visualize certain interactions exist?
  • Was a list of important aspects with defined levels of priority created?
  • How many conversations took place — with both designers and developers in the same room together?

Since communication and handover are two very important key points, let’s take a closer look at each.

Communication Is Key

Designers and developers, please talk to each other. Talk a lot. The earlier on in the project and the more often, the better. If possible, review design work in progress together early in the project (and regularly) in order to constantly evaluate feasibility and get cross-disciplinary input. Designers and developers naturally both focus on different aspects of the same part and therefore see things from different angles and perspectives.

Checking in early on lets developers become familiarized with the project so they can start researching and planning ahead on technical terms and bring in their ideas on how to possibly optimize features. Having frequent check-ins also brings the team together on a personal and social level, and you learn how to approach each other to communicate effectively.

The Handover From Design To Development

Unless an organization follows a truly agile workflow, an initial handover of design comps and assets (from the design team to the developers) will likely happen at some point in a project. This handover — if done thoroughly — can be a solid foundation of knowledge and agreements between both sides. Therefore, it is essential not to rush through it and plan some extra time.

Ask a lot of questions and talk through every requirement, page, component, feature, interaction, animation, anything — and take notes. If things are unclear, ask for clarification. For example, when working with external or contract-based teams, both designers and developers can sign off the notes taken as a document of mutual agreement for future reference.

Flat and static design comps are good for showing graphical and layout aspects of a website but obviously lack the proper representation of interactions and animations. Asking for prototypes or working demos of complex animations will create a clearer vision of what needs to be built for everyone involved.

Nowadays, there’s is a wide range of prototyping tools available that designers can utilize to mockup flows and interactions in different levels of fidelity. Javier Cuello explains how to choose the right prototyping tool for your project in one of his comprehensive articles.

Every project is unique, and so are its requirements. Due to these requirements, not all conceptualized features can always be built. Often the available time and resources to build something can be a limiting factor. Furthermore, constraints can come from technical requirements such as feasibility, accessibility, performance, usability and cross-browser support, economic requirements like budget and license fees or personal constraints like the skill level and availability of developers.

So, what if these constraints cause conflicts between designers and developers?

Finding Compromises And Building Shared Knowledge

In order to successfully ship a project on time and meet all defined requirements, finding compromises between the two disciplines is mostly inevitable. Developers need to learn to speak to designers in non-technical terms when they explain reasons why things need changes or can’t be built in a specific situation.

Instead of just saying, “Sorry, we can’t build this,” developers should try to give an explanation that is understandable for designers and — in the best case — prepare suggestions for an alternative solution that works within the known constraints. Backing your point with statistics, research, or articles, can help to emphasize your argument. Also, if timing is an issue, maybe the implementation of some time-consuming parts can be moved to a later phase of the project?

Even though it is not always possible, having designers and developers sit next to each other can shorten feedback loops and make it easier to work out a compromised solution. Adapting and prototyping can be done directly through coding and optimizing with DevTools open.

Show your fellow designers how to use DevTools in a browser so that they can alter basic information and preview small changes in their browser (e.g. paddings, margins, font sizes, class names) on the fly.

If the project and team structure allow it, building and prototyping in the browser as soon as possible can give everyone involved a better understanding of the responsive behavior and can help eliminate bugs and errors in the early stage of the project.

The longer designers and developers work together, the better designers will understand what is easier and what is more difficult for the developers to build. Over time, they can eventually refer to solutions that have worked for both sides in the past:

“We’ve used that solution to find a compromise in Project A. Can we use it for this project as well?”

This also helps developers get a better sense of what details the designers are very specific about and what visual aspects are important to them.

Designers Expect The Frontend To Look (And Function) Like Their Design The Design File Vs. Browser Comparison

A helpful technique to prevent designers from frustration is to make a simple left-right comparison between the design file you got handed over and what your current state of development looks like. This might sound trivial, but as a developer, you have to take care of so many things that need to function under the hood that you might have missed some visual details. If you see some noticeable discrepancies, simply correct them.

Think of it this way: Every detail in your implementation that looks exactly as it was designed saves both you and the designer valuable time and headaches, and encourages trust. Not everyone might have the same level of attention to detail, but in order to train your eye to notice visual differences, a quick round of Can’t Unsee might be a good help.

(Image credits: Can’t Unsee) (Large preview)

This nostalgically reminds me of a game we used to play a long time ago called “Find it”. You had to find discrepancies by comparing two seemingly similar images in order to score points.

(Image credits: Mordillo find them) (Large preview)

Still, you may be thinking:

“What if there simply is no noticeable system of font sizes and spacings in the design?”

Well, good point! Experience has shown me that it can help to start a conversation with the designer(s) by asking for clarification rather than radically starting to change things on your own and creating unwanted surprises for the designer(s) later.

Learn Basic Typographic And Design Rules

As Oliver Reichenstein states in one of his articles, 95% of the information on the web is written language. Therefore, typography plays a vital role not only in web design but also in development. Understanding basic terms and concepts of typography can help you communicate more effectively with designers, and will also make you more versatile as a developer. I recommend reading Oliver’s article as he elaborates the importance of typography on the web and explains terms such as micro- and macro-typography.

In the “Reference Guide For Typography In Mobile Web Design”, Suzanne Scacca thoroughly covers typography terminology such as typeface, font, size, weight, kerning, leading and tracking as well as the role of typography in modern web design.

If you would like to further expand your typographical horizon, Matthew Butterick’s book “Butterick’s Practical Typography” might be worth reading. It also provides a summary of key rules of typography.

One thing I found particularly useful in responsive web design is that one should aim for an average line length (characters per line) of 45 to 90 characters since shorter lines are more comfortable to read than longer lines.

Comparing different line lengths (Large preview) Should Developers Design?

There has been a lot of discussion whether designers should learn to code, and you may be asking yourself the same question the other way around. I believe that one can hardly excel in both disciplines, and that’s totally fine.

Rachel Andrew nicely outlines in her article “Working Together: How Designers And Developers Can Communicate To Create Better Projects” that in order to collaborate more effectively, we all need to learn something of the language, skills, and priorities of our teammates so that we can create a shared language and overlapping areas of expertise.

One way to become more knowledgable in the field of design is an online course known as “Design for Developers” that is offered by Sarah Drasner in which she talks about basic layout principles and color theory — two fundamental areas in web design.

“The more you learn outside of your own discipline, is actually better for you [...] as a developer.”

— Sarah Drasner The Visual Center

By collaborating with designers, I learned the difference between the mathematical and visual center. When we want to draw the reader’s attention to a certain element, our eye’s natural focal point lies just slightly above the mathematical center of the page.

We can apply this concept, for example, to position modals or any kinds of overlays. This technique helps us to naturally get the user’s attention and makes the design appear more balanced:

(Large preview) We’re All In This Together

In fast-paced and not-so-agile agency environments with tight deadlines, developers are often asked to implement fully functional responsive frontends based on a mobile and desktop mockup. This inevitably forces the developer to take design decisions throughout the process. Questions such as, “At what width will we decrease the font size of headlines?” or “When should we switch our three-column layout to a single column?” may arise.

Also, in the heat of the moment, it may happen that details like error states, notifications, loading states, modals or styles of 404 pages simply fall through the cracks. In such situations, it’s easy to start finger-pointing and blaming the people who should have thought about this earlier on. Ideally, developers shouldn’t ever be put in such a situation, but what if that’s the case?

When I listened to Ueno’s founder and CEO, Haraldur Thorleifsson, speak at a conference in San Francisco in 2018, he presented two of their core values:

“Nothing here is someone else’s problem.” “We pick up the trash we didn’t put down.”

What if more developers proactively start mocking-up the above-mentioned missing parts as good as they can in the first place, and then refine together with the designer sitting next to them? Websites live in the browser, so why not utilize it to build and refine?

While winging missing or forgotten parts might not always be ideal, I’ve learned in my past experiences that it has always helped us to move forward faster and eliminate errors on the fly — as a team.

Of course, this does not mean that designers should be overruled in the process. It means that developers should try to respectfully meet designers halfway by showing initiative in problem-solving. Besides that, I as a developer was valued way more by the team simply for caring and taking on responsibility.

Building Trust Between Designers And Developers

Having a trustful and positive relationship between the creative and tech team can strongly increase productivity and outcome of work. So what can we, as developers, do to increase trust between the two disciplines? Here are a few suggestions:

  1. Show an eye for details.
    Building things exactly as they were designed will show the designers that you care and put a big smile on their faces.
  2. Communicate with respect.
    We’re all human beings in a professional environment striving for the best possible outcome. Showing respect for each other’s discipline should be the basis for all communication.
  3. Check in early on and regularly.
    Involving developers from the start can help to eliminate errors early on. Through frequent communication, team members can develop a shared language and better understanding of each other’s positions.
  4. Make yourself available.
    Having at least an optional 30-minute window a day when designers can discuss ideas with developers can give designers a feeling of being supported. This also gives developers the opportunity to explain complex technical things in words that not-so-technical people can understand better.
The Result: A Win-Win Situation

Having to spend less time in QA through effective communication and a proper handover of designs gives both the creative and dev team more time to focus on building actual things and less headaches. It ultimately creates a better atmosphere and builds trust between designers and developers. The voice of frontend developers that show interest and knowledge in some design-related fields will be heard more in design meetings.

Proactively contributing to finding a compromise between designers and developers and problem-solving as a developer can give you a broader sense of ownership and involvement with the whole project. Even in today’s booming creative industry, it’s not easy to find developers who — besides their technical skillset — care about and have an eye for visual details. This can be your opportunity to help bridge the gap in your team.

Related Resources (dm, yk, il)
Categories: Web Design

Setting Up A Digital Policy: An Interview With Kristina Podnar

Smashing Magazine - Mon, 05/13/2019 - 04:00
Setting Up A Digital Policy: An Interview With Kristina Podnar Setting Up A Digital Policy: An Interview With Kristina Podnar Vitaly Friedman 2019-05-13T13:00:59+02:00 2019-05-23T09:05:51+00:00

The web is wonderfully diverse and unpredictable because of wonderfully diverse people shaping it. In this new series of short interviews, we talk to interesting people doing interesting work in our industry, and sharing what they’ve learned.

For over two decades, Kristina Podnar has worked with some of the most high-profile companies in the world and has helped them see digital policies as opportunities to free the organization from uncertainty, risk, and internal chaos.

Kristina is an energetic and passionate problem-solver, and we’re honored to welcome her at SmashingConf Toronto 2019 for a live session for creating and documenting a sound policy and standards, and a few tools and tactics which will help nurse your website back to health.

Vitaly: So, hello everyone. Thank you so much for joining in again. This is one of those mysterious sessions where we interview interesting people behind the scenes. I think it’s actually very important to highlight the important people doing important work just silently in the back, hiding a little bit, trying to make the world a bit better, one step at a time and, that’s important, sharing what they learned with the community, with all of us, so we can benefit from it.

Vitaly: And so, I’m very happy and privileged today to have with us Kristina Podnar who is a digital policy innovator. And, for over two decades she has worked with some of the most high profile companies in the world, and has helped them see policies as opportunities to free the organization from uncertainty, risk, and internal chaos. This is the official description. What I can tell from my side though is that Kristina is just such an incredibly positive and energetic and nice person. I’m so privileged to have you speaking in Toronto with us, Kristina. So Kristina, how are you today?

Kristina Podnar: Thanks for having me, Vitaly. I am doing really well and really excited to be here with you. You have no idea. This is sort of a pinnacle of my career and a path I’ve been on for a while. As you know, I contributed to Smashing Magazine back in 2016, but having the opportunity to be with you in Toronto is, I think, an ultimate high for me amongst everything else that I’ve done so far. I’m really excited.

Vitaly: This is so nice. I can’t wait. I can’t wait.

Kristina Podnar: Same here.

Vitaly: So, Kristina, tell me, the truth, the story, how did you end up in this mess? Every time we talk about digital policies and governance, and I heard rumors that you are going to speak about that, everybody thinks about boring stuff. Bureaucracy, slow processes, and communication issues, and maintenance problems. Messy, messy things.

Kristina Podnar: That’s right.

Vitaly: How do you feel there?

Kristina Podnar: Well, you know what, I don’t blame anybody for thinking that because that’s all that we’ve all been taught, right? I mean, we always think about policies as these 20 page PDF documents that have been signed off by legal or HR, or there somewhere on SharePoint. We have to go searching for them when we need to know something, and all we need is a yes or no answer and somebody’s saying, "No, no. Go read this document. Really, it’ll help you." And, if you are a digital, that usually means reading 30 or 40 such documents.

Kristina Podnar: I don’t blame anybody for feeling like it’s a lot of bureaucracy. It’s really, really annoying. And, it’s where I actually came from in my career. Well, that’s not true. It was a little bit of a derailment in my career, but I came from the world where we used to live in the wild, wild west. We did things like migrate new websites in HTML with having a backup, which is how I personally made sure that one of my clients didn’t have a website for nine hours. Or, we would pass credit card numbers through FTP without encryption. Right. It was the crazy days.

Kristina Podnar: And then, it seems like the world just went to this extreme of trying to tie down anybody who was doing anything creative. And, if you wanted to do a really cool marketing campaign online, it was like compliance had to sign off, and legal had to sign off, and you had to say certain things. And, by the time you got to this point where your really cool idea came out the other end, you didn’t even recognize it. It was boring and it was dull.

Kristina Podnar: And so, I lived in this world for many years, and what I discovered is it doesn’t have to be like that. We can actually have a really good balance between understanding what needs to be done to protect the business, doing things the right way in terms of laws and regulations, and yet freeing everybody to do really creative and innovative work. And so, I’m on this mission to help businesses understand that because I think far too many people come into their work job every day and they’re not happy. And, I think that’s really sad.

Kristina Podnar: So, I’m all about let’s create policies that free the organization to do what it needs to get done in digital, and let’s free the workers to be creative and innovative and not have to do the humdrum of reading these long PDF’s or putting up with red tape because digital policies are fun and exciting and enabling. They are anything but red tape.

Vitaly: But, Kristina it sounds like a magic dream. It sounds like it’s something that it’s really hard to achieve. So, when it comes to something like that, and I guess this is also something you’re going to speak about in Toronto,-

Kristina Podnar: Yeah.

Vitaly: ... where do you even start? Imagine you have this mass organization just in front of you and it desperately needs some better structure, maybe better communication. Every single company I was working within my career had communication issues, including ours to be honest for quite a bit of time.

Kristina Podnar: No.

Vitaly: So, where do you even start? What’s the starting point for you?

Kristina Podnar: So, personally what I like to do is really kind of just come into the organization fresh-eyed, and trying to understand really what are the biggest challenges. And, I’ve worked with really, really large multinationals all the way down to really small companies. And, it varies. The problem varies. But, in most organizations that I work with, what I find is people feel like they have to really control digital because it’s something new and they feel like it’s something that’s really, really dangerous and can kind of pose a threat to the organization as much as it can kind of create that opportunity.

Kristina Podnar: And so, it’s all about trying to find the pain point. So, for example, I recently worked with a pharma company, and they had this really crazy review process where it took 21 days to get content published. I’m thinking to myself that could work if it’s a really big product launch and you’ve been creating the product for years. 21 days isn’t a big deal. But, if you had like the measles outbreak in the United States, you want to act really quickly and get the information out there. 21 days is forever.

Kristina Podnar: And so, what it was is people had to go through the same pain staking points for content review over and over again and their medical signatories had to feel comfortable. They had to do these crazy screenshots of the content on an iPad versus an iPhone versus this screen, that screen. Legal had to review things. And, what we found is that we can actually boil the steps down and creates certain rules that can’t be broken and do this in a way that facilitates the content being created with awareness across the whole sign-off team.

Kristina Podnar: And so, really ahead of time, what we would do is, as content was being created, we would do screenshots with the different devices. We would make sure that, up front, whoever was in charge of the marketing campaign was following certain sort of rules and regulations and actually showing where they were getting creative or where they wanted to kind of relax some of the rules.

Kristina Podnar: And, what that meant is that there was a summary and a summative package at the end of the process that we could serve up, almost in a restaurant where you have your menu item and you check things off and go, "I don’t want the fish today, but gosh, the chicken sounds delicious." We’ll go with that really quickly and get that order in. And, it was the same thing. And so, all of a sudden we found ourselves in this crazy pharma world, which is probably the most regulated of anybody out there, 21 review day process down to three.

Kristina Podnar: But, it has to do with understanding what the expectations are of sort of this regulatory policy driven world and really making sure that as creatives we address that up front, and that we actually give everybody the ability to exhale, take a deep breath, and understand we’re doing things and working towards the same common goal, and we’re going to make sure we don’t get the company sued. But, at the end of the day, we want to have a lot of freedom. We want to make sure that it’s innovative, that it catches the user’s imagination, that we have these great digital experiences, and that that can still be done within that framework. Because it’s really freedom within a framework, if you will. And, it doesn’t have to be boring and it doesn’t have to be onerous and it certainly doesn’t have to take 21 days.

Vitaly: Wow. Now, I actually getting excited about all that stuff. That’s surprising.

Kristina Podnar: Yay.

Vitaly: I did not see that coming at all. But, I’m wondering at this point, so would you say that every single company of every size could benefit from a very clear digital governance and kind of policy? Does every company has to invest time in it, or do you see it’s more a deal for enterprise or larger level, larger size companies?

Kristina Podnar: So yes, everybody needs to have digital policies, even me. I’m an independent consultant, but even I have to comply with things like GDPR. And so, last year I actually wrote up how I did that and how GDPR applies to the gig economy. So, policies are really good for anybody, whether you’re a single consultant all the way up to multinational. The thing that’s different I think, and we have to be very, very cognizant of this because I don’t want everybody to run out there and create 300 policies. Don’t do that. That’s also wrong.

Kristina Podnar: What we have to be really cognizant of is if you’re a small startup, for example, you’re not going to have the same policies nor the same number of policies, that they’re not going to be as robust, perhaps, in terms of how you implement them, as a large multinational. And, I really wrote my book, The Power of Digital Policy, and that’s really what I focused on. I focused on how can you get this done, whether you’re a startup, or if you’re a small company, if you’re a large enterprise, and it really is about where you are in your maturity growth in terms of policy.

Kristina Podnar: So, if you’re just starting out, don’t worry about 300 things. Worry about the four things that I’m going to tell you about at the conference, right? Let’s kind of just get you started. Pay attention to the most important things and get you to the point where, for you, in terms of what you’re trying to get done, you’ve properly balanced out that risk and that opportunity that digital brings with it. Because that’s really what I want people to understand. There is no magic checklist for policies. Just because somebody else is doing the crazy dance over there with 300 policies and that’s what they need to do, the crazy dance in a happy way. That’s okay.

Kristina Podnar: But, the same thing doesn’t apply to you. You’re unique in terms of your culture, you’re unique in terms of your beliefs. You’re unique in terms of what you’re trying to get done. And so, don’t just take somebody else’s suit and put it on. It’s going to be constructive if it’s too small and too tight. It’s not going to feel good. Same thing with policies. Don’t go off and take somebody’s policies and put them on. They’re not going to feel good. We want your organization to be safe, to be productive, to do the right things for the business. But, by the same token, we want you to actually be able to get some cool things done. And, that’s really what digital policies are and that’s what I’m trying to actually get done and help everybody else do.

Kristina Podnar: And so yes, one person all the way up to multinational, everybody needs policies. What type? It depends on what you’re doing. It could be accessibility, which I know we’re going to also be covering it at Smashing and I’m excited about that. But, it could be anything from accessibility to user-generated content. It could be policy and privacy, lots of conversation around that these days. It could be about just literally who gets to select the content management system we’re going to use inside of an organization so we don’t have to have that conversation over and over again every time we have a new digital martech stack or something else we want to introduce into the organization and get something done. So, to me, yes, policies always sound boring, but the reality is they can be anything but that. And, it’s just about how we get that done and get it done in a reasonable way that helps everybody out and is in the interest of everybody in the organization. And, that’s where I see the most success.

Vitaly: I have to switch cameras now.

Kristina Podnar: Okay.

Vitaly: Interesting. And, it’s also, for me personally, when it comes to policies, I think it’s all about streamlining. So, we improved a lot of things just to streamline processes to make sure that everything is kind of clear, what is following what, kind of how do we move from a to b in a very predictable set of steps rather than chaotic, just throwing everything in the air and hoping that something will stick. And so, this was actually very helpful and it was very informal in many ways. Would you say that a policy has to be kind of stated on a piece of paper or in a document? How do you document it? How does it manifest itself?

Kristina Podnar: So, it’s interesting, I actually spent a year thinking about all of my experiences in terms of what works best in an organization and size, industry, et cetera. And, what I found is policies do need to be written down somewhere, right? Just because most organizations, no matter how small you are, there’s always somebody new jumping onto the team, or somebody’s leaving for maternity leave and so somebody has to step in, et cetera. So, it’s important to document things.

Kristina Podnar: Now, I think, especially if you’re in a small organization, you’re part of a smaller team, you don’t need to have a really formal template. You can even write on the back of a napkin if everybody can see that napkin in the lunchroom and knows where to find it. So, I don’t think we need to get stuck on this is the template, this is the format, although in a larger organization that does help.

Kristina Podnar: What I think we need to really focus on, and this is where policies get the bad rap, policies are not just about how we document things and that’s sort of old-world thinking, right? That’s how we did things 25 years ago. We wrote it on a piece of paper and it’s in a file folder over there. But, here we are in the digital world, right? We’re trying to make these really great user experiences online, but what we forget to do is the same thing for our internal friends and colleagues. And, that’s really what I think we need to be doing around policies.

Kristina Podnar: We need to be making policies and documenting them in a way that’s easily accessible by everybody and it fits into what you’re already doing. And, that’s what I see work the best. If you want people to do certain things, for example, around content creation and they’re in Drupal, honestly just create a little checklist that they can actually link to from Drupal, and understand quickly these are the things I should be paying attention to. Don’t make them quit their day job and go looking for guidance because nobody wants that. Right?

Kristina Podnar: Or, if in a really large multinational, like we just deployed a chat bot that is really great. It actually tells marketers real time what they need to be thinking about and what they need to be doing in terms of that campaign. But, what’s really cool is it remembers and builds on top of itself over and over again. So, if a marketer is focused, for example, on Asia Pacific, we already know you’re focused on Asia Pacific and so all guidance we’ll ever give you is in the context of Asia Pacific and you can get that real time. We remember last time you did a campaign, what you were trying to achieve, and what your performance objectives were. And so, if they’re the same ones, we can just track that going forward and narrow the amount of guidance that you have to think about or even do.

Kristina Podnar: And, what’s really great is if you do this in the right way, it doesn’t just empower the designer, the marketer, or the developer, the content strategist. It really also helps your vendors and agencies that you bring on board. Or, if you’re a part of an agency and you’re coming to the table, imagine how cool when somebody brings you on board and says, "Hey, I want you to do this for me. Stand up this new website." And then it’s like, ta-da. These are the things we expect you to do and this is how we’re going to measure you when you’re done. I mean, that’s great. You already know how high you have to jump and what you have to achieve, and that allows you to focus on the things that really matter, in where you have that freedom and creativity without having to worry, oh no, are they going to tell me at the last hour my website has to be accessible and I haven’t built it that way. It’s like, man, nobody wants to go back to step one.

Kristina Podnar: And so yes, it’s about documentation, but more than just write it down on a piece of paper, although that can certainly work. It’s about doing it in the context of your culture and how people want to be delivered that information, and treating people who are going to consume this information like they’re actual users because they are.

Vitaly: Oh, this sounds like... I’m so happy now. I’m so happy.

Kristina Podnar: Oh good.

Vitaly: So, if you had to sum up what you’re going to cover in 40 or 45 minutes at this madness show called SmashingConf Toronto, how would you sum it up? What is it all about in maybe 40 seconds or less?

Kristina Podnar: Sure. So, you know what, all of us collectively, even if you’ve only been in this field for a few years, have contributed to a big mess. The mess has been underway in 25 years. It’s not going to get cleaned up right away, but we can make a huge difference in terms of what we do, cleaning up the messes, and making our life easier and more fun. So, we’re going to play doctor and patient in this session. We’re going to have some fun and hopefully make it funny as well. And, we’re going to literally go through how can we diagnose some of the illnesses that our organizations have, some of our projects have, and make sure that we give the right medicine, the right Rx, the right policies so that we can enable ourselves to have fun, be creative, and balance out that risk and that opportunity that I keep talking about.

Vitaly: Wow. I have a question for you.

Kristina Podnar: Sure.

Vitaly: Kristina, are you planning to run for President? Because if you do, I think you have very good chances of winning.

Kristina Podnar: Oh, thank you. I don’t know about that. But, you know what, and I shouldn’t say this publicly, it’ll be an interesting scene in the United States in terms of who’s going to run and where the bar is. And, I’ll let everybody decide on where they fall on that one.

Vitaly: Yes. So, maybe the last one, can you maybe share some insights with us about what you’re working on now, and also what excites you the most in this vast worldwide web of ours? Is there something you’re particularly interested in? Or, if you look into GDPR and all of this stuff, and I know that there is a law coming in California next year.

Kristina Podnar: Yes. CCPA.

Vitaly: Yes, exactly.

Kristina Podnar: January 1st, yeah.

Vitaly: Oh, January 1st. Here we go.

Kristina Podnar: January 1st, yes. Here we go.

Vitaly: What are you kind of looking forward to? What is something that really brings you to life or keeps you awake at night?

Kristina Podnar: Okay. So, two things. I’m working on something really fun right now, which I love. I’m actually becoming a spokesperson for this really small company in the United States. They are active in every country in the world with the exception, I think of Cuba and maybe Iraq. And, very tiny company, really small staff, not a lot of money. They’ve decided to become GDPR compliant, but get this, they’re applying GDPR principles to everybody, that’s their customer or consumer or prospect around the world, and they’re applying the same principles to everybody who works for them. Which is a huge order.

Kristina Podnar: And so, for me, it’s really fun. It’s really energizing. It’s a little bit of a proof of concept because GDPR inherently conflicts with other regulations around the world and other things that we try to do in terms of best practice. And so, I’m kind of taking this as an extreme case and an opportunity to do a proof of concept and see how do you do this in a practical way, and what does an organization do when there’s actually a conflict? Right? Where do you decide to kind of go in terms of your practices? So, that’s really something that gets me up in the morning and I don’t even need coffee to get started. I just go.

Kristina Podnar: And, in terms of what keeps me up at night, I think it’s this entire notion, what I call, the perfect storm of where we are right now. We have a situation where there’s sort of the crazy dance going on in social media, right? We have the opportunity for violence to be streamlined in social media. We have politicians using social media as a platform, claiming that they have First Amendment rights in the United States, of freedom of speech on a private platform, which is just crazy. We have users getting really upset around privacy and all of the privacy laws you just mentioned.

Kristina Podnar: So, I see this as the perfect storm, and what keeps me up at night is are we going to take this as an opportunity and make the best of it, or are we going to just passively sit by and not contribute, in which case the perfect storm will pass. And so, I hope that all of us step up and play a role because we have an important one to play and it’s a little bit more important than we probably realize. So, I hope we all engage in that.

Vitaly: Yeah. Well, so that sounds very exciting. So, with this in mind, thank you so much Kristina, for being with us today. I can’t wait for Toronto.

Kristina Podnar: Me either.

Vitaly: It’s coming up in just a few weeks from now, like six weeks or so from now.

Kristina Podnar: Yep. Countdown’s on.

Vitaly: This’ll be the first time where we actually finally meet. We have many friends in common-

Kristina Podnar: That’s right.

Vitaly: ... and so I can’t wait. So, thank you so much, Kristina.

Kristina Podnar: Same here.

Vitaly: Everyone, thank you so much for joining us today. I’m looking forward to the next little sessions about people behind the scenes and all of that. And, with this in mind, signing off. Kristina, any last words you want to share with the audience to kind of send a message out there?

Kristina Podnar: I’m bringing cookies and I’ll leave it at that.

Vitaly: Oh, wow. If that doesn’t work, I don’t know what will.

Kristina Podnar: Sounds good.

Vitaly: All right, thanks everyone. Thanks Kristina, and see you next time.

Kristina Podnar: Thanks Vitaly. Take good care.

That’s a Wrap!

We’re looking forward to welcoming Kristina to SmashingConf Toronto 2019, with a live session on digital policy, how to set up one, and how to solve some of the issues most companies are struggling with these days. We’d love to see you there as well!

Please let us know if you find this series of interviews useful, and whom you’d love us to interview, or what topics you’d like us to cover and we’ll get right to it!

(ra, il)
Categories: Web Design

The new evergreen Googlebot

Google Webmaster Central Blog - Fri, 05/10/2019 - 16:30
Googlebot is the crawler that visits web pages to include them within Google Search index. The number one question we got from the community at events and social media was if we could make Googlebot evergreen with the latest Chromium. Today, we are happy to announce that Googlebot now runs the latest Chromium rendering engine (74 at the time of this post) when rendering pages for Search. Moving forward, Googlebot will regularly update its rendering engine to ensure support for latest web platform features.


What that means for youCompared to the previous version, Googlebot now supports 1000+ new features, like:

You should check if you’re transpiling or use polyfills specifically for Googlebot and if so, evaluate if this is still necessary. There are still some limitations, so check our troubleshooter for JavaScript-related issues and the video series on JavaScript SEO.

Any thoughts on this? Talk to us on Twitter, the webmaster forums, or join us for the online office hours.

Posted by Martin Splitt, friendly internet fairy at the Webmasters Trends Analyst team
Categories: Web Design

Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign

Smashing Magazine - Fri, 05/10/2019 - 10:00
Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign Mid-Century Modern Illustration: Creating A Cover Book With Illustrator And InDesign Manuela Langella 2019-05-10T19:00:59+02:00 2019-05-23T09:05:51+00:00

In this tutorial, I’m going to show you how to create a beautiful cover design inspired by the 1950s. Specifically, the cover will be for a children’s book, so we’re going to create a well-known character: Little Red Riding Hood.

The interesting aspect of this design is that we are going to create its purely retro character that was typical for cartoons back then. As an illustrator, I have always been fascinated by the graphics of the last half-century. I grew up watching many cartoons, books, and comics characterized by that style, although I wasn’t exactly born in the 50s.

This is the reason why I want you to soak in a little inspiration from 1950. In this article, I’ll explain why I chose this precise historical period to inspire me and where my love for this type of artwork comes from. I’ll also share some ideas which you can find online if you are looking for a little inspiration to give this a try yourself.

In order to follow along, you can download the files and practice on my self-made drawing or, if you like, you can create one of your own. The important thing is that you follow all of the steps and tips if you want to create an absolutely fascinating retro design!

You will then discover the world of retro colors and all those effects that will allow us to have retro effects: I’m talking about brushes, textures, and patterns. Once the design is finished, the cover design is ready. Finally, we will prepare our cover in InDesign to export for print.

Are you ready? Let’s have fun!

  1. Why Mid-Century Art?
  2. Looking For Inspiration
  3. Drawing Concepts

    1. How To Import A Hand-Drawn Design
    2. How To Create A Basic Design
    3. How To Create A Retro Brush
    4. How To Outline Drawings
    5. Further Details
  4. Colors, Textures And Patterns

    1. Coloring Characters
    2. Brushes Effects
    3. The Background
    4. Texture Effects
  5. How To Organize A Cover Into InDesign
  6. The Final Result
1. Why Mid-Century Art?

Growing up, I read so many comics and watched so many cartoons. But not any kind — just the ones that had been drawn in a mid-century style. I’m not sure why that particular design atttracted me that much; maybe it was because of the simple lines used in the drawings or the pastel colors that were used to create the comics and cartoons.

As an illustrator and graphic designer, I always search for inspiration and like to browser through Pinterest. (It’s a great place to discover some very special ideas!)

While searching for some retro inspiration for this tutorial, I found a couple of illustrations that captured my attention:

Illustrations by Satoshi Hashimoto (left) and Derek Yaniger (middle and right) inspired by the 1950s (Large preview)

I absolutely love the hilarious way these artists have represented people and things in their artwork — the exaggeration, the details in simplicity, and the vibrant colors. Aren’t they something!

I’ve always wanted to know everything about drawings and designs created during the mid-century age, and the more I research, the more I keep rediscovering a world created with beautiful patterns, Scandinavian colors, and simple but very communicative designs.

2. Looking For Inspiration

There is so much to discover about mid-century designs. Here some examples of very inspiring advertisements and illustrations.

Image credits (from left to right): Luca Vecchi, Vintage Ad Browser, Classic Film, Ward Jenkins. (Large preview)

Characteristics: few colors, simple lines, brush effects.

Image credits: Vintage Ad Browser (top left), CrumbByCrumb (top right), Vintage Everday (bottom left), Kathryn Howard (bottom right). (Large preview) 3. Drawing Concepts

For this tutorial, I wanted to find something to draw that is well known to everyone, so that it’s not too difficult to understand how the details can be applied to an illustration of your choice later on when you want to try out the steps on your own.

3.1. How To Import A Hand-Drawn Design

So, Little Red Riding Hood came to mind. I’m going to guess that everybody is familiar with this fairy tale, and we all have an idea of how Little Red Riding Hood looks like. As children, we have seen her at least once, i.e. in a book or a cartoon.

As with all of my designs, I begin drawing my idea by hand. Below, you’ll see the two original drawings (including the erasures and the yellow color of recycled paper):

(Large preview)

I tidied up my sketches with the help of Photoshop and so now we can easily outline the characters and use them in the illustration:

(Large preview)

Note: You can download the start images over here.

To achieve the retro look, let’s take a look now at which elements I used for the principal characters:

For Little Red Riding Hood, I used many edges on the hood, the eyes, eyebrows, elbows, and feet. The face is pretty simple, too, and has a triangular shape. (Large preview)

Edges are one of the most useful details used for mid-century graphics and designs. I think edges give a very funny nature to the design, making it very playful and childish.

The little coat I used is also typical of 50s clothing:

(Image source: 1stdibs on Pinterest) (Large preview)

For the wolf, I also used some typical elements from the 50s, such as the cartoon-like as eyes and feet:

(Large preview)

Funny note: In his book, “Modern Cartooning: Essential Techniques for Drawing Today’s Popular Cartoons”, Christopher Hart shows two ways to draw the same shoe:

“It’s funnier to draw the boots in a quirky manner. The disadvantage is that they only come in a size 7.” (Large preview)

I decided to give the wolf typical facial expressions that were widely used in retro cartoons. Take a look at the image below (taken once again from Christopher Hart book):

(Large preview) “The circle shape is the most common eye shape. It can be used for almost any character.”

For the rest of my design, everything follows the same rules. The trees, the house, and even the clouds have that particular edgy effect.

(Large preview)

Now that you know how to get started, we can finally begin to bring our illustration to life!

Let’s fire up Adobe Illustrator.

3.2. How To Create A Basic Design

Once you open Illustrator, start with creating a new document first. I will create a square artboard for a square book cover. (Many children’s books have a square shape.)

(Image credits: Pam Keller) (Large preview)

Let’s go to File → New. In the open Window, I chose Print because I’d like to have my design printed. Then, I set 3000px × 3000px for the artboard size. Finally, I name it Little Red Riding Hood. See my setting below:

(Large preview) (Large preview)

Now you have to import the drawings. (I’ve provided the files for you here.)

Go to File → Place, choose the folder where you saved the drawings, and put them onto the artboard. Since the files are bigger than our artboard, just resize them to fit in.

(Large preview)

Put the drawings on two different layers, so we can have control on both of them.

(Large preview)

Once we have done, let’s go to the further step: create a brush to draw in Illustrator.

3.3. How To Create A Retro Brush

I have drawn some brushes myself, inventing something always based on the 50s style. As you can see in some examples below, used lines are not perfect. They always give the impression of something handmade.

So I grabbed my iPad and drawn some lines I liked in Procreate. I wanted to give the brushes a hand-drawn look, typical from 50s design, so this is my result:

(Large preview)

Note: For our mid-century-inspired illustration, I’ve provided the brushes for you here— feel free to download and use them.

So, let’s go back to Illustrator and see how the brushes can be installed.

Open the file you just downloaded and open it in Illustrator. Be sure your Brush Panel is open by clicking on Window → Brushes. Select the first brush from the file you just opened and drag it into the Brush Panel as shown below:

Large preview

As you can see, after I dragged the brush in the Brush Panel, I selected “Art brush” from the open window and renamed the brush. I checked the “Stretch to fit stroke length” option and then selected “Tint” as Colorization Method. This way, we will be able to change our brush color as well.

Let’s go on and drag all the brushes in the Brush Panel, following the same instructions as above. At the end, you should have five brushes:

(Large preview)

Nice! Your very own custom mid-century-inspired brushes!

Note: If you want your brushes be permanent in Illustrator, select them all and click on the first left icon at the bottom of the panel (“Brush Library Menu”). Then click on “Save Brushes”.

(Large preview)

Illustrator will save them in a “Brushes” folder as the default. Then you will see your custom brushes by clicking Brush Library Menu → User Defined.

3.4. How To Outline Drawings

With our new brushes, let’s begin to outline our design. You just need to select the brush you like most and begin to draw on the design lines.

If you don’t see the brushes in your panel, go on to Brush Library Menu → User Defined and choose mid-century01 (or whatever other name you used).

Select the layers with imported files and set their opacity to 50% through the Appearance panel:

(Large preview) (Large preview)

Once you’ve done that, lock them and create another layer on the top. Then, begin to trace:

(Large preview)

You can choose to work with just one or all of the brushes — it’s up to you. I suggest to use the first one for thinner lines, and the other ones for thicker lines. Of course, you can set the size of the brushes in any way you like.

(Large preview)

Have fun by tracing all of the lines. The thing I like the most are the trembling lines — that’s exactly the effect I desire.

Your finally design should look something like this:

(Large preview) 3.5. Further Details

Now, let’s add some details to our characters. I drew some stains with the help of the Blob Brush tool (Shift + B):

Large preview

This is the result:

(Large preview)

Another cute detail are the dotted lines on LRRH’s coat. They are very simple: open the Properties panel and click on Stroke. Check the Dashed Line and give 0 pt dash and 20 pt gap:

(Large preview)

Grab the Pencil tool (N) and draw dotted lines on the edges of the coat.

This is the result:

(Large preview)

Now that we’ve completed this step, we can now continue to the next one: adding colors, textures, and effects.

4. Colors, Textures And Patterns 4.1. Coloring Characters

The first thing we need is a palette to color our characters. I researched some colors on Pinterest and saved many interesting palettes on my Pinterest wall:

(Large preview)

I then created this palette for myself:

(Large preview)

Let’s insert our palette in the Swatches. Create some circles with these colors in Illustrator, then select them and open the Swatches panel through Windows → Swatches. With color circles selected, click on New Color Group:

(Large preview)

In the pop-up window, click on “Selected Artwork”, including “Convert Process to Global (the palette will be permanent in the Swatches panel) and “Include Swatches for Tints”.

(Large preview)

And now we have our palette in the swatches:

(Large preview)

Let’s color Little Red Riding Hood and the wolf. Go into the Layers panel and create a new layer below the other two:

(Large preview)

Grab the Blob Brush tool and begin to color on this layer. The lines of the characters will stay on top and colors on the bottom.

I set the Blob Brush as shown below:

(Large preview)

Take the time you need to color everything. This is a relaxing and fun step, so enjoy it!

(Large preview)

Here are my final colors:

(Large preview) 4.2. Brushes Effects

I used some other brushes to create shadow effects on the characters. The brushes are default in Illustrator; you can find them by clicking Brush Library Menu → Artistic → ChalkCharcoalPencil.

(Large preview)

Select one of them, go to Appearance and set the opacity to 15% Multiply.

(Large preview)

Now, draw some lines on the characters to create some shadow effects:

(Large preview) (Large preview) (Large preview)

And we’re done with the characters! Let’s move on to the background.

4.3. The Background

As first thought, we probably need to start with the sky. So let’s create another layer (under the characters) and rename it as “Sky”.

Draw a rectangle with the color #9BD2D2, then grab and drag a circle inwards to make the rectangle rounded.

Large preview

Again, let’s work with the Chalk brushes see 4.2. above. With the same color applied as the background. Brush some lines at the bottom of the rectangle to give some art effects:

(Large preview)

We will add some others brush effects to the sky. Create a new layer above the sky one and rename it as “Brushes effect”. With another charcoal brush (I used charcoal feather), draw some lines in the sky. The color is #FFFFFF with opacity set to 50%. See the image below.

(Large preview)

Now that wasn’t that hard, was it? Let’s draw some clouds now. You can use the Pencil tool (N) with #FFFFFF as the color and draw some simple shapes like the ones shown below:

(Large preview)

Next, draw a country lane with the Pencil tool (N) (again, with #FFFFFF as the fill color):

(Large preview)

Let’s add some tufts of grass. Select a brush as we did in 4.3 and draw them as shown below. Set the brush color to #1BA58E:

(Large preview)

By using the Rectangle tool (M), you can create simple shapes so let’s try to create a little house in the background as well. In order to make it a bit deformed, we need to use the Direct Selection tool (A), then grab and drag the angles.

Large preview

Let’s move on to the trees now. With the Polygon Tool, click just once on your artboard, so that a window appeary. Set “3 sides” and 100 px for Radius:

(Large preview)

For the triangle you just created, set the background color on #1BA58E. To make it look a bit deformed, use the the Direct Selection tool (A), then grab and drag the angles like we did when we created the house earlier.

(Large preview)

With the Pen tool (P), make a simple line in the center of the tree. Open Window → Stroke and set the stroke profile as shown below:

(Large preview)

The result should be something like this:

(Large preview)

Keep the same settings and draw some little lines with the Pen tool (P) to create a couple of branches:

(Large preview)

Let’s now group all tree elements, duplicate it or create some other trees to fill the scene. Put every tree on a different layer and play with layers to give depth to the scene.

Be brave. Try different shades of green for the trees:

(Large preview)

With the Ellipse tool (L), create some circles under the trees to simulate a shadow. Set the background to #000 and the opacity to 50%.

(Large preview) 4.4. Texture Effects

Let’s now add some effect to the trees, to make them more “retro”. I applied this effects just to the trees, but you are free to apply it to the entire design.

First of all, we need a texture. Since we work in vectors, we should apply a vector texture. You can download one for free (just googling “vector textures”. Anyway, I provided a vector texture for you here.

Download the texture and open it in Illustrator. Create a new layer and rename it as “Texture”.

(Large preview)

Put the texture on the new layer. Your illustration should look like this:

(Large preview)

Don’t be scared, we won’t ruin our design. We just need to make some changes.

Go to Windows > Appearance and set the Opacity on 15% and Blending Mode on Overlay. Then go to Object > Expand.

(Large preview)

In order to apply the texture just on trees, I deleted the superfluous parts of the texture with the Eraser tool (Shift + E). See my example below:

Large preview

Here my final result:

(Large preview)

All that remains is to make visible the layer with our characters and put them in the centre of the scene:

(Large preview)

As the very last thing, let’s create the title. Draw two simple black and white rectangles using the Rectangle tool (M) and write the title ad I show you in the image below. The fonts I used are Fontdiner Swanky and Fontdiner Sparkly (both free to download).

(Large preview)

Congratulations! You just finished your first Mid-Century Cover!

Next step is to complete our cover in InDesign. Ready?

5. How To Organize A Cover Into InDesign

Now I need to work in InDesign to prepare my cover for the print. Consider that we will need the front and back cover and must calculate a space for the spine.

I want my front cover size be 18 x 18 cm (7.00 × 7.00 in). Since I need to create everything in a single artboard, I need to put the pages side by side, plus a space more for the spine.

So, let’s set 37 cm width (18 cm front + 18 cm back + 1 cm spine) and 18 cm height. Other settings are 0,3 cm Margins and 0,3 cm Bleed.

(Large preview)

Create two guides, respectively on 18 and 19 cm.

(Large preview)

A quick back to Illustrator to save our cover design. If you have Adobe CC, you can use the Library to save your design. Open Window > Libraries, select everything on your artboard and drag to the library:

Large preview

By opening the Library in Indesign, you will find your cover. Drag it and drop into the page. Put it on the right side of it.

(Large preview)

For the back side i’d like to use just the Little Red Riding Hood Character. Go back to illustrator and drag it in the Library.

Large preview

Again, come back to InDesign and import the character into the page from Library the way I show you:

Large preview

Then write the title again, this time directly into InDesign. Feel free to play with the size and position of the words! Here my result:

(Large preview)

Let’s write the title on the spine too:

(Large preview)

And we’re done! Let’s export our file for the print.

Click on File > Export and choose Adobe PDF (Print).

In the General panel choose Adobe PDF Preset: High Quality Print. Leave the rest as it is.

In the Mark and Bleeds select All Printer’s Marks. Clic OK.

Here your result:

(Large preview)

Nice job! Bravo! You have finished this (quite long) tutorial!

6. The Final Result

Here some mockups to simulate the real book:

(Large preview) (Large preview) (Large preview) (Large preview)

I hope you enjoyed this tutorial, and — most of all — I hope I was able to convey to you my passion for mid-century design!

Try it out, and please share your own illustrations and thoughts in the comments below.

(yk, il)
Categories: Web Design

Finding Inspiration In Digital Influencers

Smashing Magazine - Thu, 05/09/2019 - 04:30
Finding Inspiration In Digital Influencers Finding Inspiration In Digital Influencers Suzanne Scacca 2019-05-09T13:30:59+02:00 2019-05-23T09:05:51+00:00

You want your client’s website to become the go-to destination for their target audience. So, you design them to look great, work perfectly and rank well in search. Is that enough? It could be, though I have a sneaking suspicion that the growing millennial and Gen Z consumer base are going to complicate that with their mobile-loving ways.

An eMarketer report from 2018 revealed that consumers’ time spent on mobile devices is about to surpass time spent watching TV:

eMarketer shows the TV versus mobile device statistics flip. (Image source: eMarketer) (Large preview)

And here’s why that matters so much:

TV is littered with celebrities. As consumers spend more time with their smartphones, there’s going to be a fundamental shift from trusting and admiring celebrities to trusting and admiring digital influencers.

In this post, I’m going to explain:

  • What a digital influencer is (as opposed to a celebrity or lifestyle influencer).
  • Why they’re so successful in building trust with their target audience.
  • How to leverage certain influencer-like qualities to attract higher levels of consistent traffic (and business) for the websites you build.

To be clear, this post has nothing to do with turning your clients’ websites into sponsor-driven money-making machines. This is about giving your website the same kind of clout as a digital influencer — and using that perceived expert status to consistently maintain high levels of traffic, engagement and referrals.

What Is An Influencer?

In the past, celebrities were mainly the ones that companies turned to promote their products or services. While that still happens today, you’re more likely to see celebrity influencers pushing luxury products.

Thanks to the Internet and social media, businesses no longer have to pay top-dollar to get a celebrity endorsement. Instead, we’re now seeing the rise of digital influencer marketing.

A digital influencer is one that’s built a brand around their expertise or knowledge. There are different ways to be an influencer, too:

  • Content creators
  • Industry experts
  • Micro-influencers (these are average joes who’ve amassed a following of more than 500)
  • Thought leaders.

In reality, you’ll find that most digital influencers cover each one of these categories. For example, you have Neil Patel:

Neil Patel has hundreds of thousands of followers and a highly engaged audience. (Image source: Neil Patel) (Large preview)

He’s an entrepreneur, content creator, thought leader, trusted expert in content marketing and has way more than 500 followers wherever you encounter him online.

That’s obviously an extreme example of a digital influencer though. How about we look at a web developer that’s established himself as an authority in his space?

This is Iain Poulson’s Twitter account:

Iain Poulson is a micro-influencer web developer. (Image source: Iain Poulson) (Large preview)

Although his follower count and engagement levels don’t reach that of macro-influencers like Patel, it doesn’t make his words any less impactful with his target audience (on or off Twitter). The point is that he creates high-quality and engage-worthy content that his audience recognizes as such.

Regardless of the size of the influencer and the space in which they work, their words command so much authority that consumers can’t help but trust them. This is the power of the digital influencer.

This is why businesses flock to influencers for help in getting the word out about their brand. If a business can leverage that built-in authority, it can grow its follower and customer base with a solid recommendation from that influencer. Influencer Marketing Hub reports that those who’ve used influencer marketing earn $7.65, on average, for every $1.00 paid to a digital influencer.

Needless to say, digital influencers are powerful and valuable entities in the world we live in. Now, we need to look at how you can imbue your websites with digital influencer-like qualities to increase their own value on the web.

How To Turn Websites Into Digital Stars

To turn a website into a digital influencer-like entity, you have to make it embody those qualities that make digital influencers so trustworthy and powerful in the first place.

For the purposes of demonstrating what these qualities are, I’m going to use websites that represent today’s top digital influencers and/or their businesses.

Whether you’re in the process of building a new site for a client or you’re looking for a way to rebrand or upgrade one that already exists, use these tips to up the influencer factor:

1. Let the Navigation Tell Your Story

In general, the navigation (and sitemap) of a website is a very powerful tool for both your visitors as well as search engines.

The only thing is, many websites use a similarly-structured and labeled navigation. That’s fine if the website’s offer is plain and simple:

  • This is the product we sell (“Products” or “Services”).
  • This is who we are (“About” or “Team”).
  • Get in touch or buy the product (“Contact Us” or “Buy Now”).

What makes many digital influencers stand apart is that they’ve crafted a robust brand for themselves, which means they’re usually a double- or triple-threat. And they make sure the navigation highlights each of these strengths or offerings.

Social Media Examiner, for instance, demonstrates that it’s not just a blog containing posts related to social media. Social Media Examiner does it all:

The Social Media Examiner mobile website navigation (Image source: Social Media Examiner) (Large preview)

As you can see, the navigation shows you all of the different ventures Social Media Examiner has going on:

  • Blogging
  • Podcasting
  • Membership
  • A live conference.

It’s an impressive list and one that will instantly demonstrate to visitors that they are the authority on social media.

The Marketing Nutz takes a similar approach with its navigation:

The Marketing Nutz navigation on mobile (Image source: The Marketing Nutz) (Large preview)

This navigation, however, is less focused on authority-building content. Instead, it highlights all of the ways in which it empowers its followers to get more out of their social media efforts with:

  • Social media training
  • Information on Pam Moore as a keynote speaker
  • Free social media management tools and ebooks
  • A regularly updated blog.

In sum, your navigation needs to be able to demonstrate the website’s/brand’s expertise and value within seconds. It should also be one that has visitors thinking, “Wow! They do all that?”

2. Lead with a Strong Visual

Another way to establish authority immediately is with a strong and unique visual. This sends the signal that this website isn’t just going to be a place to get information. It’s a place to actually experience something.

Take a look at the Youpreneur website:

The Youpreneur’s striking image and animated text (Image source: Youpreneur) (Large preview)

What you can’t see in the screenshot above is the animation directly below the image and tagline that definitely took some time to design.

See the cursor after the word “speaker”? This is a text animation that types out and deletes different entrepreneurial titles. Speaker. Blogger. Consultant. If the banner image didn’t capture their attention, this certainly will.

Jay Baer’s personal website is another beautiful example of making a strong impression with visuals.

Jay Baer uses a combination of image, colorful filter and video to make a strong first impression. (Image source: Jay Baer) (Large preview)

Not only does he include a uniquely personal photo of himself in the hero section of the home page, but he has also applied a powerful color filter atop it. Further, he leads with a call-to-action for visitors to watch his five-minute video.

Although the messaging puts the focus on the customer, these strong visuals simultaneously convey that Jay Baer is someone they need to stop and listen to.

You’ll want to strike the same balance with your own entry visuals and messaging. Make sure the text lets visitors know there’s something really valuable here to stick around for. But be savvy in how you design the visuals surrounding that message. There’s a lot you can to do to convince visitors that they’ve entered the website of authority instead of just a service provider or seller.

Recommended reading: Reasons Your Mobile App Retention Rate Might Be So Low

3. Be Ripe with Content

I touched on this point slightly in the navigation point, though I think it’s worth taking a closer look so you can see the ways influencer websites produce and disseminate a variety of content.

Here is the Single Grain blog:

Single Grain’s blog page (Image source: Single Grain) (Large preview)

Single Grain’s blog is full of new and cutting-edge posts on the subject of digital marketing. As you scroll down the page, you’ll soon see that each of the featured images is designed in the same manner. All are customly illustrated and contain a mix of visuals and light text.

This not only gives the blog a consistent and easily recognizable look, but it also gives the content an edge up when it gets shared on social media. Imagine you’re looking through your social media feed and happen upon a short post with a descriptive image attached to it. In a sea of image-less posts or ones that use meaningless stock images, this kind of visual content is sure to stand out.

Now, what’s interesting about Single Grain is that its podcasts page has a different style from the blog:

Single Grain’s podcast page (Image source: Single Grain) (Large preview)

You can tell right away that the lightness in design and custom illustrations for the blog posts have no place here. Instead, Single Grain uses a more traditional design and layout for its Growth Everywhere podcast.

That doesn’t necessarily say anything about the kind of content covered here compared to the blog; it’s not more serious in nature nor is it created by someone with more traditional leanings. It’s simply a matter of designing for the channel. In this case, simpler and less customized makes more sense for a podcast.

As you bring together the pieces of your client’s website, don’t feel as though all of their content needs to be shoved under a single “Resources” tab and designed in the same manner.

Instead, give each content channel (e.g. blog posts, podcast episodes, video training, etc.) a separate tab and design it in a way that makes the most sense. For instance, you want visitors to spend a lot of time looking through a blog post, so you might design custom yet consistently styled graphics for each one. With something like an ebook, you’d keep it simple: show a picture of a bound book (even if it’s a digital-only book) and pair it with some intro text.

Influencers treat their different channels like sub-brands with unique identities. You should do the same.

Recommended reading: Designing For Micro-Moments

4. Confidently Collect Leads

Recently, I wrote about how to design lead gen landing pages for mobile. There were different examples included (a SaaS company, a digital magazine, a monthly subscription box company, etc.), which isn’t surprising considering how valuable lead generation is for online businesses.

That said, you’d be hard-pressed to find a digital influencer that doesn’t have a lead magnet offer on his or her website. It’s almost a guarantee.

The main difference between how some websites promote their lead gen offers and how digital influencers do it is the strength of the message and design.

This is the blog of Tim Ferriss:

Tim Ferriss’ strongly worded and designed lead magnet promo (Image source: Tim Ferriss) (Large preview)

All this is is a promotional banner asking visitors to subscribe to the blog. Take note, however, that this isn’t posed as a request. This is an invitation to something special. And it’s intense. This is because of the special way in which the banner is designed:

  • The solid black background;
  • The words “EXCLUSIVE CONTENT”;
  • The red all-capped letters;
  • The call to “GET ACCESS”.

This is not at all the kind of thing you’d see on most websites and that’s because many of them just don’t exude the kind of in-your-face confidence and authority that digital influencers do.

Kim Garst is another influencer with an eye-catching lead gen banner:

Kim Garst’s engaging lead capture form (Image source: Kim Garst) (Large preview)

Clearly, the color palette is one you can’t help but stop and look at. The teal and purple colors are pretty safe choices, but it’s the contrast of the red callouts that gives this an edge.

Also, check out the wording she uses — it’s very similar to how Ferriss gave his lead gen an air of exclusivity. With Kim’s lead gen promo, she uses strong wording like “Top Secret”, “Discover” and “A Matter of Minutes”. If visitors weren’t feeling as though they had to read any more of the content on her website, this would surely get them to reconsider.

Bottom line: to demonstrate your authority, you can’t waiver nor can you provide a soft sell (e.g. “Subscribe here”) when promoting a lead magnet. Instead, your messaging and design both need to convey the confidence and authority that tell visitors:

“Don’t miss this special opportunity to peek inside my brain and gain more valuable knowledge and skills than you could ever ask for!” Wrapping Up

Digital influencers are a special breed, that’s for sure. But that doesn’t mean you can’t draw lessons from how they’ve managed to convey and reinforce authority through their websites.

What’s nice about digital influencer websites is that they show you that obvious cash-grab features (like affiliate advertising and gated content) aren’t necessary in order to increase conversions. By designing your website as an authority, you’ll see an increase in traffic, be able to more easily collect leads, and establish long-term trust with an audience.

The revenue increase will come naturally as visitors are dying to share the news about what they discovered.

Further Reading on SmashingMag: (ra, yk, il)
Categories: Web Design

New in structured data: FAQ and How-to

Google Webmaster Central Blog - Wed, 05/08/2019 - 08:46

Over the last few weeks, we've been discussing structured data: first providing best practices and then showing how to monitor it with Search Console. Today we are announcing support for FAQ and How-to structured data on Google Search and the Google Assistant, including new reports in Search Console to monitor how your site is performing.

In this post, we provide details to help you implement structured data on your FAQ and how-to pages in order to make your pages eligible to feature on Google Search as rich results and How-to Actions for the Assistant. We also show examples of how to monitor your search appearance with new Search Console enhancement reports.

Disclaimer: Google does not guarantee that your structured data will show up in search results, even if your page is marked up correctly. To determine whether a result gets a rich treatment, Google algorithms use a variety of additional signals to make sure that users see rich results when their content best serves the user’s needs. Learn more about structured data guidelines.How-to on Search and the Google AssistantHow-to rich results provide users with richer previews of web results that guide users through step-by-step tasks. For example, if you provide information on how to tile a kitchen backsplash, tie a tie, or build a treehouse, you can add How-to structured data to your pages to enable the page to appear as a rich result on Search and a How-to Action for the Assistant.

Add structured data to the steps, tools, duration, and other properties to enable a How-to rich result for your content on the search page. If your page uses images or video for each step, make sure to mark up your visual content to enhance the preview and expose a more visual representation of your content to users. Learn more about the required and recommended properties you can use on your markup in the How-to developer documentation.


    
Your content can also start surfacing on the Assistant through new voice guided experiences. This feature lets you expand your content to new surfaces, to help users complete tasks wherever they are, and interactively progress through the steps using voice commands.

As shown in the Google Home Hub example below, the Assistant provides a conversational, hands-free experience that can help users complete a task. This is an incredibly lightweight way for web developers to expand their content to the Assistant. For more information about How-to for the Assistant, visit Build a How-to Guide Action with Markup.


    
To help you monitor How-to markup issues, we launched a report in Search Console that shows all errors, warnings and valid items for pages with HowTo structured data. Learn more about how to use the report to monitor your results.


FAQ on Search and the Google AssistantAn FAQ page provides a list of frequently asked questions and answers on a particular topic. For example, an FAQ page on an e-commerce website might provide answers on shipping destinations, purchase options, return policies, and refund processes. By using FAQPage structured data, you can make your content eligible to display these questions and answers to display directly on Google Search and the Assistant, helping users to quickly find answers to frequently asked questions.

FAQ structured data is only for official questions and answers; don't add FAQ structured data on forums or other pages where users can submit answers to questions - in that case, use the Q&A Page markup.

You can learn more about implementation details in the FAQ developer documentation.



To provide more ways for users to access your content, FAQ answers can also be surfaced on the Google Assistant. Your users can invoke your FAQ content by asking direct questions and get the answers that you marked up in your FAQ pages. For more information, visit Build an FAQ Action with Markup.


To help you monitor FAQ issues and search appearance, we also launched an FAQ report in Search Console that shows all errors, warnings and valid items related to your marked-up FAQ pages.

We would love to hear your thoughts on how FAQ or How-to structured data works for you. Send us any feedback either through Twitter or our forum.

Posted by Daniel Waisberg, Damian Biollo, Patrick Nevels, and Yaniv Loewenstein
Categories: Web Design

SVG Web Page Components For IoT And Makers (Part 1)

Smashing Magazine - Wed, 05/08/2019 - 04:00
SVG Web Page Components For IoT And Makers (Part 1) SVG Web Page Components For IoT And Makers (Part 1) Richard Leddy 2019-05-08T13:00:16+02:00 2019-05-23T09:05:51+00:00

The IoT market is still in its early stages, but gathering steam. We are at a cusp in the history of IoT. Markets are quadrupling in the course of five years, 2015 to 2020. For web developers, this IoT growth is significant. There is already a great demand for IoT web techniques.

Many devices will be spread out geospatially, and its owners will desire remote control and management. Full web stacks must be made in order to create channels for teleoperation. Also, the interaction will be with one or more IoT devices at a time. The interaction must be in the real time of the physical world.

This discussion delves into the interface requirements using Vue.js as a catalyst and illustrates one method of webpage to device communication out of many subsitutions.

Here are some of the goals planned for this discussion:

  1. Create a single page web app SPWA that hosts groups of IoT human-machine interfaces (we may call these “panel groups”);
  2. Display lists of panel group identifiers as a result of querying a server;
  3. Display the panels of a selected group as a result of a query;
  4. Ensure that the panel display is loaded lazily and becomes animated quickly;
  5. Ensure that panels synchronize with IoT devices.
IoT And The Rapid Growth Of Web Pages

The presentation of graphics for visualization and remote control of hardware along with synchronization of web pages with real-time physical processes are within the realm of web page problem solving inherent in this IoT future.

Many of us are beginning our search for IoT presentation techniques, but there are a few web standards along with a few presentation techniques that we can begin using now. As we explore these standards and techniques together, we can join this IoT wave.

Dashboards and data visualization are in demand. Furthermore, the demand for going beyond web pages that provide forms or display lists or textual content is high. The dashboards for IoT need to be pictographic, animated. Animations must be synchronized with real-time physical processes in order to provide a veridical view of machine state to users. Machine state, such as a flame burning or not, trumps application state and provides critical information to operators, perhaps even safety information.

The dashboards require more than the visualization of data. We have to keep in mind that the things part of IoT is devices that not only have sensors but also control interfaces. In hardware implementations, MCUs are extended with switches, threshold switches, parameter settings, and more. Still, web pages may take the place of those hardware control components.

Nothing new. Computer interfaces for hardware have been around for a long time, but the rapid growth of web page use for these interfaces is part of our present experience. WebRTC and Speech API are on a development path that started in 2012. WebSockets has been developing in a similar time frame.

IoT has been in our minds for a long time. IoT has been part of the human dialog since 1832. But, IoT and wireless as we are coming to know it was envisioned by Tesla around 1926. Forbes 2018 State of Iot tells us the current market focus for IoT. Of interest to web developers, the article calls out dashboards:

“IoT early adopters or advocates prioritize dashboards, reporting, IoT use cases that provide data streams integral to analytics, advanced visualization, and data mining.”

The IoT market is huge. This Market Size article gives a prediction for the number of devices that will appear: 2018: 23.14 billion ⇒ 2025: 75.44 billion. And, it attempts to put a financial figure on it: 2014: \$2.99 trillion ⇒ 2020: $8.90 trillion. The demand for IoT skills will be the fastest growing: IoT in Demand.

As we develop clear interfaces for controlling and monitoring devices, we encounter a new problem for developing our interfaces. All the many billions of devices will be owned by many people (or organizations). Also, each person may own any number of devices. Perhaps even some of the devices will be shared.

Modern interfaces that have been made for machine controls often have a well-defined layout specific to a particular machine or installation of a few machines. For instance, in a smart house, a high-end system will have an LCD with panels for carefully placed devices. But, as we grow with the web version of IoT, there will be any number of panels for a dynamic and even mobile stream of devices.

The management of panels for devices becomes similar to managing social connections on social web sites.

“Our user interfaces will have to be dynamic in managing which highly animated real-time panel must be displayed at any one time for each particular user.”

The dashboard is a single page web app SPWA. And, we can imagine a database of panels. So, if a single user is going to access a number of panels and configurations for his devices strewn about the planet, the SPWA needs to access panel components on demand. The panels and some of their supporting JavaScript will have to load lazily.

“Our interfaces will have to work with web page frameworks that can allow incorporating asynchronous component bindings without reinitializing their frameworks.”

Let’s use Vue.js, WebSockets, MQTT, and SVG to make our step into the IoT market.

Recommended reading: Building An Interactive Infographic With Vue.js

High-Level Architecture For An IoT Web App

When designing the interface for the IoT web page, one always has many options. One option might be to dedicate one single page to one single device. The page might even be rendered on the server side. The server would have the job of querying the device to get its sensor values and then putting the values into the appropriate places in the HTML string.

Many of us are familiar with tools that allow HTML templates to be written with special markers that indicate where to put variable values. Seeing {{temperature}} in such a template tells us and the view engine to take the temperature queried from a device and replace the {{temperature}} symbol with it. So, after waiting for the server to query the device, the device responding, rendering the page, and delivering the page, the user will finally be able to see the temperature reported by the device.

For this page per device architecture, the user may then wish to send a command to the device. No problem, he can fill out an HTML form and submit. The server might even have a route just for the device, or perhaps a little more cleverly, a route for the type of device and device ID. The server would then translate the form data into a message to send to the device, write it to some device handler and wait for an acknowledgment. Then, the server may finally respond to the post request and tell the user that everything is fine with the device.

A web page architecture for treating the IoT as a form server — looking for something better. (Large preview)

Many CMSs work in this way for updating blog entries and the like. Nothing seems strange about it. It seems that HTML over HTTP has always had the design for getting pages that have been rendered and for sending form data to be handled by the web server. What’s more, there are thousands of CMS’s to choose from. So, in order to get our IoT system up, it seems reasonable to wade through those thousands of CMS’s to see which one is right for the job. Or, we might apply one filter on CMS’s to start with.

We have to take the real-time nature of what we are dealing with into consideration. So, while HTML in its original form is quite good for many enterprise tasks, it needs a little help in order to become the delivery mechanism for IoT management. So, we need a CMS or custom web server that helps HTML do this IoT job. We can also just think of the server as we assume CMS’s provide server functionality. We just need to keep in mind that the server has to provide event-driven animation, so the page can’t be 100% finalized static print.

Here are some parameters that might guide choices for our device-linked web page, things that it should do:

  1. Receive sensor data and other device status messages asynchronously;
  2. Render the sensor data for the page in the client (almost corollary to 1);
  3. Publish commands to a particular device or group of devices asynchronously;
  4. Optionally send commands through the server or bypass it.
  5. Securely maintain the ownership relationship between the device and the user;
  6. Manage critical device operation by either not interfering or overriding.

The list comes to mind when thinking about just one page acting as the interface to a selected device. We want to be able to communicate with the device freely when it comes to commands and data.

As for the page, we need only ask the web server for it once. We would expect that the web server (or associated application) would provide a secure communication pathway. And, the pathway does not have to be through the server, or maybe it should avoid the server altogether as the server may have higher priority tasks other than taking care of one page’s communication for data coming from sensors.

In fact, we can imagine data coming in from a sensor once a second, and we would not expect the web server itself to provide a constant second by the second update for thousands of individual sensor streams multiplied by thousands of viewers. Of course, a web server can be partitioned or set up in a load balancing framework, but there are other services that are customized for sensor delivery and marshaling commands to hardware.

The web server will need to deliver some packet so that the page may establish secure communication channels with the device. We have to be careful about sending messages on channels that don’t provide some management of the kinds of messages going through. There has to be some knowledge as to whether a device is in a mode that can be interrupted or there may be a demand for user action if a device is out of control. So, the web server can help the client to obtain the appropriate resources which can know more about the device. Messaging could be done with something like an MQTT server. And, there could be some services for preparing the MQTT server that can be initiated when the user gains access to his panel via the web server.

Because of the physical world with its real-time requirements and because of additional security considerations, our diagram becomes a little different from the original.

A single page app that talks to one MCU. It now interacts asynchronously with the MCU independently of the web page server. (Large preview)

We don’t get to stop here. Setting up a single page per device, even if it is responsive and handles communication well, is not what we asked for. We have to assume that a user will log in to his account and access his dashboard. From there, he will ask for some list of content projects (most likely projects he is working on). Each item in the list will refer to a number of resources. When he selects an item by clicking or tapping, he will gain access to a collection of panels, each of which will have some information about a particular resource or IoT device.

Any number of the panels delivered in response to the query generated as a result of the user’s interface action may be those panels that interact with live devices. So, as soon as a panel comes up, it will be expected to show real-time activity and to be able to send a command to a device.

How the panels are seen on the page is a design decision. They might be floating windows, or they might be boxes on a scrollable background. However that is presented, panels will be ticking off time, temperature, pressure, wind speed, or whatever else you can imagine. We expect the panels to be animated with respect to various graphic scales. Temperature can be presented as a thermometer, speed as a semicircular speed gauge, sound as a streaming waveform, and so on.

The web server has the job of delivering the right panels to the right user given queries to a database of panels and given that devices have to be physically available. What’s more, given that there will be many different kinds of devices, the panels for each device will likely be different. So, the web server should be able to deliver the pictographic information needed for rendering a panel. However, the HTML page for the dashboard should not have to be loaded with all the possible panels. There is no idea of how many there will be.

Here are some parameters that might guide choices for our dashboard page, things that it should do:

  1. Present a way of selecting groups of related device panels;
  2. Make use of simultaneous device communication mechanisms for some number of devices;
  3. Activate device panels when the user requests them;
  4. Incorporate lazily loaded graphics for unique panel designs;
  5. Make use of security tokens and parameters with respect to each panel;
  6. Maintain synchronicity with all devices under user inspection.
A single page app that talks to multiple MCU's, asynchronously and independently of the web page server. (Large preview)

We can begin to see how the game changes, but in the world of dashboard design, the game has been changing a little bit here and there for some time. We just have to narrow ourselves down to some up to date and useful page development tools to get ourselves up and going.

Let’s start with how we can render the panels. This already seems like a big job. We are imagining many different kinds of panels. But, if you ever used a music DAW, you would see how they have used graphics to make panels look like the analog devices used by bands from long ago. All the panels in DAW’s are drawn by the plugins that operate on sound. In fact, a lot of those DAW’s plugins might use SVG to render their interfaces. So, we limit ourselves to handling SVG interfaces, which in turn can be any graphic we can imagine.

Choosing SVG For Panels

Of course, I like DAWs and would use that for an example, but SVG is a web page standard. SVG is a W3C standard. It is for carrying line drawings to the web pages. SVG used to be a second class citizen on the web page, required to live in iFrames. But, since HTML5, it has been a first class citizen. Perhaps, when SVG2 comes out, that it will be able to use form elements. For now, form elements are Foreign Objects in SVG. But, that should not stop us from making SVG the substrate for panels.

SVG can be drawn, stored for display, and it can be lazily loaded. In fact, as we explore the component system we will see that SVG can be used for component templates. In this discussion, we will be using Vue.js to make components for the panels.

Drawing SVG is not difficult, because there are many line drawing programs that are easy to get. If you spend the money, you can get Adobe Illustrator, which exports SVG. Inkscape has been a goto for SVG creation for some time. It is open source and works well on Linux, but can also be run on Mac and Windows. Then, there are several web page SVG editing programs that are open source, and some SaaS versions as well.

I have been looking around for an open-source web-based SVG editor. After some looking around, I came upon SVG-Edit. You can include it in your own web pages, perhaps if you are making an SVG based blog or something.

An electric diagram is pretty detailed, but we can obtain it easily in SVG and animate it with just a little code. (Large preview)

When you save your work to a file, SVG-Edit downloads it in your browser, and you can pick up the file from your download directory.

The picture I have drawn shows an AND gate controlling an integrator. That is not what one would usually expect to see in a panel for an MCU. The panel might have a button to feed one of the AND gate inputs, perhaps. Then it might have a display from an ADC that reads the output of the integrator. Perhaps that will be a line chart on a time axis. Most panels will have graphics that allow the user to relate to what is going on inside the MCU. And, if our circuit is going to live anywhere, it will be inside the MCU.

All the same, our electronic diagram can be used to discuss animation. What we want to do is take a look at the SVG and see where we can get at some of the DOM tags that we would like to change in some way. We can then animate the SVG by using a little vanilla JavaScript and a timer. Let’s make the AND gate blink in different colors.

The SVG that we are looking for is in the following code box. It doesn’t look very friendly for the programmer, although the user will be quite happy. Nevertheless, there are still some cues to go on for finding which DOM element we wish to operate on. First, most SVG drawing tools have a way of getting at object properties, in particular, the id attribute. SVG-Edit has a way, too. In the editor, select the AND gate and observe the toolbar. You will see a field for the id and the CSS class as well.

One of the SVG drawing tools with a way to capture the object id using the provided interface. (Large preview)

If you can’t get to an editing tool for some reason, you can open the SVG up in a browser and inspect the DOM. In any case, we have found that our gate had id = “svg_1”.

<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g class="layer"> <title>Layer 1</title> <path d="m80.59881,87.020171l14.714795,0m-14.714793,-11.938687l14.714797,0.000004m-0.033867,-6.543869l0,24.758504c42.377882,2.221929 43.364812,-27.139117 0,-24.758504zm47.366321,12.333056l-15.303943,0m-48.188699,-6.489897l1.454753,0l0,1.454751l-1.454753,0l0,-1.454751zm-0.068425,11.869359l1.454753,0l0,1.454753l-1.454753,0l0,-1.454753zm63.545246,-6.089294l1.454751,0l0,1.454751l-1.454751,0l0,-1.454751z" fill="#FF0000" id="svg_1" stroke="#000000"/> <path d="m48.58886,119.662231l18.234678,0l2.523043,-7.173309l4.128604,13.808613l4.587337,-13.987948l4.013933,13.808613l4.35797,-13.629278l4.35797,13.718944l2.408353,-6.72497l18.349357,0m-64.482612,-0.623112l1.515724,0l0,1.515728l-1.515724,0l0,-1.515728zm64.484275,-0.103111l1.515721,0l0,1.515728l-1.515721,0l0,-1.515728z" fill="#FF0000" id="svg_3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="rotate(90.3367 80.0675 119.304)"/> <polygon cx="108.5" cy="79.5" edge="0" fill="#ffffff" id="svg_6" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="#000000"/> <polygon cx="215.5" cy="192.5" edge="0" fill="#ffffff" id="svg_7" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="165.5" cy="164.5" edge="0" fill="#ffffff" id="svg_8" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="161.5" cy="138.5" edge="0" fill="#ffffff" id="svg_9" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="160.5" cy="161.5" edge="0" fill="#ffffff" id="svg_10" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <g id="svg_23"> <path d="m225.016923,53.008793l0,3.419331m-4.558966,-1.709666l9.11791,0m10.303228,4.235512l-25.770656,0m-34.429182,0l24.544724,0m0.220544,-4.058194l1.543807,0l0,8.164451l-1.543807,0l0,-8.164451zm7.939567,-4.473673l1.543805,0l0,16.999955l-1.543805,0l0,-16.999955zm-34.176663,8.126854l1.474036,0l0,0.747515l-1.474036,0l0,-0.747515zm61.677552,0.018809l1.474038,0l0,0.747515l-1.474038,0l0,-0.747515z" fill="#FF0000" id="svg_4" sides="3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <polygon cx="171.5" cy="159.5" edge="43.256342" fill="#ffffff" id="svg_5" orient="x" points="223.47406005859375,91.5 186.01296997070312,113.128173828125 186.01296997070312,69.871826171875 223.47406005859375,91.5 " shape="regularPoly" sides="3" stroke="#000000" stroke-width="null" strokeWidth="null" strokecolor="#000000"/> <line fill="none" id="svg_12" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171" x2="186" y1="103.5" y2="103.5"/> <path d="m130.801817,80.659041l15.333707,0l2.12165,-4.564833l3.47178,8.787299l3.857534,-8.901421l3.375353,8.787299l3.664657,-8.673176l3.664657,8.730237l2.025206,-4.279526l15.430142,0m-54.224016,-0.396526l1.274586,0l0,0.964554l-1.274586,0l0,-0.964554zm54.225414,-0.065616l1.274584,0l0,0.964554l-1.274584,0l0,-0.964554z" fill="none" id="svg_14" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <line fill="none" id="svg_15" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171.5" x2="171.5" y1="103.75" y2="135.388167"/> <line fill="none" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="177.75" x2="177.75" y1="58.75" y2="80.255951"/> <line fill="none" id="svg_17" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="223.75" x2="266.854524" y1="91.75" y2="91.75"/> <line fill="none" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="241.75" x2="241.75" y1="59.75" y2="91.754167"/> <line fill="none" id="svg_19" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="168.25" x2="180.75" y1="135.75" y2="135.75"/> <line fill="none" id="svg_20" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="169.75" x2="179.25" y1="138.5" y2="138.5"/> <line fill="none" id="svg_22" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" x1="171" x2="179.75" y1="141.25" y2="141.25"/> </g> </g> </svg>

All we need now is a little JavaScript. We do take note first that the element attribute “fill” is present. Then there is just the simple program that follows:

<html> <head> </head> <body> <!-- ALL THE SVG FROM ABOVE GOES HERE --> </body> <html> </svg> <script> // Set up a timer interval flash the color. var gateElement = document.getElementById("svg_1"); if ( gateElement ) { setInterval( () => { var fillC = gateElement.getAttribute("fill"); gateElement.setAttribute("fill", (fillC == "#00FF00") ? "#FF0000" : "#00FF00" ); }, 2000 ) } </script>

Notice that what we have is a minimal HTML page. You can cut and paste the code into your favorite editor. And, then don’t forget to cut and paste the SVG to replace the comment. My version of Chrome requires the page to be HTML in order to have the JavaScript section. So, that is one browser still treating SVG as something separate. But, it is a long way from the <iframe> days.

If you cut and paste just right, you can bring up the page and see the AND gate go from red to green over and over.

Recommended reading: SVG Circle Decomposition To Paths

Building Panels From VUE Components

We are already on our way to making any single panel come alive, but if we want to manage large collections of panels in sensible ways, we would have our work cut out for us. That would especially be the case if we simply built on our first example.

While the first example shows us how we can asynchronously change an object view, it does not show us how to tie the view to the state of any data object let alone one that manages a machine. We can certainly understand how the setInterval demonstration can be replaced by a fetch handler, but we might not even get the state of a machine from the web server that serves the SVG containing page. Also, when we get the data, our programs are now required to know about the DOM structure of the given page.

Fortunately, frameworks such as Vue have become popular, and they can save us a lot of work.

It’s easy to find out about Vue. The Vue documentation is very accessible. So, if this discussion jumps too far ahead, then you may spend some time learning about Vue on its own web site. But, there are very good discussions within the Smashing pages. Krutie Patel wrote a stunning article on making an infographic. Souvik Sarkar tells us how to build a weather dashboard with Vue.

Group Selection of Related Panels

For the first step, we should address searching for groups of panels. One reason for doing this first is that it is at the framework level of our human interactions.

The user searches for something he is interested in. Perhaps he is interested in all the devices at locations in one town. Perhaps he has many batches of liquid products and he wants to narrow down to one type of product with each batch governed by a small collection of IoT devices. So, the user will first search to get a small list.

Here is the process:

  1. Search for groups of panels by features/parameters.
  2. View a list of icons representing groups.
  3. Select an icon (click/tap).
  4. Start using panels identified with the icon when they come up.

Another reason this is a good first step is that we can use Vue in its simplest form. No build tools needed. We will just include vue.js with a script tag in HTML. In fact, we don’t even have to download it. There is a site where a working copy of vue.js is being served.

All we need is the following tag:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script>

I copied the script tag directly from the Vue documentation about installation.

Now, we need a web page that can load icons and make them into something that clicks. Vue makes that very easy. In fact, I just wrote a little app to manage a Twitter list using Vue. It just manages text fields. As it is a tiny bit simpler than an SPWA using icons, we can have a look at it and then change it to be our desired single page app framework.

Here is part of what the page looks like:

A text-based page to use as a starting point for building a graphics application. (Large preview)

This looks like a fairly simple page. Each outer numerical entry is a time slot with one or two tweets in it. The second tweet is optional. If you edit a tweet, Vue mechanisms update a JavaScript object. This page leaves it up to the user to click the “update entries” button to tell the server that something has changed, via its button handler function.

In order for the button handler to relay data to the server, it must change the Vue data object into a JSON string. Now, you may wonder just how difficult translating a Vue object to JSON will be. It turns out to be one line of code. You can find the line in the following source code, but if you want to find it faster, it is highlighted in the paragraph after the source code.

The page looks simple. Looks can be deceiving. Of course, the page looks simple, but is the code simple? Yes, indeed it is! Using Vue, the page manages the contents of the fields almost magically. Here is the code:

<!DOCTYPE html> <html lang="en" prefix="og: http://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="http://schema.org/Article"> <title>Tweet Keeper</title> <style> body { margin: 2em; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin-bottom: 3px; background-color: #EEF4EE; } </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script> </head> <body onload="GetTweets()"> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div id="tweetAppDiv"> <!-- Recognize the name from the Vue doc --> <div itemscope itemtype="http://schema.org/Article"> <h1 itemprop="name">mangage tweets</h1> <p itemprop="description">My personal Tweet engine. This page accesses a personal tweet page that belongs to {{tweetOwner}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button onclick="sendTweets(event)">Update Entries</button> </div> <!-- Here is a Vue loop for generating a lit --> <ol> <li v-for="tweet in tweets"> <!-- here is the first tweet represented as an object with a lable and tweet text --> <div class="entryart"> <input v-model="tweet.def[0].label" /> <input style="width:40%" v-model="tweet.def[0].tweet" /> </div> <!-- here is the second tweet in the slot. But, notice that it is optional. --> <div class="entryart" v-if="tweet.def.length > 1"> <input v-model="tweet.def[1].label"/> <input style="width:40%" v-model="tweet.def[1].tweet"/> </div> </li> </ol> </div> <script> var twtApp = new Vue({ el: '#tweetAppDiv', data: { tweets: [ // Where is the data? Still on the server.s ], tweetOwner : "Lucky Dude" // picked a name for demo } }); </script> </body> </html> <script> // Notice that you don’t have to do everything in the Vue framework. // Here we are using some native API calls var gDefaultPostInfo = { // there server is beyond simple - an example from node.js docs method: 'POST', // or 'PUT' mode: "cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "same-origin", // include, *same-origin, omit redirect: "follow", // manual, *follow, error referrer: "no-referrer", // no-referrer, *client body: "", headers:{ 'Content-Type': 'application/json' } } // // // recall the "onload" function GetTweets(event) { var url = "http://localhost:8080/twitlist1.json" // We have a fixed file name. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. twtApp.tweets = newData // the page update right away with new data. }); }); } function sendTweets() { // recall the button up above. This is not a Vue style button, but still in the Vue app. var url = "http://localhost:8080/" var data = twtApp.tweets; // GET THE DATA OUT OF VUE. That’s all folks. // // so happens that Vue pulls out the right data and stringifies it. var jdata = JSON.stringify(data); // data can be `string` or {object}! // gDefaultPostInfo.body = jdata; // that’s for fetch - not Vue related // fetch(url,gDefaultPostInfo).then(res => { // We use fetch to POST as well as GET res.json() }).then(response => { console.log('Success:', JSON.stringify(response)) // promises }).catch(error => { console.error('Error:', error) }); } // // // </script>

So, just to highlight the amazing lines that speak to the power of the framework, let’s repeat here:

A. This is pulling the data out.

postOptionsObject.body = JSON.stringify(twtApp.tweets);

B. This is putting the data into Vue and seeing the screen update:

twtApp.tweets = JSON.parse(text) // text is the server response

How much work is that?

It looks like there is going to be a nice way to express how data will update panels for IoT.

Now, let’s turn the tweets into clickable icons designed to fetch components from the web server.

From Tweets to Panel Fetching Icons

People like to use SVG for icons. They like that use for SVG more than for other things as far as I can tell. I am only going on the number of web sites that sell or give away icons made in SVG. The selling point is that line graphics has fewer bytes than images. And, if I were going to ask for lists of pictures with button-like behavior, I might have grabbed for PNGs or JPEGs in the days SVG was in iframes. But, we can even find libraries in the Vue contributor lists that help us to a serving of icons.

We can turn the tweets page into an icon list returned as a search result. Just a little code has to be changed. Of course, there are a few things to be careful about if we want SVG icons to be loaded as buttons. Vue provides mechanisms for putting HTML into the application. These mechanisms have to be used or DOM elements fetched from the server don’t get interpreted.

Here is the kind of rendering you can get from view if you follow your first impulse in creating a handlebars style variable location in the application DOM.

Vue will quote the HTML an insert it as text. (Large preview)

Here is the code that produces the result in the picture:

<div id="iconAppTry"> <div class="entryart" style="padding:4px"> <span class="oneItem" v-for="icon in iconList"> {{icon}} </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>

Notice that we have gone from looping over tweets to looping over icons. tweet in tweets changed into icon in iconList. Our twtApp hooks into the DOM element #tweetAppDiv, while our iconApp hooks into the DOM element #iconAppTry. Within the Vue option object, the data subobject has a tweets in the first app, and iconList in the second. The fields are both empty arrays that receive data when the fetch routine does its job.

But, we have imitated our tweet app too closely. In the code above, the iconList is an array, and the server is expected to send an array of strings. So, let’s say the server has sent us HTML, and we have it properly decoded with the array assigned to data.iconList. Then, the picture above can be seen.

Now, let’s change the code just a little. In this revised code, we can see the following:

v-html="icon">

Vue responds to the v-html syntax by putting in the DOM of the icon element. Notice that the syntax is included after the loop directive as another attribute to the span tag.

By removing the handlebars syntax and using v-html, our picture changes to something more comprehensible:

<div id="iconAppTry2"> <div class="entryart" style="padding:4px"> <span class="oneItem" v-for="icon in iconList" v-html="icon"> </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry2', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script> Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics. (Large preview)

While v-html is a quick way to do things, the Vue team recommends using components to get the desired HTML into the page. That seems like a good idea, and we shall soon set about doing that.

But, let’s use the v-html syntax for our next example.

It’s time to set up our working example for fetching SVG icons. Let’s have those icons be responsive to a button click. Once those are working, we can get the panels associated with an icon.

Let’s suppose that the SVG required for icons is stored in a database. For our example, we can just fetch a JSON file from the server. The grown-up version of the icon server would store many such files in a database, and deliver them to the page with the same mechanisms.

Also, it’s best if the SVG arrives on the page URL encoded since we will be using JSON parse. The SVG can be decoded by calling JavaScript’s decodeURIComponent function.

In order to simulate the response to searching, we can make use of several JSON files. The page can have one button for each file. Here is the code for the page:

<!DOCTYPE html> <html lang="en" prefix="og: http://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="http://schema.org/Article"> <title>Search Bar</title> <style> body { margin: 2em; } div { margin: 6px; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin: 2px; margin-bottom: 3px; background-color: #EEF4EE; } .oneItem { background-color: #EEFFFF; margin: 2px; padding: 4px; border: solid 1px purple; } </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script> </head> <body> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div id="iconAppTry"> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button onclick="GetIcons(11)">Find All</button> <button onclick="GetIcons(5)">Find 5 Point</button> <button onclick="GetIcons(6)">Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart" style="padding:4px"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } } }); </script> </body> </html> <script> // // recall the "onclick" on the <buttons> function GetIcons(points) { // special file names instead of search parameters // var url = (points == 11) ? "http://localhost:8080/batchQuery-all.json" : ((points == 5) ? "http://localhost:8080/batchQuery-five.json" : "http://localhost:8080/batchQuery-six.json") fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); iconApp.iconList = newData; // the page update right away with new data. }); }); } </script>

Here is one display of icons that have been fetched from the server:

An artistic idea suggesting how search could return icons indicating certain groups of MCU’s to interact with. (Large preview)

The data being sent is an array with the following kind of structure:

{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },

Here, svg1 is SVG taken from a file. Of course, a righteous server would have taken the structure from a database, where the SVG would be stored in the structure.

Here is a snippet from the above code. This is the code that fetches the JSON and places the array of structures into the Vue app. You can see the promise structure of fetch in use. The text is parsed, and in the next line, the encoded SVG is decoded. One more line, and Vue updates the page. The number of buttons in the button bar will be equal to the length of the JSON array.

fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); // the page update right away with new data. iconApp.iconList = newData; }); });

Now, just two more snippets. The Vue app. The reader will notice that the @click directive has been included on the buttons. The data element, iconEntry.name, is passed to a method within quotes.

The method is defined within the Vue app:

<div class="entryart" style="padding:4px"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>

Here is the snippet for the definition of methods. The methods object is added just after the data object within the app parameter object:

, methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }

The reader should find the goGetPanel definition, and the use of it was pointed out for the @click handler. In our final application, the alert call can be replaced by a function that fetches panels from the server.

A Component Library For IoT Panels

We could just decide that panels that we fetch from the server can be HMTL or just SVG drawings, but if there are going to be many kinds of panels, we would hope that the job of creating panels could be simplified by having libraries of components to choose from. We can imagine that SVG editors could be improved to allow library components to be dropped onto pictures as part of editing. Then, if the SVG editor could output a version of the picture with component tags, then the use of Vue would allow the picture to be created while ensuring that the JavaScript automation and animation is neatly woven together. For our discussion, some hand editing can help us get there.

If we want to create panels out of Vue components, then we had better figure out how to make the components and then collect them together into something useful. We will have to switch to using command line tools provided by Vue and organize our workflow.

Components

The Vue documentation points out that the component data section (subobject) of the component definition needs to be a function that returns data. The reason for this is that Vue needs to keep data separate among the instances. So, in going from a Vue application initialization to a component definition there is another small code change.

In this first snippet of code a Vue application is being initialized:

var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });

In this new snippet of code, a component is being defined and registered. First, notice that instead of creating a new Vue instance, a component named iconic is being registered. Then, the data field returns custom data for any iconic instance that the Vue app makes. Finally, the template field is present at the end of the component registration. Any HTML that might have been written on the web page to display the component can be part of the template.

Vue.component('iconic', data: () => { var instanceData = { // data fields named for the // variables appearing in the template onevar : "test" } return(instanceData); }, methods : { ... }, template: '<div>This appears in every instance {{onevar}}</div>' });

So, we can imagine a panel with thermometers. So, if someone provided a thermometer component, we would expect a component definition somewhere in our code. As such:

Vue.component('thermometer', data: () => { var instanceData = { // data fields named for the // variables appearing in the template temperature : 0 } return(instanceData); }, methods : { ... }, template: '<div>Some SVG will go here</div>' });

We are trying to create something that looks like this:

Animated thermometer application in Vue before exploring components. (Large preview)

The thermometer component is very similar to the first components that you will come across in the Vue tutorials. But, it’s a little tricky to figure out how to update it. There is a better way of defining the component for reactivity using properties. And, that is in the following:

Vue.component('thermometer', { props: ['temperature'], computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } }, template: '#thermometer-template' })

So, instead of representing temperature as a data element. It is represented as a property under props. Then, there is a new section, computed, that provides variables that are functions of the property. We see this.temperature being used for both y and height. These computed variables are being used in the SVG as attributes for a rectangle.

In SVG, y grows from the top down. So, when we want the rectangle to be small at the bottom of the thermometer, the y of the red box has to be lower, and the height has to be reduced so that (y + height) stays at the thermometer zero.

Notice the template field in the definition of the components. It is in fact, a document element ID. The element being referred to is a script section with the special type: type="text/x-template". The script element is where the SVG for the thermometers is. And, the SVG makes use of Vue variables and control terms so that reactivity can be defined.

Here is some of the SVG:

<script type="text/x-template" id="thermometer-template"> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="20" height="70" version="1.1" > <g transform="translate(0,-180)"> <g transform="matrix(2.0111869,0,0,1.0489665,-215.11053,144.5592)"> <rect style="fill:#fffcfc;stroke:#000000;stroke-width:0.68848258;stroke-miterlimit:4;stroke-dasharray:none" stroke-linecap="null" stroke-linejoin="null" width="2.9665921" height="54.724472" x="111.90748" y="41.176476" /> <rect style="fill:#e82b0d;stroke:#000000;stroke-width:0.68848258;stroke-miterlimit:4;stroke-dasharray:none" stroke-linecap="null" stroke-linejoin="null" width="2.9665921" x="111.90748" :height="height" :y="y" /> <g transform="matrix(0.76503813,0,0,1,26.586929,0)"> <line y2="57.306953" y1="57.306953" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null" style="fill:none;stroke:#000000;stroke-width:0.787139;stroke-miterlimit:4;stroke-dasharray:none" /> <line y2="74.408356" y1="74.408356" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null"

The reader can find id="thermometer-template" at the top, and looking further down to the rect elements, the computed variables can be found.

Here the variable uses are separated out. The Vue shorthand syntax for v-bind is in use, with :height="height" and the same for y:

x="111.90748" :height="height" :y="y"

When the parent of the SVG elements sets variables that act as input to the thermometer property temperature, Vue recalculates height and y. As a result, the position and height of the red box change.

It helps to have a listing of the Vue app that makes use of the thermometer.

<body> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div id="thermoApp"> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Set Temperature</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button @click="updateTemp(50,50)">mid</button> <button @click="updateTemp(20,80)">low</button> <button @click="updateTemp(80,20)">high</button> </div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> <script> var thermoApp = new Vue({ el: '#thermoApp', data: { temp1 : 30, temp2 : 60, queryToken : "HEAT" }, methods : { updateTemp: function (tval1,tval2) { this.temp1 = tval1; this.temp2 = tval2; } } }); </script> </body>

That is the whole thing. There are three buttons which call the updateTemp method of the thermoApp Vue application. The data section has two temperature variables. And, each thermometer updates its temperature when the values change.

The code for the two thermometers called out below can be found on the HTML assigned to the Vue app.

<thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>

Notice that application uses the function formalism for the method definition. Defining updateTemp this way updateTemp: function (tval1,tval2) allows for the instance variable this to be accessed.

Also, defining updateTemp this way updateTemp: (tval1,tval2) => assigns this to an internal data structure that does not react and update the view.

Assembling a Panel

Each IoT panel can be a component. Vue provides a way of defining components with subcomponents. Alternatively, there is a slot mechanism that can be used to yield a component that can wrap around any HTML content.

In the following few paragraphs, let’s look at making a panel out of subcomponents. There are two forms that follow quickly from our examples. In one case, the thermometers can be subcomponents called out in JavaScript. In another case, the components are defined independently but are mentioned in the HTML.

In both cases, the same HTML can be used for the template. Here is our panel as a template:

<script type="text/x-template" id="thermo-panel-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>

The only difference between the first detailing of the application is that a div element is surrounding the two thermometers. Vue will throw an error if the template is missing a top level DOM element. The div passes the Vue requirement, and the multiple elements may be included inside of it.

Now, we may see the two thermometers side by side. Passing the temperatures from the top to the final thermometer has values cascading down. At the top level, the panel joins the application when a single line is included in the application DOM.

<themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>

The template for the panel, although simple, seems to indicate that panels can be easily designed in term of components. It’s as if a language for just IoT components is possible.

Now, the template definition for the panel is simple enough. Here it is with the subcomponents defined independently:

Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });

That is about as much as is required to make the panel functional. It is true that this version relies on a long list of properties for defining values to be updated as messages come into the page. But, this is a good start. Updating the data object at the top level does the job of animating the thermometers. However, as the panels become complicated, there may need to be another method for showing change.

Having made mention to the other ways of specifying subcomponents, for the panel, we should take a look at it. Here it is:

Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template', components: { // a sub component for the labels 'thermometer': { props: { temperature: Number, }, template: '#thermometer-template', computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } } } } });

There is certainly more code, but that is because the JavaScript for the thermometer component is included within the components list of thermo-panel. The two approaches do the same job, but they offer different ways of packaging component definitions.

At the moment, my preference is for the first way. It should be considerably easier to revise panels and have them retrieved dynamically if only changing template and properties is required. To this end, the independently defined components form a component library. But, although that seems better, in the following it becomes more convenient to use the second, seemingly more verbose way.

Given that we can make responsive panels out of components in clearly defined ways, I’ll explain how we can manage them as a database that can make simple queries in the next part of my article.

(dm, yk, il)
Categories: Web Design

Why Mason And Front-End As A Service Will Be A Game Changer For Product Development

Smashing Magazine - Tue, 05/07/2019 - 03:30
Why Mason And Front-End As A Service Will Be A Game Changer For Product Development Why Mason And Front-End As A Service Will Be A Game Changer For Product Development Suzanne Scacca 2019-05-07T12:30:59+02:00 2019-05-23T09:05:51+00:00

(This is a sponsored article.) Take a look around at the apps and software you interact with on a regular basis. Each has its own unique design, right? And, yet, there’s something similar about each of them. Navigation bars, contact forms, feature boxes, CTAs — certain elements tend to be present no matter where you go.

That’s because these elements play a crucial part in how users engage with the products that you’ve built. From the users’ end, this is a good thing. By including these recognizable and predictable elements within the frontend structure of an application, the user’s focus is on the content before them; not on trying to solve the mystery of the UI.

From the software developers’ end, though, this is a pain. You know what kinds of components need to be included in a product. However, until now, you’ve had to build them from-scratch time and time again. Worse, any time something needs to be updated, it rides on you to implement the update and push it to the live site — and it’s not often you have the bandwidth to make those changes right away.

That’s why what Mason is doing with front-end-as-a-service (FEaaS) is so interesting. In this article, I’m going to give you a closer look at FEaaS, who it’s for and why empowering product and marketing teams with it is a big deal.

What Is FEaaS?

You know what software-as-a-service (SaaS) is. But have you heard of software-components-as-a-service (SCaaS)?

There were some light grumblings around SCaaS a number of years back. The basic idea was that you could create and easily maintain reusable UI components and widgets for your software. However, it never really caught on — and that’s probably because it was too restrictive in what it enabled developers to do.

With FEaaS, though, you have a much more valuable and powerful solution. Essentially, Mason’s front-end-as-a-service solution enables you to quickly and effectively build the visual aspects and functionality of your software.

This means that you’re building complex features and making them talk to APIs. An example of different designed, complex forms connected to Airtable as the datasource can be found here.

What’s more, each feature you build with Mason lives in the same codebase as the rest of your product. Let’s take a look at a customizable Apixu-powered Chatbot that was made with Mason:

An example of the kinds of dynamic content you can build with FEaaS. (Source: Mason) (Large preview)

And this is a hero banner I created for an ebook giveaway using a Mason template:

An example of a hero image template, customized and published with Mason. (Source: Mason) (Large preview)

Make no mistake: this is not a website builder. Mason empowers you and your team to build individual components and fully functional features; not entire managed hosting websites or products. This way, you’re no longer restricted by the capabilities of your site builder solution.

You can build your website, app, or other software product in the tool of your choice. Then, design and export really complex features from Mason to be integrated into your code base. It’s important to point out that unlike a platform that locks you and your customer data in, Mason lets product teams augment their current products and own everything (not like some website buiders that own your whole website and business instead).

Who Is Mason For?

With Mason, you should already have a fully developed software product or, at the very least, a solution to build it with. Mason is the tool you’ll use to build and design the features (and their functionality) for your product — and to do so with ease (i.e. no coding).

Those features will then be self-contained and dropped into the product when they’re good to go.

As for the actual people that Mason was built for, Tom McLaughlin, Mason’s CEO, explains:

“Today, the entire product lives in the codebase, so it becomes the de facto realm of the engineering team only, even though so many of the features that make up the product can be found in every other codebase on earth — they’re just not that unique. Mason lets your product team build these common features faster, but, more importantly, lets anyone in the organization — technical or not — manage them, even once they’re in production.”

Your product team — your software developers and designers — are the ones that will use Mason to build your software. However, your marketing and content teams will gain the ability to update the features you’ve built in Mason after they’ve been deployed, without needing to wait on engineering to deploy every new edit or tweak.

This means that maintenance of front end features is no longer solely dependent on you, the developer. Anyone on your team — designers, marketers, content creators, etc. — can use Mason’s FEaaS platform to build and update your software’s features.

So, not only can you more efficiently build powerful features for your products, your team can deploy updates in real-time, rather than allowing them to pile up on your open ticket list.

Why FEaaS Matters

Has your software development, deployment or update schedule suffered in the past due to (albeit completely understandable) software developer bottlenecks? If so, then FEaaS should sound like a dream to you.

Until now, there’s really been no other option for software engineers. If you wanted to build a product for the web, everything had to be built from scratch and it required a good amount of time on your part to do so, especially if your aims were more complex in nature. All the while, the rest of your team was left waiting in the wings for you to do your part.

With Mason leading the charge with its FEaaS solution, I’d like to take a look at how its capabilities are going to revolutionize your product development workflow.

Design UI Components Visually

FEaaS takes engineers and developers out of a product’s code base and into a visual build interface. As such, you see exactly what you’re building without having to switch back and forth between your code and a visual preview of what it’ll look like once deployed.

With Mason’s visual builder, you can design complex but essential UI components using a system of containers, columns, layers and pre-configured elements like text, form fields, buttons and more.

A look inside Mason’s visual builder tool. (Source: Mason) (Large preview)

Similar to how other modern builder tools work, there is an abundance of options available to help you do more without ever having to write a line of code. And thanks to a convenient toggle between desktop, mobile and tablet views, responsive design is no problem either.

In addition, Mason comes with a full-featured UI kit that includes a variety of templates for the most common UI components. Or you can hand-select the ones you need:

Mason’s pre-built UI component library of templates. (Source: Mason) (Large preview)

Feature cards. Login screens. Blog content blocks. Hero images. CTA buttons. All of the core components you need to get visitors to engage with your product and take action have already been built for you.

If you’re tired of creating them from scratch in each and every product you build, these templates will be a huge help. As you can imagine, having the ability to design and customize product components this way would be a great boon to your team’s productivity.

Build Components And Functionality More Quickly

Now, being able to style components visually is just one of the benefits of using an FEaaS platform like Mason. As you might expect, a tool like this was manufactured for speed.

In terms of actually using Mason, it’s a tool that loads insanely quickly — which would make this quite valuable to anyone who’s lost time in the past waiting for their tools to launch, save changes or move from one view to another.

In terms of how it affects your workflow, expect to gain speed there as well.

With the Mason builder, you can:

  • Add new containers, columns, rows, content blocks or custom-coded elements with a simple drag-and-drop:
Mason’s comprehensive set of design layouts, components, and coding options. (Source: Mason) (Large preview)
  • Review, edit, duplicate, move or delete the layers of your component using this visualized hierarchy of elements:
Mason’s easy-to-manage layer controls. (Source: Mason) (Large preview)
  • It’s not just the UI design piece that’s simplified either. You can connect your components to other sources through APIs with ease, too.
Connecting datasources to Mason features to prepare for mapping. (Source: Mason) (Large preview) Connecting APIs to Mason components through mapping. (Source: Mason) (Large preview)

Mason’s “Configure” tab enables you to quickly integrate with other applications, like:

  • Authy
  • Facebook
  • Hubspot
  • Stripe
  • Twilio
  • And more.

So, let’s say you want to sell the eBook promoted in your hero banner instead of just collect leads with it. The first thing you’d do is set up the Stripe integration.

All you need are the Publishable and Secret keys from Stripe’s Developer dashboard:

Retrieve the API keys from your Stripe developer dashboard. (Source: Stripe) (Large preview)

Then, input each of the keys into the corresponding field in Mason:

Integrate other applications with Mason components as datasources, like this Stripe example. (Source: Mason) (Large preview)

Return to the “Design” tab and drag the Credit Card Form Element into the component.

Use the Credit Card Form Element in Mason to accept payments through components. (Source: Mason) (Large preview)

With your form added to the page, there’s one final step to take to set up this integration.

Return to the Configure tab. You’ll now see a new option on the sidebar called “Forms”:

Configure a Stripe payment form in just a few steps with Mason. (Source: Mason) (Large preview)

You can see that all of the pertinent details have already been added here and the connection already made to your form.

Again, Mason makes light work of something that would typically take software engineers awhile to do if they were to build a component from-scratch. Instead, you now have all the tools you need to quickly design and program new features for your product.

Deploy New Features With Ease

To be sure, being able to design new features quickly is important for product teams. However, that still doesn’t fix the issue of deployment.

Bottlenecks can occur at various points of a product’s development. And when you build a piece of software that’s so complex that only an engineer can readily launch it or deploy updates, well, you can only expect further delays in the pipeline.

Mason has developed a solution for this. To start, publishing a component to Mason’s library is a cinch. Simply click the “Publish” button in the top-right corner of the builder and Mason takes care of the rest.

To get the component inside your product or app, though, a developer needs to get involved — but only just this once and it shouldn’t take more than five minutes.

To do this, use the “< > Deploy” button in the the top-right corner of the builder. It will then prompt you to do the following:

Deploying a Mason component takes just five minutes and four steps. (Source: Mason) (Large preview)

Essentially, what you’re doing is taking the unique identifier Mason has created for the feature you built and adding it to your codebase. When set up correctly, your product will call on the Mason API to render the component app-side. And those on the front end of the site will be none the wiser.

It’s as simple as that to push a new component and all its functionality live.

Empower Everyone To Make Changes And Push Updates

All of the points I’ve made here about the benefits of FEaaS have been dancing around this final — and huge — benefit, which is this:

FEaaS empowers everyone to make changes to features and push them to a live application.

Think about that for a moment.

How much time has your team spent waiting around for an engineer to implement the changes that they need? And what has that done in terms of stunting your app’s ability to engage and convert visitors? Without an impressive-looking UI, without properly functioning features, without all of the critical elements needed to compel visitors to take action.

You’re ultimately costing the business money by holding the software hostage. Until now, that’s something that software product teams couldn’t help. It was just the nature of their work. But with FEaaS by Mason, this finally changes.

Once you have (1) published your component and (2) deployed it to your application, the feature will appear within your product. But let’s say changes are needed to it. For example:

  • Your designer wants to change the style of a form to mirror the revamped landing page design.
  • Your marketing manager has a new branded image that needs to replace the home page hero image.
  • Your editor has decided to tweak the wording for the latest lead gen offer and wants to update the CTA.

It doesn’t matter who steps inside the Mason builder to change a component. The second it happens, that faded “Saved” button in the top-right corner of the builder turns to a green “Go to Publish” button.

Updating Mason components can be done by anyone. (Source: Mason) (Large preview)

And guess what? No technical experience is needed to click it.

Mason takes care of publishing your components and its updates to its library. (Source: Mason) (Large preview)

Mason takes care of publishing and deploying the changes, so as long as the connection has already been made between your app and Mason, these updates should instantly go live for visitors to see.

If you and your product team have been bogged down with a barrage of tickets, asking you to build new components or to tweak existing ones, this will effectively put a stop to that.

Wrapping Up

One of the wonderful things about building products for the web is that someone’s always developing a new way to help us accomplish more while simultaneously doing less.

With software applications, in general, it’s been a long time coming. Thankfully, FEaaS is here and it looks as though Mason has developed a supremely valuable tool to speed up software development, improve output, and also empower more of your team to pitch in.

(md, yk, il)
Categories: Web Design

Google I/O 2019 - What sessions should SEOs and webmasters watch?

Google Webmaster Central Blog - Mon, 05/06/2019 - 08:05
Google I/O 2019 is starting tomorrow and will run for 3 days, until Thursday. Google I/O is our yearly developers festival, where product announcements are made, new APIs and frameworks are introduced, and Product Managers present the latest from Google to an audience of 7,000+ developers who fly to California.

However, you don't have to physically attend the event to take advantage of this once-a-year opportunity: many conferences and talks are live streamed on YouTube for anyone to watch. Browse the full schedule of events, including a list of talks that we think will be interesting for webmasters to watch (all talks are in English). All the links shared below will bring you to pages with more details about each talk, and links to watch the sessions will display on the day of each event. All times are Pacific Central time (California time).



This list is only a small part of the agenda that we think is useful to webmasters and SEOs. There are many more sessions that you could find interesting! To learn about those other talks, check out the full list of “web” sessions, design sessions, Cloud sessions, machine learning sessions, and more. Use the filtering function to toggle the sessions on and off.
We hope you can make the time to watch the talks online, and participate in the excitement of I/O ! The videos will also be available on Youtube after the event, in case you can't tune in live.
Posted by Vincent Courson, Search Outreach Specialist
Categories: Web Design

Hybrid Lazy Loading: A Progressive Migration To Native Lazy Loading

Smashing Magazine - Mon, 05/06/2019 - 04:30
Hybrid Lazy Loading: A Progressive Migration To Native Lazy Loading Hybrid Lazy Loading: A Progressive Migration To Native Lazy Loading Andrea Verlicchi 2019-05-06T13:30:59+02:00 2019-05-23T09:05:51+00:00

In the past few weeks, you might have heard or read about native lazy loading, which is coming to Chromium 75 in the upcoming months.

“Yeah, great news, but we’ll have to wait until all browsers support it.”

If this was the first thing that crossed your mind, keep reading. I will try and convince you of the opposite.

Let’s start with a comparison between native lazy loading and the good ol’ JavaScript-driven one.

Native Versus JavaScript-Driven Lazy Loading

Lazy loading is a way to improve the performance of a website or web application by maximizing the rendering speed of the above-the-fold images and iframes (and sometimes videos) by deferring the loading of below-the-fold content.

JavaScript-Driven Lazy Loading

In order to lazy load images or iframes, it’s a very common practice to mark them up by replacing the proper src attribute with a similar data attribute, data-src, then to rely on a JavaScript solution to detect when the images/iframes are getting close to the visible portion of the website (typically because the user scrolled down) and to copy the data attributes into the proper ones, then triggering the deferred loading of their content.

<img data-src="turtle.jpg" alt="Lazy turtle" class="lazy"> Native Lazy Loading

According to the native lazy loading specification (still under development), if you want to lazy load images or iframes using the native lazy loading feature, you would just need to add the loading=lazy attribute on the related tag.

<img src="turtle.jpg" alt="Lazy turtle" loading="lazy">

Addy Osmani wrote extensively about this topic in his article “Native Image Lazy-Loading For The Web!” in which he stated that the Google Chrome team are already developing the feature and intend to ship it in Chrome 75.

Other Chromium-based browsers like Opera and Microsoft Edge will also benefit from this development by gaining the same feature in their first update based on Chromium 75.

Get Started With Native Lazy Loading

In case your website’s images are downloaded all at once at page landing without lazy loading, you can enable (where supported) native lazy loading in your website as easily as adding an HTML attribute. The loading attribute tells browsers which images are important to load immediately, and which ones can be downloaded lazily as the users scroll down. The same attribute can be applied to iframes.

In order to tell browsers that a particular image is important so they can load it as soon as possible, you must add the loading="eager" attribute on the img tag. The best practice is to do this for the primary images — typically for the ones that will be displayed above the fold.

<img src="rabbit.jpg" alt="Fast rabbit" loading="eager">

To tell browsers that an image should be downloaded lazily, just add the loading="lazy" attribute. This is a best practice only if you do it only to secondary images — typically for the ones will be displayed below the fold.

<img src="turtle.jpg" alt="Lazy turtle" loading="lazy">

Just by adding the loading attribute to your images and iframes, you will enable your website to use native lazy loading as a progressive enhancement. Your website will gradually benefit from it as support arrives to your users in most modern browsers.

This is the best approach to use if your website is not using any kind of lazy loading today, but if you already implemented a JavaScript-driven lazy loading solution, you might want to keep it while progressively switching to native lazy loading.

The ideal solution would be to start using native lazy loading right away, and use a polyfill to make it work across all browsers. Unfortunately, native lazy loading is not a feature we can polyfill with JavaScript.

No Use For A Polyfill

When a new browser technology is released to a single browser, the open-source community usually releases a JavaScript polyfill to provide the same technology to the rest of the browsers. For example, the IntersectionObserver polyfill uses JavaScript and DOM elements to coordinate Element.getBoundingClientRect() to reproduce the behavior of the native API.

But the case of native lazy loading is different because a JavaScript polyfill for loading="lazy" would have to prevent browsers from loading content as soon as they find a URL in the markup of an image or iframe. JavaScript has no control on this initial stage of page rendering, therefore it is not possible to polyfill native lazy loading.

Hybrid Lazy Loading

If you are not satisfied with having native lazy loading only as a progressive enhancement, or you have already implemented JavaScript-based lazy loading and don’t want to lose this feature in less modern browsers (but still want to enable native lazy loading on browsers that support it), then you need a different solution. Introducing: hybrid lazy loading.

Hybrid lazy loading is a technique to use native lazy loading on browsers that support it, otherwise, rely on JavaScript to handle the lazy loading.

In order to do hybrid lazy loading, you need to mark up your lazy content using the data attributes instead of the real ones (such as in JavaScript-driven lazy loading), and to add the loading="lazy" attribute.

<img data-src="turtle.jpg" loading="lazy" alt="Lazy turtle">

Then you require some JavaScript. In the first place, you need to detect whether or not native lazy loading is supported by the browser. Then, do one of the following for every element with the loading="lazy" attribute:

  • If native lazy loading is supported, copy the data-src attribute value to the src attribute;
  • If not supported, initialize a JavaScript lazy loading script or plugin to do that as the elements enter the viewport.

It’s not very hard to write the JavaScript code required to perform these operations on your own. You can detect if native lazy loading is supported with the condition:

if ('loading' in HTMLImageElement.prototype)

If it is, just copy the src attribute value from data-src. If it’s not, initialize some lazy-loading script of your choice.

Here’s a snippet of code that does that.

<!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let’s lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <script> (function() { if ("loading" in HTMLImageElement.prototype) { var lazyEls = document.querySelectorAll("[loading=lazy]"); lazyEls.forEach(function(lazyEl) { lazyEl.setAttribute( "src", lazyEl.getAttribute("data-src") ); }); } else { // Dynamically include a lazy loading library of your choice // Here including vanilla-lazyload var script = document.createElement("script"); script.async = true; script.src = "https://cdn.jsdelivr.net/npm/vanilla-lazyload@12.0.0/dist/lazyload.min.js"; window.lazyLoadOptions = { elements_selector: "[loading=lazy]" //eventually more options here }; document.body.appendChild(script); } })(); </script>

You can find and test the code above in this live demo.

Still, that is a very basic script, and things can get complicated when you’re using additional attributes or tags to get responsive images (such as the srcset and sizes attributes or even the picture and source tags).

A Little Third-Party Help

For the past four years, I’ve been maintaining an open-source lazy load script named “vanilla-lazyload” and, in a couple of days after Addy Osmani wrote about native lazy loading, the community reacted by asking me if my script could act as a polyfill.

As I explained before, you cannot create a polyfill for the native lazy loading feature, however, I thought of a solution that would make it easier for developers to begin the transition to native lazy loading, without needing to write any of the JavaScript code that I’ve mentioned before.

Starting from version 12 of vanilla-lazyload, you can just set the use_native option to true to enable hybrid lazy loading. The script is only 2.0 kB gzipped and it’s already available on GitHub, npm, and jsDelivr.

Demos

You can start playing around with native lazy loading today by downloading Chrome Canary or Microsoft Edge Insider (dev channel) then enabling the flags “Enable lazy image loading” and “Enable lazy frame loading”. To enable these flags, enter about:flags in your browser’s URL field and search for “lazy” in the search box.

Native Lazy Loading Demo

To analyze how native lazy loading works in the developer tools, you can start playing with the following demo. In this one, not a single line of JavaScript is used. Yes, it’s just full plain native lazy loading.

What to expect: All images are fetched at once, but with different HTTP responses. The ones with the response code 200 are the eagerly loaded images, while the ones with the response code 206 are only partially fetched in order to get the initial information about the images. Those images will then be fetched completely with a 200 response code when you scroll down.

Hybrid Lazy Loading Demo

To analyze how hybrid lazy loading works, you can start playing with the next demo. Here, vanilla-lazyload@12.0.0 is used and the use_native option is set to true:

What to expect: Try the demo on different browsers to see how it behaves. On browsers that support native lazy loading, the behavior would be the same as in the native lazy loading demo. On browsers that do not support native lazy loading, the images will be downloaded as you scroll down.

Please note that vanilla-lazyload uses the IntersectionObserver API under the hood, so you would need to polyfill it on Internet Explorer and less recent versions of Safari. It’s not a big deal if a polyfill is not provided, though, because in that case vanilla-lazyload would just download all the images at once.

Note: Read more in the “To Polyfill Or Not To Polyfill” chapter of vanilla-lazyload’s readme file.

Try Hybrid Lazy Loading In Your Website

Since native lazy loading is coming soon to some browsers, why don’t you give it a chance today using hybrid lazy loading? Here’s what you need to do:

HTML Markup

The simplest image markup is made by two attributes: src and alt.

For the above-the-fold images, you should leave the src attribute and add the loading="eager" attribute.

<img src="important.jpg" loading="eager" alt="Important image">

For below-the-fold images, you should replace the src attribute with the data attribute data-src and add the loading="lazy" attribute.

<img data-src="lazy.jpg" loading="lazy" alt="A lazy image">

If you want to use responsive images, do the same with the srcset and sizes attributes.

<img alt="A lazy image" loading="lazy" data-src="lazy.jpg" data-srcset="lazy_400.jpg 400w, lazy_800.jpg 800w" data-sizes="100w">

If you prefer to use the picture tag, change the srcset, sizes and src also in the source tags.

<picture> <source media="(min-width: 1200px)" data-srcset="lazy_1200.jpg 1x, lazy_2400.jpg 2x"> <source media="(min-width: 800px)" data-srcset="lazy_800.jpg 1x, lazy_1600.jpg 2x"> <img alt="A lazy image" loading="lazy" data-src="lazy.jpg"> </picture>

The picture tag can also be used to selectively load the WebP format for your images.

Note: If you want to know more usages of vanilla-lazyload, please read the “Getting Started” HTML section of its readme file.

JavaScript Code

First of all, you need to include vanilla-lazyload on your website.

You can load it from a CDN like jsDelivr:

<script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@12.0.0/dist/lazyload.min.js"></script>

Or you can install it using npm:

npm install vanilla-lazyload@12

It’s also possible to use an async script with automatic initialization; load it as a ES module using type="module" or load it as AMD using RequireJS. Find more ways to include and use vanilla-lazyload in the “Getting Started” script section of the readme file.

Then, in your website/web application’s JavaScript code, include the following:

var pageLazyLoad = new LazyLoad({ elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading });

Note: The script has plenty of other settings you can use to customize vanilla-lazyload’s behavior, e.g. to increase the distance of the scrolling area from which to start loading the elements or to load elements only if they stayed in the viewport for a given time. Find more settings in the API section of the readme file.

All Together, Using An async Script

To put it all together and use an async script to maximize performance, please refer to the following HTML and JavaScript code:

<!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let’s lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <!-- Set the options for the global instance of vanilla-lazyload --> <script> window.lazyLoadOptions = { elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading }; </script> <!-- Include vanilla lazyload 12 through an async script --> <script async src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@12.0.0/dist/lazyload.min.js"></script>

That’s it! With these very simple and easy steps, you’ll have enabled hybrid lazy loading in your website!

Important Best Practices
  • Apply lazy loading only to the images that you know that will probably be displayed below the fold. Eagerly load the ones above the fold to maximize performance. If you just apply lazy load to all images in your page, you’ll slow down rendering performance.
  • Use CSS to reserve some space for the images before they are loaded. That way, they’ll push the rest of the content below. If you don’t do that, a larger number of images will be placed above the fold before they should, triggering immediate downloads for them. If you need a CSS trick to do that, you can find one in the tips and tricks section of the readme of vanilla-lazyload.
Pros And Cons NATIVE LAZY LOADING PROS
  • No JavaScript required;
  • No setup headaches, it just works;
  • No need to reserve space for images using CSS tricks;
CONS
  • It does not work today on all browsers;
  • The initial payload is higher, because of the prefetch of the initial 2 kb for every image.
JAVASCRIPT-DRIVEN LAZY LOADING PROS
  • It works consistently across all browsers, right now;
  • You can do very highly customized UI tricks, like the blur-in effect or the delayed loading.
CONS
  • It relies on JavaScript to load your content.
HYBRID LAZY LOADING PROS
  • It gives you the chance to enable and test native lazy loading where supported;
  • It enables lazy loading on all browsers;
  • You can transparently remove the script dependency as soon as native lazy loading support will be widespread.
CONS
  • It still relies on JavaScript to load your content.
Wrapping Up

I’m very excited that native lazy loading is coming to browsers, and I can’t wait for all browser vendors to implement it!

In the meantime, you can either choose to enrich your HTML markup for progressive enhancement and get native lazy loading only where supported, or you can go for hybrid lazy loading and get both native and JavaScript-driven lazy loading until the day native lazy loading will be supported by the vast majority of browsers.

Give it a try! Don’t forget to star/watch vanilla-lazyload on GitHub, and let me know your thoughts in the comments section.

Further Reading on SmashingMag: (dm, il)
Categories: Web Design

A Practical Guide To SVG And Design Tools

Smashing Magazine - Fri, 05/03/2019 - 05:00
A Practical Guide To SVG And Design Tools A Practical Guide To SVG And Design Tools Mikołaj Dobrucki 2019-05-03T14:00:59+02:00 2019-05-23T09:05:51+00:00

A good understanding of SVG is a rare skill. Surprisingly often, SVG is treated as just another image format. We use SVG because of its scalability and smaller file size, but in reality, SVG is so much more!

In this article, I’ll shed light on three of the most popular design tools: Adobe Illustrator, Sketch, and Figma. There are also other tools available supporting SVG that may have other functionalities and implement other solutions.

Note: If not stated otherwise, the content of this article is referring to SVG 1.1 2nd Edition. Some of the points discussed below would not apply to SVG 2, however, it still hasn’t reached the recommendation status, leaving SVG 1.1 as the most up-to-date specification.

Why Bother About Design Tools?

SVG is an XML-based markup language and, like any other programming language, can be written and edited in a text editor. So theoretically, as opposed to JPG or PNG files, we don’t need any GUI software to create SVG. However, in a vast majority of cases, using graphic design applications is inevitable.

Working with complicated shapes and graphics in a text-based format is utterly possible, but usually would be very tricky and tedious. Therefore, it’s common practice to use applications such as Adobe Illustrator, Sketch or Figma to design graphics visually, and then export them to an SVG format.

So no matter if you’re a designer that codes or a design-conscious developer, a good proficiency in working with SVG requires a bit of knowledge from both sides: design tools and the SVG language itself. To better understand the relation between the two, let’s take a closer look at what graphic design apps have to offer and how their features translate to SVG.

Basic Shapes

Many vector graphics are build out of a few basic shapes — grouped, transformed and combined with each other. The table below represents what shape tools are available in Illustrator, Sketch, and Figma and what SVG elements they are exported as.

Illustrator Sketch Figma Generated SVG Ellipse Tool Oval Ellipse <circle /> or <ellipse /> Rectangle Tool Rectangle Rectangle <rect /> Rounded Rectangle Tool Rounded - <rect rx="…" /> Line Segment Tool Line Line <line /> (Illustrator and Figma) <path /> (Sketch) - Arrow Arrow <path /> Polygon Tool Polygon Polygon <polygon /> (Illustrator and Sketch) <path /> (Figma) Star Tool Star Star <polygon /> (Illustrator and Sketch) <path /> (Figma) - Triangle - <polygon /> Ellipses And Circles

One of the basic shapes in every design tool is an ellipse. In SVG, we will find a matching <ellipse /> element, defined by the coordinates of the ellipse’s centre (cx and cy) and two radii (rx and ry).

This is what an ellipse looks like in SVG:

<ellipse cx="400" cy="300" rx="250" ry="150"/> SVG ellipse (Large preview)

The very special type of ellipse is a circle. A circle is an ellipse with rx and ry radii equal to each other. SVG has its own <circle /> element that takes one attribute less as there’s only one radius to be taken into account:

<circle cx="400" cy="300" r="250"/> SVG circle (Large preview)

In case of ellipses and circles, all design tools work the same: Ellipse Tool in Illustrator, Oval tool in Sketch and Ellipse tool in Figma will all generate <ellipse /> element unless the radii are equal: in such cases we will end up with a <circle /> element.

Rectangles And Rounded Rectangles

Another basic shape common to all design tools is a rectangle. In case of all design tools, using a rectangle tool generates a <rect /> element in SVG. A basic <rect /> is defined by 4 attributes: its x and y coordinates, along with its width and height:

<rect x="150" y="100" width="500" height="400"/> SVG rectangle (Large preview)

Notice that while <ellipse />’s and <circle />’s position is defined by their geometrical centers, the position of a <rect /> is defined by the coordinates of its top left corner.

Apart from basic rectangles, we often use rectangles with rounded corners. In all three design tools, you can turn a rectangle into a rounded rectangle by applying a border radius to it in the Inspector or the Properties panel.

Additionally, in Sketch and Illustrator, there are tools dedicated to creating rounded rectangles (Rounded Rectangle Tool in Illustrator and Rounded tool in Sketch). However, there’s no difference between a regular rectangle with a radius applied and a rounded rectangle drawn with a Rounded Rectangle tool.

Therefore, no matter how created, a rounded rectangle will be exported using the following syntax:

<rect x="150" y="100" width="500" height="400" rx="30"/>

In this case, rx is an attribute responsible for the radius of the rounded corners:

SVG rounded rectangle (Large preview) Rounded Rectangles With Elliptical Corners

One significant difference between design tools and SVG is how radii are defined. In all the design tools we consider, border radius is defined by a single variable. We can think of border radii as little circles used to mask the corners of our rectangles:

Rounded corner in SVG (Large preview)

Meanwhile, in SVG border radii can be defined by two attributes: rx (as in the example above) and ry. They allow us to create rectangles with elliptical corners. You can think of such rounded corners as ellipses used as masks instead of circles:

<rect x="150" y="100" width="500" height="400" rx="40" ry="30"/> Elliptical corner in SVG (Large preview)

So, in this case, SVG offers you more possibilities than design tools.

Note: Even though it’s not exactly related to the topic of this article, it’s worth noting that the difference described above applies to both SVG and HTML/CSS. The CSS property border-radius that is used to style nodes such as divs and spans also allows creating elliptical corners. You can see an example below.

border-radius: 10px 5% / 20px 25em 30px 35em;

Values before the slash (/) are horizontal radii (equivalent of rx) and values after the slash are vertical values (equivalent of ry).

Rounded Rectangles With Multiple Radii

In design tools, the same as in CSS, each of the corners of a rectangle can be controlled separately. In other words, each corner can have its own radius (or no radius altogether). Such operation is not possible on a <rect /> element in SVG. Each <rect /> element has only one rx and one ry attribute. If you create a rectangle with multiple radii applied to its corners, the design tool will generate a <path /> element instead of a <rect /> element. We will talk more of a <path /> element in the next section.

Smooth Corners

One of the interesting features introduced by Sketch and Figma not that long ago is smooth corners. In short, smooth corners use an irregular border-radius to achieve a result that looks more natural and, well, smooth. The most common application of smooth corners is app icons and other rounded elements on iOS. Apple used “regular” rounded corners on its mobile platform until iOS6 and then switched to what we call today “smooth” corners as a part of the big redesign introduced in 2013 (iOS7).

Difference between rounded and smooth corners (Large preview)

In Sketch, you can achieve smooth corners effect by switching between Round Corners and Smooth Corners in Inspector. Figma is giving you even more control over your corners as you can manipulate with the level of smoothness in the Corner Smoothing menu.

Unfortunately, none of these can be easily translated to SVG as SVG doesn’t know the concept of smooth corners at all. There’s also an important difference between what Sketch and Figma do if you try to export a rectangle with smooth corners to SVG.

Figma ignores the smooth corners, and exports a rectangle as a regular <rect /> element with rounded corners. Sketch, on the other hand, exports a rectangle with smooth corners as a <path /> that is trying to replicate the true shape of smooth corners. So Figma gives us worse accuracy for the sake of keeping a rectangle a rectangle, while Sketch is aiming at maximum possible accuracy at the cost of semantics and bigger file size. If you’d like to understand better what does this difference mean, we will dig deeper into the pros and cons of preserving basic shapes a bit later.

Lines

The next basic type of element is a line. In this case, we refer to a line as a single straight line going from point A to point B. Illustrator, Sketch and Figma all offer their own line tools dedicated to drawing lines. In SVG, we have a <line /> element. Four of its attributes are required: the coordinates of its starting point and the coordinates of its end point:

<line x1="100" y1="100" x2="200" y2="200"/> SVG line (Large preview)

When it comes to exporting, Illustrator and Figma will export lines as <line /> elements where possible, while Sketch will always compute lines to <path /> elements.

Polylines

Now let’s take a look at polylines. Polyline is a connected series of straight lines. Polylines don’t have dedicated tools in the design tools. They can be drawn with a Pen tool (in Illustrator and Figma) or with a Vector tool (in Sketch).

In, SVG, polylines are defined with a <polyline /> element. <polyline /> is drawn using a points attribute which is a list of coordinates defining all the points that create a polyline. Let’s take a look at an example of a polyline made out of three segments and four points:

<polyline points="10,20 10,20 30,10 40,20" /> (Large preview)

Illustrator and Sketch translate polylines to <polyline/> elements, whilst Figma exports polylines as <path />s.

Arrows

In all three tools, you can control the ends of the lines to turn them into arrows and such. And all three tools will export such lines as <path />s, even if without the caps applied the same shapes would be translated to <line />s or <polyline />s. Is it because SVG doesn’t support arrows? Not exactly.

Actually, SVG specification does include customizable line ends which are known as markers. However, none of the design tools we mentioned use markers in the SVG they generate.

<marker> is a separate SVG element that can be defined within SVG’s <defs> and then used on <line>, <polyline> and <path> elements with marker attributes: marker, marker-start, marker-mid and marker-end. If you’d like to learn more about these attributes, I would recommend you to check out the official W3C documentation.

Polygons And Stars

The last basic shape we’ll take a look at it is a polygon. Polygon is a closed shape made of straight lines, e.g. star or a hexagon. You can also think of it as of a closed polyline. The syntax of a <polygon /> element in SVG is actually the same as of a <polyline />. The only difference between the two is that in the <polygon /> the last point on the list is always being connected with the first point to make a <polygon /> a closed shape.

SVG polygon (Large preview)

Some polygons are regular polygons. What is special about regular polygons is that all of their sides and angles are equal. To draw regular polygons, such as a hexagon or a pentagon, you can use a Polygon tool, same in Illustrator, Sketch and Figma. Polygon tools in Illustrator and Sketch will generate <polygon /> elements in SVG. In Figma, on the other hand, all shapes made with a Polygon tool result in <path /> elements.

All three design tools also have dedicated Star tools to draw stars. However, when it comes to export, shapes created with Star tools behave exactly the same as those created with Polygon tools. In SVG, stars are just polygons, there is NO ~~<star />~~ element.

It’s important to remember that Star and Polygon tools are used to create regular stars and polygons, while the <polygon /> element in SVG can be used for any polygon, regular or irregular.

All Roads Lead To <path />

As we already learned, in SVG, there are three basic shapes dedicated to drawing shapes made out of straight lines: <line />, <polyline /> and <polygon />. But what if we’d like our lines to be curved? It’s a high time we spoke about the <path /> element.

The <path /> Element

<path /> is the most versatile SVG element. It can be used to draw any possible line and shape, including, but not limited to, all the basic shapes listed above. In fact, every basic shape (<circle/>, <ellipse />, <rect />, <line />, <polyline />, <polygon />) can be described as a <path /> element. What is more, there are many shapes that can be created with <path /> but are not possible to create with any other SVG element. To learn more about <path /> and its syntax, I would recommend you to check out this excellent article by Chris Coyier.

Now, how do we create <path /> elements in design tools? First of all, as we learned above, some of the layers created with shape tools compute to <path /> elements even though they theoretically could be other elements (e.g. Figma exports all polygons as <path />s even though they could have been defined as <polygon />s. Then, every other irregular shape we draw with a Pen tool or a Vector tool must be exported as <path /> as there’s no other SVG element that could define them. Finally, in Sketch and Figma, we can convert any basic shape into a layer that computes to a <path />. In Sketch, we can accomplish this by choosing Layer > Combine > Flatten, while is Figma we can find this function under Object > Flatten Selection (⌘ + E on macOS, Ctrl + E on Windows).

Boolean Operations

Boolean operations are functions performed on shapes to combine them in a few different ways. In Illustrator, Sketch and Figma, there are 4 standard boolean operations:

  • Union (Unite)
    A sum of the shapes
  • Subtract (Minus front)
    Bottom shape subtracted by the common area between the shapes
  • Intersect
    The common area between the shapes
  • Difference (Exclude)
    A sum of the shapes subtracted by the common area between the shapes.

In Illustrator, all of these functions generate a single shape (outline). It is an action that cannot be reversed — otherwise than using Undo (⌘ + Z on macOS, Ctrl + Z on Windows). In Sketch and Figma, on the other hand, boolean operations create layer groups that can be ungrouped later on without any harm caused to the shapes inside. However, you can merge these groups into a single shape to achieve a similar result as in Illustrator using Flatten functions mentioned in the previous paragraph.

The question is, does SVG support boolean operations? No, it doesn’t. They just get merged. Therefore, every combined shape you create with boolean operations in Figma or Sketch will be exported as a single <path /> element.

It Looks The Same, So Why Does It Matter?

In terms of how different shapes can be defined in SVG, its syntax is extremely versatile. Let’s consider a basic rectangle:

Nothing more than a rectangle (Large preview)

Such a shape can be defined in SVG in a few different ways. It can be a <rect /> element, a <polygon /> element. It definitely can be a <path /> element (as everything can be a <path /> element). It can also be a <line /> element (or a <polyline /> element) if we decide to create it using strokes instead of fills.

Each of these elements renders a rectangle that looks exactly the same:

rectangle <rect width="2" height="3" fill="black"/> polygon <polygon points="0,0 2,0 2,3 0,3" fill="black"/> line <line x1="1" y1="0" x2="1" y2="3" stroke="black" stroke-width="2"/> path e.g. <path d="M0,0 l2,0 l0,3 l-2,0" fill="black"/> or <path d="M1,0 l0,3" stroke="black" stroke-width="2"/>

But, if the final result (the graphic rendered by a user agent in a browser) looks the same, does it really matter what approach do we choose? Well, it does. As a rule of a thumb, I would always recommend using basic shapes where possible.

Last but not least, use the most obvious shapes for the given case. For example, don’t create rectangles with lines or circles with rectangles if you don’t have a good reason. There are at least a few arguments behind that:

  1. Semantics/Readability
    Compression tools, such as SVGO, give you an option to compute all the basic shapes to path elements. It can save you a few bites but will definitely lower the readability of your code. <path /> syntax is extremely unintuitive, so if your SVG is ever about to be modified in a code editor rather than a design tool, it will be so much easier to understand it if you keep the basic shapes as basic shapes.
  2. File Size
    Compressing shapes to paths may help you minify files but it’s not always the case! For example, a rounded rectangle takes much more space as a <path /> than as a <rect />.
  3. Animations
    Have you ever tried to animate SVG? It’s a lot of fun — as long as you operate on clean, semantic SVG. With basic shapes, you can easily manipulate such parameters as radius, width, height or position of the point. If you merge your shapes into paths, most of those operations will be much harder to achieve or simply impossible.
  4. Variants/Responsiveness
    Remember that SVG is not a static image such as JPG. You can style it, theme it, make it responsive, and so on. Same as with animations, keeping your file well-structured and semantic will definitely help you with any of those tasks.

As with every rule, you can find some exceptions. But, on a general basis, it’s good practice to keep your SVG as readable, flexible and structured as possible.

Now, let’s take a look at other attributes and features such as viewBox, groups, transforms and visual effects.

width, height and viewBox

If you already have some experience with SVG, you probably noticed that the opening <svg> tag often has the following attributes: width, height and viewBox. In design tools, we have dimensions of artboards (or frames in case of Figma). So how exactly these values are related to each other?

Let’s start with explaining the <svg> attributes we just mentioned. You can think of a viewBox as of a virtual canvas in the form of a coordinate system. The centre of this coordinate system is placed in the top left corner of the designated area. All items within the <svg viewBox="…"> tag are placed according to this coordinate system and also clipped by it — anything that overflows the viewBox won’t be rendered. viewBox accepts 4 numbers as its value:

<svg viewBox="0 0 12 8"> … </svg> viewBox model in SVG (Large preview)

As SVG stands for Scalable Vector Graphics, no units are needed on these numbers. Just imagine it as an abstract coordinate system that can be scaled up and down to any size. Don’t worry too much about the first two numbers, most likely you won’t need them. The latter two are what usually matters. These are the actual dimensions of our SVG canvas.

viewBox doesn’t determine SVG’s size. It just specifies the coordinates of the area in which our SVG is drawn. Therefore, when used on the web, <svg> with a specified viewBox will always take all the available space and preserve the ratio set by the viewBox — unless we prevent this with CSS or set the width and/or height attributes.

width and height are the <svg> attributes that set the actual width and height of the SVG element. On the contrary to viewBox, they should use specified units such as pixels, ems or rems. This means that we can also transform the SVG with them — if the ratio between the width and height is different than the ratio between the values of the viewBox, SVG will skew the graphic specified within the viewBox according to the width and height values:

viewBox’s aspect ratio is 3:2 but its width and height attributes make it display as a square. (Large preview)

Now, what happens when we export SVG from design tools? In Sketch and Figma, all assets (no matter if they’re single layers, groups or artboards) will always get a viewBox equal to the dimensions of the exported element and width and height set in pixels, equal to the last two values of the viewBox. In Illustrator, all assets have a viewBox, specified the same way as in Sketch and Figma, but no width and height applied.

Groups

Groups are the basic mean of organizing layers in design tools. Apart from setting hierarchy, groups are used to apply bulk operations, such as transforms, to multiple elements. There’s no significant difference in how groups work across Illustrator, Sketch and Figma and, fortunately, the basic functionality of SVG groups (<g>…</g>) is pretty much the same.

Transforms

In SVG, there are five basic transforms that we can apply to an element:

  1. translate: moves the element along the vertical and/or horizontal axis;
  2. scale: scales the element along the vertical and/or horizontal axis:
  3. rotate: creates a two-dimensional rotation by a given angle specified in degrees around a given point;
  4. skew (skewX or skewY): skews the element by a given angle specified in degrees along the vertical or horizontal axis;
  5. matrix: the most complex and versatile of available transform functions. As it would require quite a lot of algebra talk to explain how matrix transformations work, it goes far beyond the scope of this article. Let’s just acknowledge that matrix allows you to perform many complicated transforms such as stretching, squeezing, shearing, and so on.

Note: Notice that even though some of the SVG transforms look very similar to CSS transforms, they are not the same. For example, CSS offers both 2D and 3D rotation functions while SVG has only one 2D rotate function. Also, while CSS accepts various angle units such as degrees or radians, SVG rotations are always set in degrees, therefore a unit can be omitted (e.g. rotate(45), NOT ~~rotate(45deg)~~).

All of these transforms can be applied to any SVG element, such as shapes or groups, and are non-destructive, i.e. do not affect the original geometry of the element. We apply transforms via a transform attribute:

<g transform="scale(3) rotate(90) translate(50,100)"> … </g>

Let’s take a look at the design tools now! So, most of the transforms we apply in design tools interact directly with the objects’ geometry and their position on the canvas. They are not independent from the shapes and will not be exported as SVG transform functions.

Rotations are here the exception, with their values being stored in the Inspector separately from the element’s geometry and they do export as a transform="rotate(…)" function.

Interestingly, the same rule applies to flips (reflections) in Sketch and Figma (not in Illustrator!). Each of them has its own approach though. Sketch uses a combination of negative scaling and translating to achieve a flip effect, while Figma performs a flip within a single matrix function.

Border Radius

We already spoke about rounded rectangles but what about rounding other shapes? In fact, in all the designs tools we discuss, you can round the corners of any shape, not only a rectangle.

But what about SVG? Do <polygon /> and <path /> elements also have a rx and ry attributes? Unfortunately, no. Any shape other than a rectangle, once you round any of its corners, will always be exported as a <path /> element treating the rounded corners as an integral part of the shape’s geometry.

Fills And Strokes

Illustrator, Sketch and Figma all support fills and strokes as the basic properties of any shapes, and so it happens in SVG. Therefore, fills specified in design tools are exported within a fill attribute and stokes are exported within a stroke attribute. Don’t think it’s all that straightforward though. The devil is in the details.

Color Fill

Color fill is the most basic of available fills and is specified with a single plain color (e.g. #3fd8e2). In SVG, this value is put directly in the fill attribute (e.g. fill="#3fd8e2").

Design tools export color fills with hex values (e.g. #0000ff), although, in SVG, you can also use all the other naming schemes known to CSS, such as color names (e.g. blue), RGB values (e.g. rgb(0,0,255)) or even HSL values (e.g. hsl(240,100%,50%)).

Fill Opacity

When it comes to fill opacity, SVG accepts semi-transparent colors (e.g. RGBA values), although it also provides a fill-opacity attribute. Because of compatibility issues, using fill-opacity is a recommended approach and it is also the one used by Figma and Sketch. (I’m not mentioning Illustrator here, as Illustrator does not allow you to control fill opacity.) So, if you want to create an SVG square filled with half-transparent red color, you can do the following:

<rect width="100" height="100" fill="rgba(255,0,0,0.5)" />

but a more recommended approach (used by Sketch and Figma) would be:

<rect width="100" height="100" fill="#ff0000" fill-opacity="0.5" /> Gradient Fill

If you’re familiar with CSS, you may know that when it comes to backgrounds, switching between color and gradient backgrounds is relatively straightforward. The same background-color (or background) property can be used in both cases. As gradients in SVG are much older than CSS gradients, their syntax is also quite different.

To use a gradient is SVG, you first need to define it within the <defs>…</defs> tags and then refer to it in a fill attribute, e.g.:

<defs> <linearGradient id="myGradient"> <stop stop-color="red" offset="0%"></stop> <stop stop-color="blue" offset="100%"></stop> </linearGradient> </defs> <rect fill="url(#myGradient)" />

So, what happens during SVG export when you use a gradient fill is that a gradient is added to the <defs> and it’s being referenced in the code below.

An important thing to remember is that that SVG supports only linear and radial gradients. Effects such as angular gradient or gradient mesh won’t be exported to SVG.

Pattern/Image Fill

Sketch and Figma also offer an Image fill where a raster graphic is used either to fill the entire element or as a repeating pattern.

When it comes to exporting Image fills to SVG, it’s actually quite similar to gradients. Images are being defined in the <defs> with a <pattern>…</pattern> element and then referenced within a fill attribute:

<defs> <pattern id="myPattern" patternUnits="objectBoundingBox"> <use xlink:href="#picture"></use> </pattern> </defs> <rect fill="url(#myPattern)" />

To make it work, the referenced #picture image must be defined somewhere. The design tools will embed them directly in SVG as <image/> elements, although it’s not a recommended approach when it comes to performance. If you really need to use raster images in your SVG, I would suggest to remove the image tag from the SVG and use it a standalone file instead:

<defs> <pattern id="myPattern" patternUnits="objectBoundingBox"> <use xlink:href="#picture"></use> </pattern> <image xlink:href="image.png" id="picture"/> </defs> <rect fill="url(#myPattern)" /> Strokes

stroke attribute in SVG, same as fill attribute accepts colors in various formats, e.g. hex, RGB or HSL. And similarly to fill, you can control stroke’s opacity with stroke-opacity. Also, same as with fill, strokes can use gradients as their value. All of those effects can be achieved in design tools and successfully exported to SVG.

Stroke Caps And Joins

There are also a few stroke specific attributes though. First, you can control the stroke width. Design tools support it and its exported as stroke-width attribute. You can also control ends and joins of the strokes. SVG allows you to define them via stroke-linecap and stroke-linejoin attributes. There are three possible caps: butt cap, round cap and square cap, and three possible joins: miter join, round join and bevel join. Both caps and joins can be controlled in Illustrator, Figma and Sketch and available caps and joins are matching those available in SVG.

Dashed And Dotted Strokes

Another effect we can achieve with strokes is dashed strokes. In Illustrator and Figma, you can set multiple dashes and gaps, while in Sketch, only a single sequence of a dash and a gap is possible.

SVG allows you to create dashed lines with a stroke-dasharray attribute. stroke-dasharray allows a sequence of multiple dashes and gaps to be passed as its value which matches Figma’s and Illustrator’s features. It also means Sketch does not allow you to use the full possibilities of SVG in this case.

An interesting edge case is a dotted line. We achieve it by setting the stroke-linecap to round and a dash’s length to zero, e.g.:

<line … stroke="black" stroke-dasharray="0 2" stroke-linecap="round"/>

Note: Currently, Figma users experience a bug that doesn’t allow them to create dotted lines. For example, using 0, 10 or 10, 0 as Dashes is interpreted the same way as 10, 10 and gives a regular dashed line rather than a dotted line. Fortunately, there’s a way to get around it. Rather than using zero, use a very small value, e.g. 0.0001, 10 — this should result in perfectly dotted line, as expected.

Stroke Alignment

There is one other, much more significant difference between design tools and SVG: stroke alignment. Illustrator, Sketch and Figma all allow you to control the alignment of the stroke and set it inside, outside or centre-align it. But guess what? SVG 1.1 does not support stroke alignment. In SVG, all strokes are centre-aligned strokes. No inside strokes or outside strokes. Which is why some very weird things happen when you’re exporting your outside- and inside- aligned strokes to SVG.

Illustrator, in such case, exports the shape and its stroke as two separate shapes. So if you apply an inside stroke or an outside stroke to a rectangle in Illustrator, in SVG it will result in a rectangle and a separate <path /> element representing the rectangle’s stroke, e.g.:

<rect x="10" y="10" width="120" height="120"/> <path d="M120,20V120H20V20H120M140,0H0V140H140V0Z"/>

This behavior has some very important repercussions. For example, you can no longer change the width of the stroke or make it dashed. It also won’t scale the same way as “real” strokes. What is more, Illustrator changes the dimensions of the original shape, e.g. a 100×100 square with a 20-units bold inner stroke will actually export as a 120×120 square to avoid rendering issues. Eventually, it’s just not a stroke. It’s just another shape with a fill.

Figma and Sketch have a different approach though. They faithfully export all strokes as strokes but they recalculate the dimensions of the shape. So if you have a circle with a radius equal to 5 and an inside stroke equal to 2, what you’ll find in your SVG will be a circle with a radius equal to 4 (and a stroke still equal to 2).

This approach allows Figma and Sketch to avoid most of the issues mentioned in the case of Illustrator. However, with some more complicated shapes this technique may turn out not to be precise and the final result to be a bit different than expected. With is why Sketch’s and Figma’s approach is not necessarily better — it’s definitely more semantic, performant and flexible, but Illustrator’s solution is more accurate.

Note: The same problem with stroke alignment applies to CSS as well. The CSS border property does not support inside or outside alignment neither. However, if you want, you can hack this behavior with outline and box-shadow properties.

Multiple Fills And Strokes

In design tools, you can add multiple fills and strokes per layer. This makes a lot of sense once combined with such attributes as opacity and blend modes. Unfortunately, SVG does not support such a feature. If you export a layer that has fills and/or strokes, it will get multiplied and each of the strokes and fills applied to its own layer.

Shadows, Filters, And Other Effects

Let’s talk about some less popular effects now. SVG is a very powerful language, in fact much more powerful than how it’s usually used on the web. One of the most interesting SVG’s features is a wide range of advanced visual effects, known as SVG filters.

The full scope of SVG filter’s possibilities is far too wide to be described in this article. If you’d like to learn more about them I strongly recommend you to check out some talks and articles on this topic by Sarah Soueidan.

Filters, same as patterns or gradients, need to be defined to apply them later to a layer. Every filter is defined as a <filter>…</filter> element that can contain numerous effects, known as filter primitives, each standing for a separate visual effect.

Filter primitives can be combined together to create filters. For example, this is what a basic blur effect applied to a rectangle looks like:

<defs> <filter id="GaussianBlur"> <feGaussianBlur stdDeviation="10"/> </filter> </defs> <rect filter="url(#GaussianBlur)" width="200" height="300"/>

…but you can also create a more complex filter that consists of more than one filter primitive:

<defs> <filter id="GaussianBlur"> <feGaussianBlur stdDeviation="10"/> <feMorphology operator="dilate" in="SourceGraphic" radius="3" /> </filter> </defs> <rect filter="url(#GaussianBlur)" width="200" height="300"/>

Out of the three design tools we discuss, only Illustrator lets you play with SVG filters. You can find them in the app’s menu, under Effect > SVG Filters. Sketch and Figma are a completely different story. Any effects these applications offer are mostly focused on CSS and native implementations, e.g. Background Blur effect was implemented primarily for designing iOS apps and Drop/Inner Shadow effects parameters are matching CSS properties (box-shadow and text-shadow).

It doesn’t mean we can’t export these effects to SVG. We can. However, translating these effects to SVG is utterly not as straightforward as to CSS. Let’s consider a square with a drop shadow applied.

A rectangle with a shadow (Large preview)

This is how our square could look like, once exported to HTML/CSS:

<style> .square { width: 100px; height: 100px; background: red; box-shadow: 10px 10px 24px 0 rgba(0,0,0,0.5); } </style> <div class="square"></div>

A similar square exported from Sketch to SVG gives us a significantly more complex piece of code:

<defs> <rect id="square" x="14" y="14" width="100" height="100"></rect> <filter x="-31.0%" y="-31.0%" width="182.0%" height="182.0%" filterUnits="objectBoundingBox" id="filter-2"> <feOffset dx="10" dy="10" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="12" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> </filter> </defs> <g id="Rectangle"> <use fill="black" filter="url(#filter-2)" xlink:href="#square"></use> <use fill="#FF0000" fill-rule="evenodd" xlink:href="#square"></use> </g>

What happens here is that Sketch duplicates the square, so we have two identical squares, one above another, and turns the duplicate into a shadow.

To accomplish this, it applies a filter to a duplicated square that consists of three different filter primitives:

  • one to offset the square;
  • one to set its color to semi-transparent black;
  • one to blur it.

In other design tools, we would encounter a similar situation.

It doesn’t mean that we should never, by all means, use shadows in SVG. It’s handy to keep in mind though that as long as SVG gives you a very powerful toolkit to modify your graphics, some seemingly simple effects are not that simple to achieve at all.

Blend Modes

Blend modes (such as Darken, Multiply or Overlay) allow blending two or more elements by combining their values in different ways. Well known to graphic designers (and applications such as Adobe Photoshop), blend modes work in Sketch, Figma and Illustrator as well.

In SVG, blend modes exist as one of the filters. They have their own <feBlend /> filter primitive. However, as <feBlend />’s syntax is fairly complicated, Sketch, Figma and Illustrator use CSS instead:

.rectangle { mix-blend-mode: overlay; }

With mix-blend-mode browser support being fairly good nowadays, it shouldn’t be a big issue. However, if it’s important for you to ensure bulletproof browser support that includes Microsoft Edge and IE, you will have to replace the CSS blend modes with SVG filters manually.

Same as with multiple fills and strokes, SVG does not support blend modes applied directly on fill and stroke attributes (rather than on whole layers). If you try to export fill and strokes with their own blend modes from a design tool to SVG, the layer will get multiplied and the blend modes applied to respective copies of the layer.

Symbols And Components

In some of the code examples above, you may have noticed an element we haven’t discussed yet: a <use>…</use> element. <use> lets us define and reuse elements in SVG, a bit similar to Symbols in Illustrator and Sketch or Components in Figma. Remember defining patterns, gradients and filters within the <defs>…</defs> tags so they can be used in some other part of your SVG code? In fact, any SVG element can be defined and reused this way. Once you defined a shape or a group, you can refer to it in the rest of the document as many times as you like, e.g.:

<defs> <circle cx="100" cy="100" r="20" id="circle"/> </defs> <use fill="red" xlink:href="#circle"> </use> <use fill="green" xlink:href="#circle"> </use> <use fill="blue" xlink:href="#circle"> </use> …

You can also reuse much more complex structures using a <symbol>…</symbol> tag. Symbol acts as a separate body within our SVG and can have its own viewBox attribute (see Width, height and viewBox for reference).

Does it mean our design tools’ symbols and components will be exported to SVG symbols? In Illustrator — yes, it does. In Sketch and Figma — no, it doesn’t. Why? Primarily, because Illustrator symbols are fairly simple and can be easily translated to SVG while Sketch’s symbols and Figma’s components are not that simple at all and exporting some of its features (such as nested overrides) would be very tricky or even impossible.

Text

It wouldn’t be a comprehensive guide if we don’t mention typography. All the design tools offer a wide variety of tools related to text. SVG, even though usually used for graphics, supports text elements too.

Illustrator, Sketch and Figma all support exporting text to SVG and computes text layers into <text>…</text> elements in SVG. SVG text elements are rendered like any other graphic elements, shapes etc. with the only difference is that they’re text.

Same as in CSS, we can control all the basic text’s parameters, such as weight, line height or alignment. In fact, if you know how to style text in CSS, you already know how to do it in SVG. However, it may feel a bit old-school. Firstly, all the parameters must be set in inline attributes, similarly to the golden standards of HTML 3.2. Secondly, there are no shorthands. For example, you won’t find anything resembling a font CSS property. That’s because SVG text attributes are actually based on CSS 2 spec which takes us back to the 90ties and are way older than CSS we know today.

Nonetheless, all of those attributes are being exported from the design tools perfectly well every time we want some text layer to become SVG code.

Custom Fonts

Unfortunately, things get a bit tricky when it comes to custom fonts. Back in the days, when SVG 1 standard was being created, custom typefaces weren’t a common thing to the web. Everybody used standard fonts, such as Tahoma, Verdana or Courier. Going fancy and using fonts people didn’t have on their machines by default, usually meant rasterizing them ruthlessly and using them as images. However, SVG implemented its own fonts format, named SVG fonts. Today, 18 years after the SVG 1.0 was published, SVG fonts are no longer supported in most of the major browsers.

Luckily for us, SVG plays very nicely with CSS, which means we can use web fonts instead of SVG fonts, e.g.:

<style> @import url("https://fonts.googleapis.com/css?family=Roboto"); </style> <text x="20" y="50" font-family="Roboto">Text</text>

Let me not get into detail of implementing web fonts here apart from one crucial note: don’t forget about it. In other words, if you use custom fonts in your SVG, you need to remember about providing these fonts to the client, the same as in HTML/CSS.

Outlining Fonts

One may argue that much easier than warring about fonts and all, would be to outline all the text layers and don’t worry about them ever after. Nonetheless, there are at least a few good reasons not to change your text to shapes:

  1. You can’t edit outlined text — before nor after export.
    Working with outlined text, you need to remember about keeping an editable copy in your Illustrator, Sketch or Figma file at all times. Otherwise, you won’t be able to edit your text layers, once they are outlined. This adds unnecessary complexity to the process. Not to mention editing the outlined text after the SVG was exported. Text in SVG can be updated at any time. Outlined text requires opening the source file every time you want to make the tiniest copy change.
  2. Outlined text is not accessible.
    Text in SVG, same as other text elements on the web, can be read by screen readers and other accessible technologies. By outlining text layers, you prevent people from using such technologies from accessing your content.
  3. People expect text to be text.
    Most people using the web know absolutely nothing about SVG, HTML or design tools. If they see text, they expect it to be just that. They may want to select it, copy it or put in a search engine. All of this is possible with text in SVG — unless you outline it.
  4. Don’t forget about SEO.
    Text in SVG is also accessible and used by search engines. By outlining text, you make your content less searchable and potentially less visible to the public.
Summary

Thank you a lot for going with me on a journey through the ins and outs of working with SVG and design tools. This article definitely does not cover the full spectrum of the topic, although it should be enough to deal with the most common use cases. If you have any questions or queries regarding the things that have not been mentioned here, don’t hesitate to post them in the comments!

(dm, yk, il)
Categories: Web Design

Monitoring structured data with Search Console

Google Webmaster Central Blog - Thu, 05/02/2019 - 07:08
In our previous post in the structured data series, we discussed what structured data is and why you should add it to your site. We are committed to structured data and continue to enhance related Search features and improve our tools - that’s why we have been creating solutions to help webmasters and developers implement and diagnose structured data.

This post focuses on what you can do with Search Console to monitor and make the most out of structured data for your site. In addition, we have some new features that will help you even more. Below are the new additions, read on to learn more about them.
  1. Unparsable structured data is a new report that aggregates structured data syntax errors.
  2. New enhancement reports for Sitelinks searchbox and Logo.
Monitoring overall structured data performanceEvery time Search Console detects a new issue related to structured data on a website, we send an email to account owners - but if an existing issue gets worse, it won’t trigger an email, so it is still important for you to check your account sporadically.

This is not something you need to do every day, but we recommend you check it once in a while to make sure everything is working as intended. If your website development has defined cycles, it might be a good practice to log in to Search Console after changes are made to the website to monitor your performance.

If you’d like to have an overall idea of all the errors for a specific structured data feature in your site, you can navigate to the Enhancements menu in the left sidebar and click  a feature. You'll find a summary of all errors and warnings, as well as the valid items.

As mentioned above, we added a new set of reports to help you understand more types of structured data on your site: Sitelinks searchbox and Logo. They are joining the existing set of reports on Recipe, Event, Job Posting and others. You can read more about the reports in the Search Console Help Center.

Here's an example of an Enhancement report, note that you can only see enhancements that have been detected in your pages. The report helps you with the following actions:
  • Review the trends of errors, warnings and valid items: To view each status issue separately, click the colored boxes above the bar chart.
  • Review warnings and errors per page: To see examples of pages which are currently affected by the issues, click a specific row below the bar chart.
Image: Enhancements reportWe are also happy to launch the Unparsable Structured Data report, which aggregates parsing issues such as structured data syntax errors that prevented Google from identifying the feature type. That is the reason these issues are aggregated here instead of the intended specific feature report.

Check this report to see if Google was unable to parse any of the structured data you tried to add to your site. Parsing issues could point you to lost opportunities for rich results for your site. Below is a screenshot showing how the report looks like. You can access the report directly and read more about the report in our help center.
Image: Unparsable Structured Data reportTesting structured data on a URL levelTo make sure your pages were processed correctly and are eligible for rich results or as a way to diagnose why some rich result are not surfacing for a specific URL, you can use the URL Inspection tool. This tool helps you understand areas of improvement at a URL level and helps you get an idea on where to focus.

When you paste a URL into the search box at the top of Search Console, you can find what’s working properly and warnings or errors related to your structured data in the enhancements section, as seen below for Recipes.
Image: URL Inspection toolIn the screenshot above, there is an error related to Recipes. If you click Recipes, information about the error displays, and you can click the little chart icon to the right of the error to learn more about it.

Once you understand and fix the error, you can click Validate Fix (see screenshot below) so Google can start validating whether the issue is indeed fixed. When you click the Validate Fix button, Google runs several instantaneous tests. If your pages don’t pass this test, Search Console provides you with an immediate notification. Otherwise, Search Console reprocesses the rest of the affected pages.
Image: Structured data error detailWe would love to hear your feedback on how Search Console has helped you and how it can help you even more with structured data. Send us feedback through Twitter or the Webmaster forum.

Posted by Daniel Waisberg, Search Advocate & Na'ama Zohary, Search Console team 
Categories: Web Design

Digging Into The Display Property: Box Generation

Smashing Magazine - Wed, 05/01/2019 - 04:00
Digging Into The Display Property: Box Generation Digging Into The Display Property: Box Generation Rachel Andrew 2019-05-01T13:00:59+02:00 2019-05-20T13:37:57+00:00

This is the second in a short series of articles about the display property in CSS. You can read the initial article in the series at “The Two Values Of Display”. The display specification is a very useful spec to understand as it underpins all of the different layout methods we have.

While many of the values of display have their own specification, many terms and ideas are detailed in display. This means that understanding this specification helps you to understand the specifications which essentially detail the values of display. In this article, I am going to have a look at the box generation values of display — none and contents.

Everything Is A Box

In CSS everything generates boxes. A webpage is essentially a set of block and inline boxes, something you get to understand very well if you open up DevTools in your favorite browser and start selecting elements on the page. You can see the boxes that make up the layout, and how their margins, padding and borders are applied.

I have highlighted the ul element using Firefox DevTools so I can inspect the different parts of the box. (Large preview) Controlling Box Generation

The none and contents values of display deal with whether boxes should appear at all. If you have elements in your markup and don’t want them to generate a box in CSS then you need to somehow suppress generation of the box. There are two possible things you might want to do. Which are:

  • Prevent generation of a box and all of its children.
  • Prevent generation of a box but still display the children.

We can take a look at each of these scenarios in turn.

display: none

The none value of display is how we prevent the generation of a box and all the children of that box. It acts as if the element was not there at all. Therefore, it is useful in situations where you intend to completely hide that content, perhaps because it will be revealed later after activating a link.

If I have an example with a paragraph, an unordered list, and another paragraph you can see that the items are displaying in normal flow. The ul has a background and border applied, plus some padding.

See the Pen Box Generation example by Rachel Andrew.

See on Codepen

If I add display: none to the ul it disappears from the visual display, taking with it the children of the ul plus the background and border.

See the Pen Box Generation example display: none by Rachel Andrew.

See on Codepen

If you use display: none it hides the content from all users of the website. This includes screen reader users. Therefore, you should only use this if your intention is that the box and everything inside it is completely hidden to everyone.

There are situations where you might want to add additional information for users of assistive technology like screen readers but hide it for other users; in such cases, you need to use a different technique. Some excellent suggestions are made by Scott O ’Hara in his article “Inclusively Hidden”.

Using display: none is therefore pretty straightforward. Use it in a situation where you want a box and contents to vanish from the display, from the box tree, and from the accessibility tree (as if it were never there in the first place).

display: contents

For the second scenario, we need to look at a much newer value of display. The value display: contents will remove the box it is applied to from the box tree in the same way that display: none does, but leave the children in place. This causes some useful behavior in terms of things we can then do in our layouts. Let’s look at a simple example and then explore further.

I am using the same example as before, but this time I have used display: contents on the ul. The list items are now visible, however, they have no background and borders and are acting as if you have added li elements to the page without any enclosing ul.

See the Pen Box Generation example display: contents by Rachel Andrew.

See on Codepen

The reason that removing a box and keeping the children is useful is due to the way that other values of display behave. When we change the value of display we do so on a box and the direct children of that box, as I described in the last article. If I add display: flex to the CSS rules for an element, that element becomes a block-level box, and the direct children become flex items. The children of those flex items return to normal flow (they are not part of the flex layout).

You can see this behavior in the next example. Here I have a containing element set to display flex, it has four direct children, three div elements and a ul. The ul has two list items. The direct children all participate in the flex layout and lay out as flex items. The list items are not direct children and so display as list items inside the box of the ul.

See the Pen Box Generation flexbox and display: contents 1 by Rachel Andrew.

See on Codepen

If we take this example and add display: contents to the ul, the box is removed from the visual display and now the children participate in the flex layout. You can see that they do not become direct children. They are not selected by the direct child universal selector (.wrapper > *) in the way that the div and ul elements are, and they maintain the background given to them. All that has happened is that the box of the containing ul has been removed, everything else carries on as normal.

See the Pen Box Generation flexbox and display: contents 2 by Rachel Andrew.

See on Codepen

This has potentially very useful implications if we consider elements in HTML which are important for accessibility and semantic data, but which generate an additional box that may prevent us from laying the content out with flex or grid layout.

This Is Not A CSS “Reset”

You may have noticed how one side effect of using display: contents is that the margin and padding on the element are removed. This is because they are related to the box, part of the CSS Box Model. This might lead to you think that display: contents is a good way to quickly rid yourself of the padding and margin on an element.

This is a use that Adrian Roselli has spotted in the wild; he was concerned enough to write a detailed post explaining the problems of doing so — “display: contents is not a CSS reset.” Some of the issues he raises are due to an unfortunate accessibility issue in browsers currently with display: contents which we will discuss below. However, even once those issues are resolved, removing an element from the box tree simply to rid yourself of the margin and padding is somewhat extreme.

If nothing else, it would be problematic for the future maintenance of the site, a future developer might wonder why they didn’t seem to be able to apply anything to this mysterious box — missing the fact it had been removed! If you need margin and padding to be 0, do your future self a favor and set them to 0 in a time-honored way. Reserve use of display: contents for those special cases where you really do want to remove the box.

It is also worth noting the difference between display: contents and CSS Grid Layout subgrid. Where display: contents completely removes the box, background, and border from the display, making a grid item a subgrid would maintain any box styling on that item, and just pass through the track sizing so that nested items could use the same grid. Find out more in my article, “CSS Grid Level 2: Here Comes Subgrid.”

Accessibility Issues And display: contents

A serious issue currently makes display: contents not useful for the very thing it would be most useful for. The obvious cases for display: contents are those cases where additional boxes are required to add markup that makes your content more easily understood by those using screen readers or other assistive devices.

The ul element of our list in the first display: contents CodePen is a perfect example. You could get the same visual result by flattening out the markup and not using a list at all. However, if the content was semantically a list, would be best understood and read out by a screen reader as a list, it should be marked up as one.

If you then want the child elements to be part of a flex or grid layout, just as if the box of the ul was not there, you should be able to use display: contents to magic away the box and make it so — yet leave the semantics in place. The specification says that this should be the case,

“The display property has no effect on an element’s semantics: these are defined by the document language and are not affected by CSS. Aside from the none value, which also affects the aural/speech output and interactivity of an element and its descendants, the display property only affects visual layout: its purpose is to allow designers freedom to change the layout behavior of an element without affecting the underlying document semantics.”

As we have already discussed, the none value does hide the element from screen readers, however, other values of display are purely there to allow us to change how things display visually. They should not touch the semantics of the document.

For this reason, it took many of us by surprise to realize that display: contents was, in fact, removing the element from the accessibility tree in the two browsers (Chrome and Firefox) that had implemented it. Therefore changing the document semantics, making it so that a screen reader did not know that a list was a list once the ul had been removed using display: contents. This is a browser bug — and a serious one at that.

Last year, Hidde de Vries wrote up this issue in his post “More Accessible Markup with display:contents” and helpfully raised issues against the various browsers in order to raise awareness and get them to work on a fix. Firefox have partially fixed the problem, although issues still exist with certain elements such as button. The issue is being actively worked on in Chrome. There is also an issue for WebKit. I’d encourage you to star these bugs if you have use cases for display: contents that would be impacted by the issues.

Until these issues are fixed, and the browser versions which exhibited the issue fall out of use, you need to be very careful when using display: contents on anything which conveys semantic information and needs to be exposed to assistive technology. As Adrian Roselli states,

“For now, please only use display: contents if you are going to test with assistive technology and can confirm the results work for users.”

There are places where you can safely use display: contents without this concern. One would be if you need to add additional markup to create fallbacks for your grid of flex layouts in older browsers. Browsers which support display: contents also support grid and flexbox, therefore you could display: contents away the redundant div elements added. In the example below, I have created a float based grid, complete with row wrappers.

I then use display: contents to remove the row wrappers to allow all of the items to become grid items and therefore be able to be part of the grid layout. This could give you an additional tool when creating fallbacks for advanced layouts in that if you do need to add extra markup, you can remove it with display: contents when doing your grid or flex layout. I don’t believe this usage should cause any issues — although if anyone has better accessibility information than me and can point out a problem, please do that in the comments.

See the Pen Removing row wrappers with display: contents by Rachel Andrew.

See on Codepen Wrapping Up

This article has taken a look into the box generation values of the display property. I hope you now understand the different behavior of display: none — which removes a box and all children completely, and display: contents which removes just the box itself. You also should understand the potential issues of using these methods where accessibility is concerned.

(il)
Categories: Web Design

The Wonders Of May (2019 Wallpapers Edition)

Smashing Magazine - Tue, 04/30/2019 - 05:50
The Wonders Of May (2019 Wallpapers Edition) The Wonders Of May (2019 Wallpapers Edition) Cosima Mielke 2019-04-30T14:50:31+02:00 2019-05-20T13:37:57+00:00

We always try our best to challenge your creativity and get you out of your comfort zone. A great occasion to do so is our monthly wallpapers challenge which has been going on for nine years already. It’s an opportunity to let your creative ideas run free and try something new, to indulge in a little project just for fun. Whatever technique you fancy, whatever story you want to tell with your wallpaper, the submissions to this challenge make for a unique bouquet of community artworks each month anew. Artworks that adorn desktops and, who knows, maybe even spark new ideas.

In this post, you’ll find wallpapers for May 2019, created with love by designers and artists from across the globe. The wallpapers all come in versions with and without a calendar and can be downloaded for free. At the end of this post, we also collected some May favorites from past years’ wallpapers editions that are too good to gather dust somewhere down in the archives.

Now before you decide on your favorite this month, we want to say thank-you to everyone who shared their artworks with us. And, well, if you’re feeling inspired, did you know that your work could get featured in one of our upcoming wallpapers posts, too? We’re always looking for fresh talent, so don’t be shy, join in. ;-)

Further Reading on SmashingMag:

April Showers Bring Magnolia Flowers

“April and May are usually when everything starts to bloom, especially the magnolia trees. I live in an area where there are many and when the wind blows, the petals make it look like snow is falling.” — Designed by Sarah Masucci from the United States.

The Wriggling Glory of River Uvac

“Did you know that there are around 65 pairs of griffon vultures in Serbia? And did you know that one of their natural habitats is located at the river Uvac canyon? Nested between Zlatibor and Zlatar mountains, the wriggling flow of river Uvac is one of the most recognizable marks of Western Serbia and one of the most beautiful natural scenes in the country. And yes, May is just the perfect time to visit and enjoy its glory.” — Designed by PopArt Studio from Serbia.

Floral Impression

“My main inspiration behind this were the blooming flowers in May. My mother collects blue and white Japanese china which was the pot inspiration. The blues and pinks together are what I find to be one of the most complimentary color palettes.” — Designed by Olivia Osborne from Pennsylvania.

Lookout At Sea

“I wanted to create something fun and happy for the month of May. It’s a simple concept, but May is typically the time to adventure out into the world and enjoy the best of Spring.” — Designed by Alexander Jubinski from the United States.

Happy Birthday To Papú!

“May is the month of celebration! We are happy to share with you the Papú’s birthday.” — Designed by Veronica Valenzuela from Spain.

May Mountains

Designed by Harley LeBlanc from the United States.

Cool As An Octopus

“A fear I need to conquer inspired this wallpaper design. I never really liked the ocean because of how much we don’t know about it or anything that lives in it. However, I have decided to try and focus on the beautiful parts of this great unknown by choosing an octopus.” — Designed by Alexandra Covaleski from the United States.

Stranded

Designed by Ricardo Gimenes from Sweden.

Sun’s Out, Tongues Out

“May reminds me of long car rides while the cool breeze whips through the open windows. What better companion to have than a big friendly dog? Cool breeze, warm sun, and a furry friend.” — Designed by Samantha Strausser from the United States.

Hello Spring!

“I was at a local bike shop the other day, and I saw one of the vintage bikes. I loved the shape of it. I also was inspired by May flowers.” — Designed by Olivia Bartoli from the United States.

Oldies But Goodies

Whimsical, adventurous, delicate — the May wallpapers which reached us in the past few years are as different as the artists who created them. Here are some of our favorites from the past. Which one is yours? (Please note that these designs come from our archives, and, thus, don’t include a calendar.)

Lake Deck

“I wanted to make a big painterly vista with some mountains and a deck and such.” — Designed by Mike Healy from Australia.

It’s Finally May, My Deer

“After going through a super long winter, I was inspired to create this whimsical wallpaper because I wanted to highlight the beauty of nature and how I envision it to be during the warmer seasons that have yet to come.” — Designed by Michaela Schmidt from Maryland.

All Is Possible In May

“Edwin Way Teale once said that ‘[t]he world’s favorite season is the spring. All things seem possible in May.’ Now that the entire nature is clothed with grass and branches full of blossoms that will grow into fruit, we cannot help going out and enjoying every scent, every sound, every joyful movement of nature’s creatures. Make this May the best so far!” — Designed by PopArt Studio from Serbia.

Spring Gracefulness

“We don’t usually count the breaths we take, but observing nature in May, we can’t count our breaths being taken away.” — Designed by Ana Masnikosa from Belgrade, Serbia.

Cruel Life

Designed by Elise Vanoorbeek (Doud Design) from Belgium.

Stone Dahlias

Designed by Rachel Hines from the United States.

Field Wild Flowers

“Springtime festival celebrated with May blossoms.” — Designed by Richard George Davis from South Africa.

Enjoy May!

“Springtime, especially Maytime is my favorite time of the year. And I like popsicles — so it’s obvious isn’t it?” — Designed by Steffen Weiß from Germany.

Birds Of May

“A little-known ‘holiday’ on May 4th known as ‘Bird Day’. It is the first holiday in the United States celebrating birds. Hurray for birds!” — Designed by Clarity Creative Group from Orlando, FL.

Always Seek Knowledge

“‘As knowledge increases, wonder deepens.’ (Charles Morgan) So I tried to create an illustration based on this.” — Designed by Bisakha Datta from India.

Magical Sunset

“I designed Magical Sunset as a friendly reminder to take a moment and enjoy life around you. Each sunset and sunrise brings a new day for greatness and a little magic.” — Designed by Carolyn Warcup from the United States.

Mental Health Awareness Day

Designed by Kay Karremans from Belgium.

Game Boy

Designed by Sander Geenen from Belgium.

Join In Next Month!

Please note that we respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience throughout their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.

Thank you to all designers for their participation. Join in next month!

Categories: Web Design

A Designer’s Guide To Better Decisions

Smashing Magazine - Mon, 04/29/2019 - 03:30
A Designer’s Guide To Better Decisions A Designer’s Guide To Better Decisions Eric Olive 2019-04-29T12:30:16+02:00 2019-04-29T22:04:14+00:00

Nearly everyone has experienced frustration while using a website, mobile app, or web application. In these moments, we might wonder “What were they thinking?” followed by “They sure were not thinking about making this easy for me.” One reason we encounter such frustrating moments is that the process of making sound and user-friendly decisions is difficult.

In this article, we’ll identify four decision-related traps that impede good design and offer techniques for avoiding these traps. These decision traps are based on research conducted by psychologists, neuroscientists, molecular biologists, and behavioral economists including several cited in this article.

Too many design decisions occur in isolation, are based on gut feel, or are not carefully examined. The web offers many examples of poor design decisions. For instance, let’s take a look at the example below.

On the left: Are they asking for city, state, or country? On the right: This tooltip does not answer the user’s question. (Large preview)

At first glance, it seems quite straightforward: type the place of birth in the text field. A moment’s reflection, however, raises a question. Should we type the country, state, or city? It’s not clear. Clicking the question mark icon displays the help text shown below, to the right. The problem? The text does not answer the question; it simply restates the original request about entering the place of birth.

The design shown above violates a basic tenet of user experience (UX) immortalized by the title of Steven Krug’s famous book Don’t Make Me Think. Sure, it’s an amusing title, but he’s serious. The entire field of user experience is based on the idea of reducing the user’s cognitive load:

“Just like computers, human brains have a limited amount of processing power. When the amount of information coming in exceeds our ability to handle it, our performance suffers.”

Kathryn Whitenton

In other words, when a design requires users to guess or think too hard about something as simple as one text entry, users will often make mistakes (costing your organization time and money) or abandon the task altogether.

Lightening the user’s cognitive load means increasing our own cognitive load as designers. We do have to think, hard and carefully. Essential to this effort is learning how to make good design decisions.

There are four common decision traps that we often fall into. I’ll explain how you can avoid them.

  1. Availability Heuristic
  2. Focalism Bias
  3. Optimism Bias
  4. Overconfidence Bias
1. Availability Heuristic

A heuristic is a mental shortcut that helps us make decisions quickly. These mental shortcuts are essential in certain situations. For example, if a car veers into your lane, you must act quickly; you don’t have time to review several options.

Unfortunately, heuristics become a flaw when making decisions in situations where many factors and participants must be considered. One such flaw is the availability heuristic, which involves an incomplete examination of current and past information.

A particularly distressing example of the availability heuristic in the design space is the software on the Boeing 737 Max. As of this writing, it appears that this software contributed to the tragedy of the downed airplanes. People around the world have asked how to prevent such tragedies in the future.

Part of the answer lies in avoiding quick fixes. Airbus, Boeing’s chief competitor, had refitted their A320 planes with larger engines. Boeing felt pressured to do the same leading to a variety of changes:

“The bigger engines altered the aerodynamics of the plane, making it more likely to pitch up in some circumstances.”

To compensate, Boeing added new software to the 737 Max:

This software “would automatically push the nose down if it sensed the plane pointing up at a dangerous angle. The goal was to avoid a stall. Because the system was supposed to work in the background, Boeing believed it didn’t need to brief pilots on it, and regulators agreed. Pilots weren’t required to train in simulators.”

The obvious and horrifying conclusion is that Boeing engineers and designers were placed under immense pressure to re-design the 737 Max at record speed resulting in a series of misjudgments. Less obvious, but equally troubling, is the likely role of the availability heuristic in these tragedies.

In short, the information used to make critical design decisions was not sufficient and resulted in tragedy.

The availability heuristic limits our perspective (Large preview) Solution

One solution is for designers to identify their area of competence. Within this sphere their intuitions are likely to serve them well, explains author Rolf Dobelli in The Art of Thinking Clearly. For example, UX designers should feel comfortable making decisions about layout and interaction design issues like flow, navigation, and how much information to present at one time.

When designers face a decision outside their circle of competence, it’s worth taking time to apply hard, slow, rational thinking. For example, when designing cockpit software for jets, designers would be well advised to work closely with engineers and pilots to ensure that everything in the proposed user interface (UI) is precise, accurate, and provides the information pilots need when they need it.

We are all subject to the availability heuristic. Designers must strive to mitigate this heuristic by consulting a variety of subject matter experts (SMEs), not simply the programmers and engineers on their immediate teams. The downside risk is simply too high.

2. Focalism Bias

The availability heuristic hinders our ability to assess current and past information. The focalism bias concerns our ability to look forward. It refers to the inclination to concentrate on a single point when considering the future. As Harvard psychologist Daniel Gilbert explains in his book Stumbling on Happiness:

“It is difficult to escape the focus of our own attention — difficult to consider what it is we may not be considering.” The focalism bias restricts our view of the future. (Large preview)

For example, while my colleagues and I were conducting UX research for a U.S. government agency, we discovered that caseworkers could not access information essential to processing applications for medical assistance.

As shown in the diagram below, these caseworkers literally had to stop in the middle of the application process in order to request critical information from another division. Typically, caseworkers had to wait 24 to 48 hours to receive this information.

The focalism bias led to a delay, the opposite of the desired results. Our re-design resolved the issue. (Large preview)

Caseworkers found this delay stressful because it made it more difficult to meet a federal law requiring all applications to be processed within 10 days of receipt.

How did this happen? One reason, surprisingly, was the emphasis on deadlines. Through our observation and interviews, we learned that the system had been rushed into production to meet a project deadline (all too common) and to give caseworkers a way to process applications more efficiently.

The intentions were good, the goals made sense. Unfortunately, the focus on rushing a system into production to supposedly expedite the process had the opposite effect. Designers created a system that delayed the application process.

Solution: Become An Active Problem Seeker

This idea may sound counterintuitive. Why would we look for problems? Don’t we already have enough to deal with? In truth, however, organizations that seek problems, such as Toyota, often demonstrate impressive performance. They’re called high-reliability organizations (HROs). Other examples include the U.S. Navy’s aircraft carriers and air traffic control centers in the U.S., both of which have incredibly low error and failure rates.

As decision expert Michael Roberto of Bryant University explains, leaders of HROs do not wall themselves off from the possibility of failure. On the contrary, they preoccupy themselves with failure. For example, they:

  • Do not simplify explanations.
  • Remain sensitive and attentive to their front-line operations as we did while observing caseworkers.
  • Defer to those who have the local, specialized knowledge as opposed to those who simply have authority in the hierarchy. Again, we relied on the expertise of caseworkers on the ground.
  • Commit to resilience, to the notion that you cannot prevent all small problems. Rather, the goal is to focus on fixing these small problems before they mushroom into large problems.
Actively seeking problems leads to better decisions. (Large preview)

Problems are not the enemy; hidden problems are because these hidden problems become serious threats down the road as we saw in the government agency examples outlined above. In both cases, earlier and additional contextual inquiry (observing users in their natural home or work environments) would likely have identified current problems and possible UI solutions to these problems.

For example, while conducting contextual inquiry for a large Mexican bank, I observed customers trying (and failing) to transfer money to family members who held accounts at different banks. Customers expressed frustration at this limitation because they wanted an easy way to send money to family members, especially those who lived far away.

While living in Mexico, I learned that loaning and giving money to family members is more common in Mexico than in the U.S., Canada, or parts of Western Europe.

Given the deeply rooted Mexican tradition of supporting family members in financial need, I was initially surprised by this banking limitation. Upon reflection, however, I realized that this limitation was simply a hidden problem. When coding the banking web site, the developers were likely focused on security, paramount in all matters financial. They had not considered including a cross-bank transfer feature.

I identified this missing feature by conducting UX Research with banking customers in Mexico. This real-world example shows how critical it is to become an active problem seeker.

3. Optimism Bias

Focusing on a single point or problem impedes our ability to plan and design for the future. An equally troubling challenge is the optimism bias. We tend to imagine the best-case scenario.

“For example, we underrate our chances of getting divorced, being in a car accident, or suffering from cancer. We also expect to live longer than objective measures would warrant, overestimate our success in the job market, and believe that our children will be especially talented.”

Tali Sharot

In design culture, this bias sounds like this:

“Sure, this part of the UI is a bit clunky, but customers will get used to it, and then it won’t be an issue.”

In other words:

“We need to ship the product; we don’t want to deal with the cumbersome interaction.”

As anyone who has conducted a survey or usability test knows, this optimism is misplaced. Users and customers are easily frustrated and often show little patience when products and UIs are hard to use.

I witnessed this bias when designing a web application for financial advisers — 70% of whom were male. The client insisted on using a red font to emphasize certain numbers. Even after I explained that approximately 9% of males are color blind, she refused to change the font color. She reasoned that financial advisers would see the numbers in context. In other words, no problem. When I conducted multiple rounds of usability testing, however, two male advisers struggled to distinguish the numbers in red. They could read those numbers, but the figures did not stand out.

The reason for this type of wishful thinking is our tendency to see the future as a variant of the present. We tend to assume that things will go on more or less as they have. In the case of the financial application, because advisers had not complained before so my client assumed that they would not complain in the future. What she failed to grasp was the significance of changing the font to red.

As author David DiSalvo explains:

“We tend to simulate the future by re-constructing the past, and the re-construction is rarely accurate.” Solution: The Pre-Mortem Technique

That’s why it’s essential to resist this innate tendency by leveraging techniques like psychologist Gary Klein’s pre-mortem. The idea is to describe a scenario in which the project failed to meet a specific goal such as a revenue target, an increase in the percentage of new purchases, requests for more information, etc.

Here’s how it works. Before committing to a major initiative, the key stakeholder (often an executive) gathers everyone who is slated to participate. She outlines the key objective and explains “what went wrong.” The statement will sound something like this:

“Imagine that we have rolled out a new e-commerce mobile app at a cost of $3 million with a projected revenue of $10 million for the first year. At the end of one year, revenue is $1 million, a huge failure. Please take 20 minutes to write a history of this failure.”

This pre-mortem exercise:

  • Legitimizes doubt by providing a safe space for asking questions and expressing concerns about the decision.
  • Encourages even supporters of the decision to search for threats not previously considered.

An e-commerce mobile app is simply an example. The pre-mortem technique can be applied to nearly any project in any industry because it’s about expanding our perspective in order to identify what could realistically go wrong.

4. Overconfidence Bias

We unconsciously exaggerate our ability to accurately assess the present and predict the future. A study of patients who died in a hospital ICU compared the doctor’s diagnosis to the actual autopsy results. The doctors who were completely confident in their diagnosis were wrong 40% of the time.

When designers fall prey to the optimism bias, they exaggerate their ability to understand how users think. The most common results are information overload and confusing terminology and controls (buttons, checkboxes, sliders, and so on).

For example, while evaluating a client’s tablet-based investment application targeted at lay people, my team and I immediately noticed that:

  • The screen where users would create a risk profile included extraneous information.
  • The phrase “time zone” would likely confuse users. The client intended the term to refer to the customer’s investment time horizon. Yet, “time zone” usually means the time in a country or region, such as the U.K. or South Africa.
  • Plus and minus controls exhibited low affordance meaning that it was hard to tell whether they could be tapped or were simply part of the display.

These observations were supported during a subsequent usability test when participants expressed confusion over these specific points. In short, the designers for this project had overestimated their ability to create an interface that users would understand.

Solution

One solution is to conduct user research as we did with the tablet-based financial application outlined above. If such research is not possible, a second solution is to actively seek case studies beyond your immediate context. For example:

  • If you are designing an investment application, it might make sense to **refer to banking applications** to identify potential design challenges and what is already working well for customers.
  • If you are designing a tablet application to help nurse practitioners make a preliminary diagnosis, **look to other projects that are related** but outside your immediate context. Has your company developed a medical device UI for surgeons or ER doctors? What worked well for users? What did not?

Referring to other projects may sound like a no-brainer. Ask yourself, however, how often a systematic review of previous, related (but not identical) projects occurs within your organization. Remember, we are all subject to overconfidence.

Conclusion

In this piece, we’ve identified four common decision traps and corresponding solutions:

  1. The availability heuristic causes us to ignore potentially important current or past information when making decisions. The solution is to expand our perspective by reaching beyond our circle of competence. For designers, this often means consulting highly technical experts.
  2. Closely related is the focalism bias, our tendency to concentrate on a single point when designing thus overlooking other, equally important factors. The solution is to actively seek problems in order to identify and address hidden problems now before they become even larger difficulties.
  3. The optimism bias refers to our tendency to imagine the best-case scenario. The solution is the pre-mortem technique. In this exercise, we imagine that a design project has gone terribly wrong and discuss why and how this happened. As with active problem seeking, the idea is to identify issues before they occur or get worse.
  4. In the design space, the overconfidence bias refers to exaggerating our ability to understand how users think and design accordingly. The solution is to conduct user research and seek case studies similar to the current design initiative.

The cognitive biases discussed here are not intended to criticize designers (I am one). Rather, they are scientific observations about human nature. While we can’t change our biology, we can remain mindful of this biology and apply the four solutions outlined in this article. In so doing, we will increase the chances of creating better, safer, and more engaging designs.

Resources (ah, yk, il)
Categories: Web Design

Web Graphic Design

Webitect - Sat, 04/27/2019 - 11:53

Web design is about more than just looking good. Rather, successful web design facilitates a smooth interaction between your organization and your users. Whether you’re selling a product, providing a service or doing something else entirely, the design of your site is a major element in your success. Clayton Johnson and his team will design […]

The post Web Graphic Design appeared first on Clayton Johnson SEO.

Categories: Web Design

Getting To Know The MutationObserver API

Smashing Magazine - Fri, 04/26/2019 - 04:30
Getting To Know The MutationObserver API Getting To Know The MutationObserver API Louis Lazaris 2019-04-26T13:30:16+02:00 2019-04-27T21:35:00+00:00

In complex web apps, DOM changes can be frequent. As a result, there are instances where your app might need to respond to a specific change to the DOM.

For some time, the accepted way to look for changes to the DOM was by means of a feature called Mutation Events, which is now deprecated. The W3C-approved replacement for Mutation Events is the MutationObserver API, which is what I’ll be discussing in detail in this article.

A number of older articles and references discuss why the old feature was replaced, so I won’t go into detail on that here (besides the fact that I wouldn’t be able to do it justice). The MutationObserver API has near complete browser support, so we can use it safely in most — if not all — projects, should the need arise.

Basic Syntax For A MutationObserver

A MutationObserver can be used in a number of different ways, which I’ll cover in detail in the rest of this article, but the basic syntax for a MutationObserver looks like this:

let observer = new MutationObserver(callback); function callback (mutations) { // do something here } observer.observe(targetNode, observerOptions);

The first line creates a new MutationObserver using the MutationObserver() constructor. The argument passed into the constructor is a callback function that will be called on each DOM change that qualifies.

The way to determine what qualifies for a particular observer is by means of the final line in the above code. On that line, I’m using the observe() method of the MutationObserver to begin observing. You can compare this to something like addEventListener(). As soon as you attach a listener, the page will ‘listen’ for the specified event. Similarly, when you start observing, the page will begin ‘observing’ for the specified MutationObserver.

The observe() method takes two arguments: The target, which should be the node or node tree on which to observe for changes; and an options object, which is a MutationObserverInit object that allows you to define the configuration for the observer.

The final key basic feature of a MutationObserver is the disconnect() method. This allows you to stop observing for the specified changes, and it looks like this:

observer.disconnect(); Options To Configure A MutationObserver

As mentioned, the observe() method of a MutationObserver requires a second argument that specifies the options to describe the MutationObserver. Here’s how the options object would look with all possible property/value pairs included:

let options = { childList: true, attributes: true, characterData: false, subtree: false, attributeFilter: ['one', 'two'], attributeOldValue: false, characterDataOldValue: false };

When setting up the MutationObserver options, it’s not necessary to include all these lines. I’m including these simply for reference purposes, so you can see what options are available and what types of values they can take. As you can see, all except one are Boolean.

In order for a MutationObserver to work, at least one of childList, attributes, or characterData needs to be set to true, otherwise an error will be thrown. The other four properties work in conjunction with one of those three (more on this later).

So far I’ve merely glossed over the syntax to give you an overview. The best way to consider how each of these features works is by providing code examples and live demos that incorporate the different options. So that’s what I’ll do for the rest of this article.

Observing Changes To Child Elements Using childList

The first and simplest MutationObserver you can initiate is one that looks for child nodes of a specified node (usually an element) to be added or removed. For my example, I’m going to create an unordered list in my HTML, and I want to know whenever a child node is added or removed from this list element.

The HTML for the list looks like this:

<ul id="myList" class="list"> <li>Apples</li> <li>Oranges</li> <li>Bananas</li> <li class="child">Peaches</li> </ul>

The JavaScript for my MutationObserver includes the following:

let mList = document.getElementById('myList'), options = { childList: true }, observer = new MutationObserver(mCallback); function mCallback(mutations) { for (let mutation of mutations) { if (mutation.type === 'childList') { console.log('Mutation Detected: A child node has been added or removed.'); } } } observer.observe(mList, options);

This is only part of the code. For brevity, I’m showing the most important sections that deal with the MutationObserver API itself.

Notice how I’m looping through the mutations argument, which is a MutationRecord object that has a number of different properties. In this case, I’m reading the type property and logging a message indicating that the browser has detected a mutation that qualifies. Also, notice how I’m passing the mList element (a reference to my HTML list) as the targeted element (i.e. the element on which I want to observe for changes).

Use the buttons to start and stop the MutationObserver. The log messages help clarify what’s happening. Comments in the code also provide some explanation.

Note a few important points here:

  • The callback function (which I’ve named mCallback, to illustrate that you can name it whatever you want) will fire each time a successful mutation is detected and after the observe() method is executed.
  • In my example, the only ‘type’ of mutation that qualifies is childList, so it makes sense to look for this one when looping through the MutationRecord. Looking for any other type in this instance would do nothing (the other types will be used in subsequent demos).
  • Using childList, I can add or remove a text node from the targeted element and this too would qualify. So it doesn’t have to be an element that’s added or removed.
  • In this example, only immediate child nodes will qualify. Later in the article, I’ll show you how this can apply to all child nodes, grandchildren, and so on.
Observing For Changes To An Element’s Attributes

Another common type of mutation that you might want to track is when an attribute on a specified element changes. In the next interactive demo, I’m going to observe for changes to attributes on a paragraph element.

let mPar = document.getElementById('myParagraph'), options = { attributes: true }, observer = new MutationObserver(mCallback); function mCallback (mutations) { for (let mutation of mutations) { if (mutation.type === 'attributes') { // Do something here... } } } observer.observe(mPar, options);

Again, I’ve abbreviated the code for clarity, but the important parts are:

  • The options object is using the attributes property, set to true to tell the MutationObserver that I want to look for changes to the targeted element’s attributes.
  • The mutation type I’m testing for in my loop is attributes, the only one that qualifies in this case.
  • I’m also using the attributeName property of the mutation object, which allows me to find out which attribute was changed.
  • When I trigger the observer, I’m passing in the paragraph element by reference, along with the options.

In this example, a button is used to toggle a class name on the targeted HTML element. The callback function in the mutation observer is triggered every time the class is added or removed.

Observing For Character Data Changes

Another change you might want to look for in your app is mutations to character data; that is, changes to a specific text node. This is done by setting the characterData property to true in the options object. Here’s the code:

let options = { characterData: true }, observer = new MutationObserver(mCallback); function mCallback(mutations) { for (let mutation of mutations) { if (mutation.type === 'characterData') { // Do something here... } } }

Notice again the type being looked for in the callback function is characterData.

In this example, I’m looking for changes to a specific text node, which I target via element.childNodes[0]. This is a little hacky but it will do for this example. The text is user-editable via the contenteditable attribute on a paragraph element.

Challenges When Observing For Character Data Changes

If you’ve fiddled around with contenteditable, then you might be aware that there are keyboard shortcuts that allow for rich text editing. For example, CTRL-B makes text bold, CTRL-I makes text italic, and so forth. This will break up the text node into multiple text nodes, so you’ll notice the MutationObserver will stop responding unless you edit the text that’s still considered part of the original node.

I should also point out that if you delete all the text, the MutationObserver will no longer trigger the callback. I’m assuming this happens because once the text node disappears, the target element is no longer in existence. To combat this, my demo stops observing when the text is removed, although things do get a little sticky when you use rich text shortcuts.

But don’t worry, later in this article, I’ll discuss a better way to use the characterData option without having to deal with as many of these quirks.

Observing For Changes To Specified Attributes

Earlier I showed you how to observe for changes to attributes on a specified element. In that case, although the demo triggers a class name change, I could have changed any attribute on the specified element. But what if I want to observe changes to one or more specific attributes while ignoring the others?

I can do that using the optional attributeFilter property in the option object. Here’s an example:

let options = { attributes: true, attributeFilter: ['hidden', 'contenteditable', 'data-par'] }, observer = new MutationObserver(mCallback); function mCallback (mutations) { for (let mutation of mutations) { if (mutation.type === 'attributes') { // Do something here... } } }

As shown above, the attributeFilter property accepts an array of specific attributes that I want to monitor. In this example, the MutationObserver will trigger the callback each time one or more of the hidden, contenteditable, or data-par attributes is modified.

Again I’m targeting a specific paragraph element. Notice the select drop down that chooses which attribute will be changed. The draggable attribute is the only one that won’t qualify since I didn’t specify that one in my options.

Notice in the code that I’m again using the attributeName property of the MutationRecord object to log which attribute was changed. And of course, as with the other demos, the MutationObserver won’t start monitoring for changes until the “start” button is clicked.

One other thing I should point out here is that I don’t need to set the attributes value to true in this case; it’s implied due to attributesFilter being set to true. That’s why my options object could look as follows, and it would work the same:

let options = { attributeFilter: ['hidden', 'contenteditable', 'data-par'] }

On the other hand, if I explicitly set attributes to false along with an attributeFilter array, it wouldn’t work because the false value would take precedence and the filter option would be ignored.

Observing For Changes To Nodes And Their Sub-Tree

So far when setting up each MutationObserver, I’ve only been dealing with the targeted element itself and, in the case of childList, the element’s immediate children. But there certainly could be a case where I might want to observe for changes to one of the following:

  • An element and all its child elements;
  • One or more attributes on an element and on its child elements;
  • All text nodes inside an element.

All of the above can be achieved using the subtree property of the options object.

childList With subtree

First, let’s look for changes to an element’s child nodes, even if they’re not immediate children. I can alter my options object to look like this:

options = { childList: true, subtree: true }

Everything else in the code is more or less the same as the previous childList example, along with some extra markup and buttons.

Here there are two lists, one nested inside the other. When the MutationObserver is started, the callback will trigger for changes to either list. But if I were to change the subtree property back to false (the default when it’s not present), the callback would not execute when the nested list is modified.

Attributes With subtree

Here’s another example, this time using subtree with attributes and attributeFilter. This allows me to observe for changes to attributes not only on the target element but also on the attributes of any child elements of the target element:

options = { attributes: true, attributeFilter: ['hidden', 'contenteditable', 'data-par'], subtree: true }

This is similar to the previous attributes demo, but this time I’ve set up two different select elements. The first one modifies attributes on the targeted paragraph element while the other one modifies attributes on a child element inside the paragraph.

Again, if you were to set the subtree option back to false (or remove it), the second toggle button would not trigger the MutationObserver callback. And, of course, I could omit attributeFilter altogether, and the MutationObserver would look for changes to any attributes in the subtree rather than the specified ones.

characterData With subtree

Remember in the earlier characterData demo, there were some problems with the targeted node disappearing and then the MutationObserver no longer working. While there are ways to get around that, it’s easier to target an element directly rather than a text node, then use the subtree property to specify that I want all the character data inside that element, no matter how deeply nested it is, to trigger the MutationObserver callback.

My options in this case would look like this:

options = { characterData: true, subtree: true }

After you start the observer, try using CTRL-B and CTRL-I to format the editable text. You’ll notice this works much more effectively than the previous characterData example. In this case, the broken up child nodes don’t affect the observer because we’re observing all nodes inside the targeted node, instead of a single text node.

Recording Old Values

Often when observing for changes to the DOM, you’ll want to take note of the old values and possibly store them or use them elsewhere. This can be done using a few different properties in the options object.

attributeOldValue

First, let’s try logging out the old attribute value after it’s changed. Here’s how my options will look along with my callback:

options = { attributes: true, attributeOldValue: true } function mCallback (mutations) { for (let mutation of mutations) { if (mutation.type === 'attributes') { // Do something here... } } }

Notice the use of the attributeName and oldValue properties of the MutationRecord object. Try the demo by entering different values in the text field. Notice how the log updates to reflect the previous value that was stored.

characterDataOldValue

Similarly, here’s how my options would look if I want to log old character data:

options = { characterData: true, subtree: true, characterDataOldValue: true }

Notice the log messages indicate the previous value. Things do get a little wonky when you add HTML via rich text commands to the mix. I’m not sure what the correct behavior is supposed to be in that case but it is more straightforward if the only thing inside the element is a single text node.

Intercepting Mutations Using takeRecords()

Another method of the MutationObserver object that I haven’t mentioned yet is takeRecords(). This method allows you to more or less intercept the mutations that are detected before they are processed by the callback function.

I can use this feature using a line like this:

let myRecords = observer.takeRecords();

This stores a list of the DOM changes in the specified variable. In my demo, I’m executing this command as soon as the button that modifies the DOM is clicked. Notice that the start and add/remove buttons don’t log anything. This is because, as mentioned, I’m intercepting the DOM changes before they are processed by the callback.

Notice, however, what I’m doing in the event listener that stops the observer:

btnStop.addEventListener('click', function () { observer.disconnect(); if (myRecords) { console.log(`${myRecords[0].target} was changed using the ${myRecords[0].type} option.`); } }, false);

As you can see, after stopping the observer using observer.disconnect(), I’m accessing the mutation record that was intercepted and I’m logging the target element as well as the type of mutation that was recorded. If I had been observing for multiple types of changes then the stored record would have more than one item in it, each with its own type.

When a mutation record is intercepted in this way by calling takeRecords(), the queue of mutations that would normally be sent to the callback function is emptied. So if for some reason you need to intercept these records before they’re processed, takeRecords() would come in handy.

Observing For Multiple Changes Using A Single Observer

Note that if I’m looking for mutations on two different nodes on the page, I can do so using the same observer. This means after I call the constructor, I can execute the observe() method for as many elements as I want.

Thus, after this line:

observer = new MutationObserver(mCallback);

I can then have multiple observe() calls with different elements as the first argument:

observer.observe(mList, options); observer.observe(mList2, options);

Start the observer, then try the add/remove buttons for both lists. The only catch here is that if you hit one of the “stop” buttons, the observer will stop observing for both lists, not just the one it’s targeting.

Moving A Node Tree That’s Being Observed

One last thing I’ll point out is that a MutationObserver will continue to observe for changes to a specified node even after that node has been removed from its parent element.

For example, try out the following demo:

This is another example that uses childList to monitor for changes to the child elements of a target element. Notice the button that disconnects the sub-list, which is the one being observed. Click the “Start…” button, then click the “Move…” button to move the nested list. Even after the list is removed from its parent, the MutationObserver continues to observe for the specified changes. Not a major surprise that this happens, but it’s something to keep in mind.

Conclusion

That covers just about all the primary features of the MutationObserver API. I hope this deep dive has been useful for you to get familiar with this standard. As mentioned, browser support is strong and you can read more about this API on MDN’s pages.

I’ve put all the demos for this article into a CodePen collection, should you want to have an easy place to mess around with the demos.

(dm, il)
Categories: Web Design

Privacy UX: Privacy-Aware Design Framework

Smashing Magazine - Thu, 04/25/2019 - 04:30
Privacy UX: Privacy-Aware Design Framework Privacy UX: Privacy-Aware Design Framework Vitaly Friedman 2019-04-25T13:30:16+02:00 2019-04-27T21:35:00+00:00

We’ve already explored approaches for better cookie consent prompts, permission requests, and notifications UX, but how do they fit into an overall design strategy as we make design decisions in our design tools?

In her article “What does GDPR mean for UX?”, Claire Barrett, a UX and UI designer at Mubaloo in Bristol, UK, has shared a very practical, actionable set of UX guidelines that the design agency has been following in respect to GDPR. While these guidelines specifically target GDPR, they are applicable to a much wider scope of user-friendly and privacy-aware interactions, and could therefore be applicable to any kind of project:

  1. Users must actively opt in to having their data collected and used.
  2. Users must give consent to every type of data-processing activity.
  3. Users should have the right to easily withdraw their consent at any time.
  4. Users should be able to check every organization and all third parties that will handle the data.
  5. Consent isn’t the same as agreeing to the terms and conditions, so they shouldn’t be bundled together; they are separate, and should have separate forms.
  6. While asking for consent at the right times is good, it’s even better to clearly explain why consent will benefit their experience.

One of the interesting things that Claire recommends in her article is to focus on “just-in-time” data collection (mentioned in part 3 of this series); that is, explain why data is required, and how it will and will not be used — but only when the app or website actually needs it. Obviously, this could be done by including an “info” icon next to the more personal bits of information collected, and showing the tooltip with the benefits and rationale behind data collection on request.

'Just-in-time' explanations with the info tooltip in forms. (Image source: Claire Barrett) (Large preview)

Many mobile applications require access to location, photos, and even the camera during installation, which isn’t something most customers would be happy to consent to. A more effective way of getting permission is to explain the need for data at the point of collection by using “just-in-time” prompts, so users can give consent only when they understand the purpose of it, very much like we’ve seen with permissions earlier in this series.

'Just-in-time' prompts, asking for access to location only when it’s actually required. (Image source: Claire Barrett) (Large preview)

The explanations should also inform customers how to withdraw consent where applicable, and provide a link to the privacy policy. These have been a matter of ongoing complaints for years, as lengthy privacy policies written in perfectly obscure legalese are almost impossible to comprehend without a dedicated review session. (In fact, a 2008 study showed it would take the average person roughly 244 hours per year to read all of the privacy policies for the sites they use, which translates to about 40 minutes per day.)

Rather than presenting the privacy policy as a wall of convoluted text, it could be chunked and grouped into clearly labelled sections and expandable text, optimized for scanning, locating, and understanding.

Separated policy actions, presented as accordions. Optimized for easy scanning and comprehension. (Image source: Claire Barrett) (Large preview)

Once consent is granted, customers should have full control over their data; that is, the ability to browse, change, and delete any of the data our applications hold. That means data settings in our mobile applications need to provide granular options to revoke consent, and opt out from marketing preferences, as well as the option to download and delete any data without wandering around the convoluted maze of help sections and ambiguous setting panels.

Customers should have full control over their data, so our 'data settings' menu should provide granular options to revoke consent, opt out from preferences, and download/or delete all data. (Image source: Claire Barrett) (Large preview)

The main issue with privacy-aware design decisions is that it’s difficult to assess the impact of data collection and all the interface challenges it poses on design and development. Being humble and subtle isn’t just a matter of respect, but also about reducing technical debt and avoiding legal battles down the road. For that, the following general guidelines could help as well.

Save As Little Data As Possible

If you choose to store credit card data, you have to be upfront about the security measures you take to store them confidentially. The less data you require and store, the less of an impact a potential breach would have.

Treat Personal Data Well

Not all data is created equal. When users provide personal information, distinguish between different strata of data, as private information is probably more sensitive than public information. Treat personal data well, and never publish it by default. For example, as a user completes their profile, provide an option to review all the input before publishing it. Be humble, and always ask for permission first; proactively protect users and don’t store sensitive data. That might help prevent uncomfortable situations down the line.

This goes not only for the procedure of storing and publishing user data on your servers, but also when it comes to password recovery or using customer data for any kind of affiliate partnerships. In fact, handing over a customer’s email to somebody else without explicit consent is a breach of trust and privacy, and often results in emails marked as spam because customers are suddenly confronted with an unfamiliar brand they don’t trust. In fact, the latter is almost like a defence mechanism against rapacious websites that continuously harvest emails in exchange for a free goodie, access to videos, and freemium offerings.

Explain Early What Kind Of User Data Third Parties Will Receive

When providing an option for social sign-in, be specific about what will happen to the user’s data and what permissions third parties will have. Usually a subtle note appears when social sign-in is prompted, but it’s a good idea to be explicit straightaway about how data will be treated, and specifically what will not happen to a user’s data.

It’s common to see user interactions coming to a halt once customers are forced into connecting their brand new accounts with already existing ones, or when they are encouraged to use their social profiles to make progress with the app. That’s never a straightforward step to take, and requires some explanation and assurance that revoking access is easy.

Prepare Customer Data For Export

It’s not trivial to get a complete picture of the collected data, especially if third parties are involved. Make sure that whenever personal data is collected, it’s structured in a way that’s optimized for export and deletion later on. Bonus points if it’s also digestible for the end user, so they can find the bits and pieces they need once they are interested in something very specific. That also means tracking what types of data are collected and where data flows, as we can use this structure later to provide granular control over data settings and privacy preferences in our UI.

You might have heard of a few friendly companies that make importing personal data remarkably seamless, yet exporting user data is painfully difficult, or close to impossible. Unsurprisingly, this practice isn’t perceived well by customers; and especially at times when they are thinking about deleting their account, such a pervasive lock-in will lead to customer support complaints, call centre calls, and angry outbursts in social channels. That’s not a delightful feature that will keep them loyal long-term.

While some companies can take public blaming because of their sheer size, for many small and mid-sized companies, reputation is the most precious asset they have, and so it’s wise not to gamble with it. You could even think of partnering with similar services and make user data seamlessly portable and transferrable to each of them, while expecting the same feature to be supported by partners as well.

Making It Difficult To Close Or Delete An Account Fails In The Long Term

Corporate behemoths have excelled in making it remarkably difficult for customers to close or delete their accounts. And this technique works when when moving away is painfully difficult — that’s the case for Amazon and Facebook.

However, if you are working on a relatively small website which strives for its loyal customers, you might not be able to pull it off successfully, at least not long-term. The overall impact is even more harmful if you make it difficult to cancel a recurring payment, as is often the case with subscriptions. (In fact, that’s why subscriptions are also difficult to sell — it’s not just the commitment to monthly payments, but rather the difficulty of cancelling the subscription at a later time without extra charge due to early cancellation.)

In fact, just as designers are getting better at hiding notorious profile settings for deleting an account, so too are customers at finding ways to navigate through the maze, often supported by the infinite wisdom of easily discoverable tutorials in blogs. If it’s not the case, customers resort to the tools they know work best: turning their back on the service that shows no respect towards their intentions — usually by marking emails as spam, blocking notifications, and using the service less. It doesn’t happen overnight; but slowly and gradually, and as interviews showed, these customers are guaranteed to not recommend the service to their friends or colleagues.

Surprisingly, it’s the other way around when it’s remarkably easy to close the account. Just like with notifications, there might be good reasons why the user has chosen to move on, and very often it has nothing to do with the quality of service at all. Trying to convince the customer to stay, with a detailed overview of all the wonderful benefits that you provide, might be hitting the wrong targets: in corporate settings especially, the decision will have been made already, so the person closing the account literally can’t do much about changing the direction.

With Smashing Membership, we try to explain what happens to the data in a clear way, and give an option to leaving Members to export their data without any hidden tricks. (Large preview)

For Smashing Membership, we’ve tried to keep the voice respectful and humble, while also showing a bit of our personality during offboarding. We explain what happens to the data and when it will be irrevocably deleted (seven days), provide an option to restore the plan, allow customers to export their orders and guarantee no sharing of data with third parties. It was surprising to see that a good number of people who canceled their Membership subscription, ended up recommending it to their friends and colleagues, because they felt there was some value in it for them even though they didn’t use it for themselves.

Postpone Importing Contacts Until The User Feels Comfortable With The Service

Of course, many of our applications aren’t particularly useful without integrating the user’s social circle, so it seems plausible to ask customers to invite their friends to not feel lonely or abandoned early on. However, before doing so, think of ways of encouraging customers to use the service for a while and postpone importing contacts until the point when users are more inclined to do so. By default, many customers would block an early request as they haven’t yet developed trust for the app.

Save User Data For A Limited Amount Of Time After Account Closure

Mistakes happen, and it holds true for accidental mis-taps as much as deleting all personal data after a remarkably bad day. So while we need to provide an option to download and delete data, also provide an option to restore an account within a short amount of time. That means that data will be saved after the account is deleted, but will be irrevocably removed after that grace period has passed. Usually, 7–14 days is more than enough.

However, you could also provide an option for users to request the immediate deletion of data via email request, or even with a click on a button. Should users be informed about the ultimate deletion of their files? Maybe. The final decision will probably depend on how sensitive the data is: the more sensitive it is, the more likely users will want to know the data is gone for good. The exception is anonymized data: most of the time, customers won’t care about it at all.

Provide User-Friendly Summaries Of Privacy Policy Changes

Nothing is set in stone, and so your privacy policy and default privacy settings might need to adjust because of new personalization features or a change of the tracking script. Whenever this happens, rather than highlighting the importance of privacy in lengthy passages of text, provide clear, user-friendly summaries of changes. You could structure the summary by highlighting how things used to be and how they are different now. Don’t forget to translate legalese into something more human-readable, explaining what the change actually means for the user.

Frankly, most users didn’t seem to care much about privacy policy changes. After the never-ending stream of policy update notifications in 2018, the default reaction is usually immediate consent. Once they’ve noticed anything related to privacy policy in the subject line or the email body, they immediately accept changes before even scrolling to the bottom of the email. However, the more personal the data stored is, the more time was spent reviewing the changes, which often were remarkably confusing and unclear.

Microcopy has always been at the very heart of Medium.com. A well-designed and well-structured privacy policy with clear summaries of privacy policy changes. (Image source: Email Design BeeFree) (Large preview) MailChimp, with a concise summary of changes of its privacy policy. (Large preview)

Note: The folks at Really Good Emails have collected some great examples of email design related to GDPR if you’re looking for more inspiration on how to share privacy policy changes with your users and subscribers.

Set Up A Communication Strategy In Case Of A Breach

Nobody wants havoc after user data is compromised. In such situations, it’s critical to have a clear and strong communication strategy. Have an explanation prepared in case some user data is compromised. Mandy Brown published a fantastic article, “Fire Drills: Communications Strategy in a Crisis”, on A List Apart, explaining how to set one up, and a few things to consider when doing it.

Privacy By Design

It might sound like visiting websites is a quite ordinary activity, and users should feel comfortable and familiar with features such as social sign-in, importing contacts, and cookie prompts. As we’ve seen in this series, there are many non-trivial privacy considerations, and more often than not, customers have concerns, doubts, and worries about sharing their personal data.

Of course, the scope of this series could stretch out much further, and we haven’t even looked into password recovery, in-app privacy settings design, floating chat windows and pop-ups, performance and accessibility considerations, or designing privacy experiences for the most vulnerable users — children, older people, and those with disadvantages. The critical point when making design decisions around privacy is always the same, though: we need to find a balance between strict business requirements and respectful design that helps users control their data and keep track of it, instead of harvesting all the information we can and locking customers into our service.

A good roadmap for finding that balance is adopting a privacy-first best-practice framework, known as Privacy by Design (PbD). Emerging in Canada back in the 1990s, it’s about anticipating, managing, and preventing privacy issues before a single line of code is written. With the EU’s data protection policy in place, privacy by design and data protection have become a default across all uses and applications. And that means many of its principles can be applied to ensure both GDPR-compliance and better privacy UX of your website or application.

In essence, the framework expects privacy to be a default setting, and a proactive (not reactive) measure that would be embedded into a design in its initial stage and throughout the life cycle of the product. It encourages offering users granular privacy options, respectful privacy defaults, detailed privacy information notices, user-friendly options, and clear notification of changes. As such, it works well with the guidelines we’ve outlined in this series.

I highly recommend reading one of Heather Burns’ articles, “How To Protect Your Users With The Privacy By Design Framework,” in which she provides a detailed guide to implementing the Privacy by Design framework in digital services.

Where to start, then? Big changes start with small steps. Include privacy in the initial research and ideation during the design stage, and decide on defaults, privacy settings, and sensitive touchpoints, from filling in a web form to onboarding and offboarding. Minimize the amount of collected data if possible, and track what data third parties might be collecting. If you can anonymize personal data, that’s a bonus, too.

Every time a user submits their personal information, keep track of how the questions are framed and how data is collected. Display notifications and permission requests just in time, when you are almost certain that the customer would accept. And in the end, inform users in digestible summaries about privacy policy changes, and make it easy to export and delete data, or close an account.

And most importantly: next time you are thinking of adding just a checkbox, or providing binary options, think about the beautifully fuzzy and non-binary world we live in. There are often more than two available options, so always provide a way out, no matter how obvious a choice might appear. Your customers will appreciate it.

(yk, il)
Categories: Web Design

Pages