Loading...

Follow Smashing Magazine | For Professional Web Design.. on Feedspot

Continue with Google
Continue with Facebook
or

Valid
Styling An Angular Application With Bootstrap Styling An Angular Application With Bootstrap Ahmed Bouchefra 2019-02-19T13:00:19+01:00 2019-02-19T14:04:44+00:00

In case you’ve already tried building a web application with Angular 7, it’s time to kick it up a notch. Let’s see how we can integrate Bootstrap CSS styles and JavaScript files with an Angular project generated using the Angular CLI, and how to use form controls and classes to create beautiful forms and how to style HTML tables using Table styles.

For the Angular part, we’ll be creating a simple client-side application for creating and listing contacts. Each contact has an ID, name, email, and description, and we’ll be using a simple data service that stores the contacts in a TypeScript array. You can use an advanced in-memory API instead. (Check out “A Complete Guide To Routing In Angular”.)

Note: You can get the source code of this tutorial from this GitHub repository and see the live example over here.

Requirements

Before we start creating the demo application, let’s see the requirements needed for this tutorial.

Basically, you will need the following:

  • Node.js and NPM installed (you can simply head on over to the official website and download the binaries for your system),
  • Familiarity with TypeScript,
  • Working experience of Angular,
  • Basic knowledge of CSS and HTML.

Web forms are such an important part of the web, but we design them poorly all the time. The brand-new “Form Design Patterns” book is our new practical guide for people who design, prototype and build all sorts of forms for digital services, products and websites. The eBook is free for Smashing Members.

Check the table of contents ↬
Installing Angular CLI

Let’s start by installing the latest version of Angular CLI. In your terminal, run the following command:

$ npm install -g @angular/cli

At the time writing, v7.0.3 of Angular CLI is installed. If you have the CLI already installed, you can make sure you have the latest version by using this command:

$ ng --version
Creating A Project

Once you have Angular CLI installed, let’s use it to generate an Angular 7 project by running the following command:

$ ng new angular-bootstrap-demo

The CLI will then ask you:

Would you like to add Angular routing?

Press Y. Next, it will ask you:

Which stylesheet format would you like to use?

Choose “CSS”.

Adding Bootstrap

After creating the project, you need to install Bootstrap 4 and integrate it with your Angular project.

First, navigate inside your project’s root folder:

$ cd angular-bootstrap-demo

Next, install Bootstrap 4 and jQuery from npm:

$ npm install --save bootstrap jquery

(In this case, bootstrap v4.2.1 and jquery v3.3.1 are installed.)

Finally, open the angular.json file and add the file paths of Bootstrap CSS and JS files as well as jQuery to the styles and scripts arrays under the build target:

"architect": {
  "build": {
    [...], 
    "styles": [
      "src/styles.css", 
        "node_modules/bootstrap/dist/css/bootstrap.min.css"
      ],
      "scripts": [
        "node_modules/jquery/dist/jquery.min.js",
        "node_modules/bootstrap/dist/js/bootstrap.min.js"
      ]
    },

Check out how to add Bootstrap to an Angular 6 project for options on how to integrate Bootstrap with Angular.

Adding A Data Service

After creating a project and adding Bootstrap 4, we’ll create an Angular service that will be used to provide some demo data to display in our application.

In your terminal, run the following command to generate a service:

$ ng generate service data

This will create two src/app/data.service.spec.ts and src/app/data.service.ts files.

Open src/app/data.service.ts and replace its contents with the following:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  contacts = [
    {id: 1, name: "Contact 001", description: "Contact 001 des", email: "c001@email.com"},
    {id: 2, name: "Contact 002", description: "Contact 002 des", email: "c002@email.com"},
    {id: 3, name: "Contact 003", description: "Contact 003 des", email: "c003@email.com"},
    {id: 4, name: "Contact 004", description: "Contact 004 des", email: "c004@email.com"}
  ];

  constructor() { }

  public getContacts():Array{
    return this.contacts;
  }
  public createContact(contact: {id, name, description, email}){
    this.contacts.push(contact);
  }
}

We add a contacts array with some demo contacts, a getContacts() method which returns the contacts and a createContact() which append a new contact to the contacts array.

Adding Components

After creating the data service, next we need to create some components for our application. In your terminal, run:

$ ng generate component home
$ ng generate component contact-create
$ ng generate component contact-list

Next, we’ll add these components to the routing module to enable navigation in our application. Open the src/app/app-routing.module.ts file and replace its contents with the following:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactListComponent } from './contact-list/contact-list.component';
import { ContactCreateComponent } from './contact-create/contact-create.component';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {path:  "", pathMatch:  "full",redirectTo:  "home"},
  {path: "home", component: HomeComponent},
  {path: "contact-create", component: ContactCreateComponent},
  {path: "contact-list", component: ContactListComponent}  
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

We use the redirectTo property of the router’s path to redirect users to the home page when they visit our application.

Adding Header And Footer Components

Next, let’s create the header and footer components:

$ ng generate component header
$ ng generate component footer

Open the src/app/header/header.component.html file and add the following code:

<nav >
  <a  href="#">Angular Bootstrap Demo</a>
  <button  type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse"
    aria-expanded="false" aria-label="Toggle navigation">
    <span ></span>
  </button>
  <div  id="navbarCollapse">
    <ul >

      <li >
        <a  routerLink="/home">Home</a>
      </li>
      <li >
        <a  routerLink="/contact-list">Contacts</a>
      </li>
      <li >
        <a  routerLink="/contact-create">Create</a>
      </li>

    </ul>
  </div>
</nav>

A navigation bar will be created with Bootstrap 4, and we’ll use the routerLink directive to link to different components.

Use the .navbar, .navbar-expand{-sm|-md|-lg|-xl} and .navbar-dark classes to create Bootstrap navigation bars. (For more information about nav bars, check out Bootstrap’s documentation on “Navbar”.

Next, open the src/app/header/header.component.css file and add:

.nav-item{
    padding:2px;
    margin-left: 7px;
}

Next, open the src/app/footer/footer.component.html file and add:

<footer>
  <p >© Copyright 2019. All rights reserved.</p>
</footer>

Open the src/app/footer/footer.component.css file and add:

footer {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    padding: 1rem;
    text-align: center;
}

Next, open the src/app/app.component.html file and replace its contents with the following:

<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>

We’re creating an application shell by using the header and footer components which means that they will be present on every page of our application. The only part that will be changed is what will be inserted in the router outlet (check out “The Application Shell” on the Angular website for more information).

Adding A Bootstrap Jumbotron

According to the Bootstrap docs:

“A Jumbotron is a lightweight, flexible component that can optionally extend the entire viewport to showcase key marketing messages on your site.”

Let’s add a Jumbotron component to our home page. Open the src/app/home/home.component.html file and add:

<div  >
  <h1>Angular Bootstrap Demo</h1>
  <p >
    This demo shows how to integrate Bootstrap 4 with Angular 7  
  </p>
  <a  href="" role="button">View tutorial</a>
</div>

The .jumbotron class is used to create a Bootstrap Jumbotron.

Adding A List Component: Using A Bootstrap Table

Now let’s create a component-to-list data from the data service and use a Bootstrap 4 table to display tabular data.

First, open the src/app/contact-list/contact-list.component.ts file and inject the data service then call the getContacts() method to get data when the component is initialized:

import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';

@Component({
  selector: 'app-contact-list',
  templateUrl: './contact-list.component.html',
  styleUrls: ['./contact-list.component.css']
})
export class ContactListComponent implements OnInit {

  contacts;
  selectedContact;
  
  constructor(public dataService: DataService) { }

  ngOnInit() {
    this.contacts = this.dataService.getContacts();    
  }
  public selectContact(contact){
    this.selectedContact = contact;
  }
}

We added two variables contactsand selectedContact which hold the set of contacts and the selected contact. And a selectContact() method which assigns the selected contact to the selectedContact variable.

Open the src/app/contact-list/contact-list.component.html file and add:

<div  >
  <table >
    <thead>
      <tr>
        <th>#</th>
        <th>Name</th>
        <th>Email</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let contact of contacts">
    
        <td>{{ contact.id }}</td>
        <td> {{ contact.name }}</td>
        <td> {{ contact.email }}</td>
        <td>
          <button  (click)="selectContact(contact)"> Show details</button>
        </td>
      </tr>
    </tbody>
  </table>
  <div  *ngIf="selectedContact">
      <div >
        # {{selectedContact.id}}
      </div>
      <div >
        <h4 >{{selectedContact.name}}</h4>
        <p >
          {{selectedContact.description}}
        </p>    
      </div>
    
    </div>
</div>

We simply loop through the contacts array and display each contact details and a button to select a contact. If the contact is selected, a Bootstrap 4 Card with more information will be displayed.

This is the definition of a Card from Bootstrap 4 docs:

“A card is a flexible and extensible content container. It includes options for headers and footers, a wide variety of content, contextual background colors, and powerful display options. If you’re familiar with Bootstrap 3, cards replace our old panels, wells, and thumbnails. Similar functionality to those components is available as modifier classes for cards.”

We use the .table and .table-hover classes to create Bootstrap-styled tables, the .card, .card-block, .card-title and .card-text classes to create cards. (For more information, check out Tables and Cards.)

Adding A Create Component: Using Bootstrap Form Controls And Classes

Let’s now add a form to our contact-create component. First, we need to import the FormsModule in our main application module. Open the src/app/app.module.ts file, import FormsModule from @angular/forms, and add it to the imports array:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';

/* ... */

@NgModule({
  declarations: [
  /* ... */
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Next, open the src/app/contact-create/contact-create.component.ts file and replace its contents with the following:

import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';

@Component({
  selector: 'app-contact-create',
  templateUrl: './contact-create.component.html',
  styleUrls: ['./contact-create.component.css']
})
export class ContactCreateComponent implements OnInit {

  contact : {id, name, description, email} = {id: null, name: "", description: "", email: ""};
  
  constructor(public dataService: DataService) { }

  ngOnInit() {
  }
  
  createContact(){
    console.log(this.contact);
    this.dataService.createContact(this.contact);
    this.contact = {id: null, name: "", description: "", email: ""};

  }
}

Next, open the src/app/contact-create/contact-create.component.html file and add the following code:

<div  >

  <div >

    <div >

      <div>
        <form>
          <div >
            <label for="id">ID</label>
            <input [(ngModel)]="contact.id" type="text" name="id"  id="id" aria-describedby="idHelp" placeholder="Enter ID">
            <small id="idHelp" >Enter your contact’s ID</small>

            <label for="name">Contact Name</label>
            <input [(ngModel)]="contact.name" type="text" name="name"  id="name" aria-describedby="nameHelp" placeholder="Enter your name">
            <small id="nameHelp" >Enter your contact’s name</small>

            <label for="email">Contact Email</label>
            <input [(ngModel)]="contact.email" type="text" name="email"  id="email" aria-describedby="emailHelp"
              placeholder="Enter your email">
            <small id="nameHelp" >Enter your contact’s email</small>

            <label for="description">Contact Description</label>
            <textarea [(ngModel)]="contact.description" name="description"  id="description" aria-describedby="descHelp">
                      </textarea>
            <small id="descHelp" >Enter your contact’s description</small>

          </div>
        </form>
        <button  (click)="createContact()">Create contact</button>
      </div>
    </div>
  </div>
</div>

We use the .form-group, .form-control classes to create a Bootstrap-styled form (check out “Forms” for more information).

We use the ngModel directive to bind the form fields to the components’ variable. For data binding to properly work, you need to give each form field a name.

Recommended reading: Managing Image Breakpoints With Angular by Tamas Piros

Running The Angular Application

At this step, let’s run the application and see if everything works as expected. Head over to your terminal, make sure you are in the root folder of your project then run the following command:

$ ng serve

A live-reload development server will be running from the http://localhost:4200 address. Open your web browser and navigate to that address. You should see the following interface:

(Large preview)

If you navigate to the Contacts page, you should see:

(Large preview)

If you navigate to the “Create contact” page, you should see:

(Large preview) Conclusion

In this tutorial, we’ve seen how to create a simple Angular application with a Bootstrap interface. You can find the complete source code on GitHub and see the live example here.

(dm, il)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
How A Screen Reader User Accesses The Web: A Smashing Video How A Screen Reader User Accesses The Web: A Smashing Video Bruce Lawson 2019-02-18T14:00:32+01:00 2019-02-18T14:03:52+00:00

Two weeks ago, I had the pleasure of hosting a Smashing TV webinar with Léonie Watson on how a screen reader user accesses the web. In the talk, Léonie showed some big-name sites, such as BBC, sites nominated by Members (including my own!), Smashing Magazine itself, and the popular third-party service Typeform, because so many of us (including us at Smashing) just assume that the popular services have been checked for accessibility. Throughout, Léonie explained how the sites’ HTML was helping (or hindering) her use of the sites.

We felt that the webinar was so valuable that we would open it up so that it’s free for everybody to use. Hopefully, it will serve as a resource for the whole web development community to understand how — and why — semantic markup matters.

How A Screen Reader User Surfs The Web - YouTube
What We Learned

I was pleased that my personal site’s use of HTML5 landmark regions (main, nav, header, footer, etc) helped Léonie form a mental model of the structure of the page. Although I’ve always been scrupulous to avoid link text like “click here” because WCAG guidelines require “The purpose of each link can be determined from the link text alone”, it hadn’t occurred to me before that because I have hundreds of weekly “Reading List” articles, it’s impossible for a screen reader user to tell one from the other when navigating by headings. Since the webinar, I’ve made each new reading list’s heading unique by including its number in the heading (“Reading List 222”).

We also learned that being technically accessible is good, but even better is to be usably accessible. The Smashing Team learned that before Léonie can read her own article on our site, there’s loads of preamble (author bio, email sign-up form) that she can’t easily skip over. We’re correcting this at the moment. There’s also an issue with our quick summaries; Léonie gets no indication when the summary has finished and the article proper has begun. Sighted users get a dividing line, but what can we do for non-sighted users?

After the webinar, Léonie suggested using a semantic HTML element and a sprinkling of ARIA:

<section aria-label="Summary">
</section>

This is announced as “Summary region start” and “Summary region end”, and can be skipped over if desired.

Thank You!

We’d like to thank Léonie for giving the webinar, and also our magnificant Smashing Magazine members whose support allows us to commission such content, pay our contributors fairly, and reduce advertising on the site.

Shameless plug: if you enjoyed this webinar, why not consider becoming a Member yourself? There are around three webinars a month free, Smashing eBooks and discounts galore. It costs around two cups of coffee a month, and you can cancel anytime.

(ra, il)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
Monthly Web Development Update 2/2019: Web Authentication And The Problem With UX Monthly Web Development Update 2/2019: Web Authentication And The Problem With UX Anselm Hannemann 2019-02-15T11:42:15+01:00 2019-02-15T12:04:43+00:00

The only constant in life is change, they say. And it’s true, even if we think nothing changes at all. Whether you notice change or not is only a question of how you perceive and how you observe things. In the tech industry, it’s easy to see how fast things evolve — read a summary article like this one, and you’ll suddenly become aware of how much has happened in just one month. Since I took up meditation again, I gained a new perspective, and it helps me to deliberately appreciate such change and find personal value and gratefulness even in things that didn’t seem particularly positive at first.

Like this week, for example. I was reminded of a fact we usually forget: how the Internet is structured. If you browse the web, most traffic is directed through Amazon at some point, so if you block their servers, — or Google’s or Apple’s, or all of them —, there’s not much left of the Internet. I have used a Pi-Hole DNS blocker in my network for three years now, but never really appreciated it, until I learned about its real value this week — the security and privacy it provides considering our dependency on tech giants. Isn’t it remarkable how a big part of my perceived online security relies on one piece of open-source software that the authors spent so much time and efforts on to provide it for free in the end?

News
  • Firefox 65 was released. The new version dispatches events on disabled HTML elements and comes with support for the referrerpolicy attribute on script elements, CSS environment variables (the env() function), Intl.RelativeTimeFormat for JavaScript, and WebP images.
  • Safari Tech Preview 74 brings abortable fetch, support for U2F HID Authenticators on macOS, and new Web Authentication API features.
  • With Chrome 72, Chrome introduced the User Activation API. The new version also disallows popups on pageunload.
  • The Chrome 72 update for Android shipped the long-awaited Trusted Web Activity feature, which means we can now distribute PWAs in the Google Play Store.
  • Safari 12.1 release notes are up (iOS 12.2, macOS 10.14.4). What’s new? Dark mode for the web, intelligent tracking prevention, the push notification prompt for Safari on macOS now requires a user gesture, motion and orientation settings on iOS to enable DeviceMotionEvent and DeviceOrientationEvent (this means it’s disabled by default now). Also new are the Intersection Observer API, Web Share API, and the <datalist> element.

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬
General
  • Max Böck shares his thoughts on why simplicity is the most valuable and important thing in projects.
  • Ian Littman on Twitter: “Moving 50% of servers to PHP 7 from PHP 5 would save $2.5 (edited to 2.0) billion in energy costs per year, and avoid billions of kilograms of CO2 emissions. Upgrade to PHP 7. Save the planet.”
  • How did you start to learn web development? I guess most of us relied on our browsers’ “view source” functionality and still do. But with JavaScript SPAs and more tooling that mangles, minifies and uglifies sources, we block this road of self-education for countless people out there. Let’s move to a more open approach and at least provide source maps on production servers so that people can access the actual sources via Developer Tools.
UI/UX To create stellar user experiences we need to see our users as humans. (Image credit) HTML & SVG
  • Sara Soueidan wrote a 101 course on SVG filters to help you understand what they are and how to use them to create your own visual effects.
Accessibility Privacy
  • Google is one of those companies which always find new, clever ways to expose user location data and sell it to third parties. Now Google wants to sell the exact location data of users to improve planning for urban planners, for example. Useful on the one hand, but still worrying for all users of Google products who might not be aware of what happens with their data.
  • I was wrong about Google and Facebook: there’s nothing wrong with them (so say we all),” says Aral Balkan. This piece explains how even the most honorable open-source projects struggle to make ethical choices and the fallacies of offering the best UX instead of promoting ethically correct solutions.
Web Performance
  • Jens Oliver Meiert shares his research on how the way you write HTML influences performance. Leaving out optional tags and quotes can make a difference, even though we’re able to use gzip or other techniques to optimize the document response in the browser.
JavaScript The Guide to Web Authentication is a handy introduction to securing sensitive information online. (Image credit) CSS Explore the solar system in Fabricius Seifert’s fantastic CSS experiment. (Image credit) Work & Life
  • Paul Greenberg is in search of lost screen time and explores what our lives could look like and how much more time we’d have if we escaped the screens. There are some revealing numbers in the article: The average American spends $14,000 per decade on smartphones. That’s $70,000 over the course of an average working life. More than 29% of Americans would rather give up sex for three months than give up their smartphone for a single week. Or you could plant 150 trees and buy half an acre of land for the amount of money you’d spent on your smartphone and apps per year.
  • Are you a patient person? Regardless of if you are or not, the experiment that Jason Fried wants to try is certainly a challenge: Try to pick the longest line at the supermarket, cancel Amazon Prime so that delivery takes longer, and take the chance to wait whenever possible. Embrace slowness.
  • In Praise of Extreme Moderation” shares an interesting perspective on why the culture of over-committing, over-working, and over-delivering in all areas of life isn’t healthy, and how we can shift towards a more moderate, calmer path.
Going Beyond…
  • It must be free.” On services we obviously don’t need but want to have. My essay about the importance of seeing value in the things we really need and why less is more.
  • How can we make our lives better? By maintaining essential relationships, avoiding technology, and embracing values instead of lifehacks, says Eric Barker.
  • Watch this talk of Greta Thunberg, a sixteen-year-old woman who tells all the well-known and influential people out there that she doesn’t care about money and why we need to view climate change from a perspective like hers — her life is in danger and no money will be able to save it. We need more people like her who aren’t led by corporate or financial rules.
(cm)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
Managing Image Breakpoints With Angular Managing Image Breakpoints With Angular Tamas Piros 2019-02-14T13:00:08+01:00 2019-02-14T12:05:03+00:00

As web developers, we are often required to create applications that are responsive as well as media-rich. Having such requirements in place means that we need to work with image breakpoints, as well as media queries since we want to provide the best experience to the end users. Adding to the list of requirements we may need to use a front-end framework such as Angular which is great for creating SPAs and other application types.

In this article, we’ll take a look at image breakpoints, their use-cases and throughout a hands-on example; we’ll implement them in an Angular application using Angular’s own BreakPoint Observer. While using this approach, we’ll also highlight why this popular framework helps us work with the aforementioned techniques in a seamless way.

Image Breakpoints And Responsive Images

In the era of responsive layouts (where we capture breakpoints based on the viewport size and based on the breakpoint we change the layout of the page), we also need to make sure that images can be displayed with the right dimensions — even after a layout change. Selecting the right image is quite challenging for modern responsive websites.

Let’s discuss two options that developers can utilize at the moment.

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬
srcset

srcset lets us define a list of images that the browser switches between based on the rendered <img> size and the density of the display.

Let’s take a look at an example:

<img
  srcset="tuscany-sm.jpg 600w, tuscany-md.jpg 900w, tuscany-lg.jpg 1440w" sizes="100vw"
  src="tuscany.jpg" />

In the above, we specify 3 images, with the w indicating the pixel width for the image. When using the above with srcset we also need to specify the sizes attribute (this is required because the spec mandates that if we use srcset and w we must have a sizes attribute as well). What is the purpose of this attribute? Browsers need to pick which resource to load out of a source set before they layout the page (before they know how big the image will end up being). We can think of sizes as a hint to the browser that, after layout, the image will occupy 100% of the width of the viewport (that’s what vw refers to). The browser knows the actual viewport width (as well as the DPR of the image) at load-time, so it can do the math to figure out what size resource it needs and pick one out of the source set.

The <picture> and <source media=""> element combinations let us switch out image resources in response to media queries, like the ones at layout breakpoints.

Let’s take a look at an example of this as well:

<picture>
    <source media="(min-width: 1440px)" srcset="../assets/images/tuscany-lg.jpg">
    <source media="(min-width: 900px)" srcset="../assets/images/tuscany-md.jpg">
    <source media="(min-width: 600px)" srcset="../assets/images/tuscany-sm.jpg">
    <img src="../assets/images/tuscany-sm.jpg" />
  </picture>

Change the code above locally with an image of your choice that has a small, medium and large size. Notice how, by resizing the browser, you get a different image.

The key takeaway from all the above is that if we want to swap out images at specific breakpoints, we can use the <picture> element to put media queries right into the markup.

Note: If you’re interested in exploring the differences between <picture> and srcset + sizes, I recommend reading Eric Portis’ great article: srcset and sizes.

So far we have discussed how to use image breakpoints along with media queries in a pure HTML environment. Wouldn’t it be a lot better to have a convenient, almost semi-automated way of generating image breakpoints as well as the corresponding images for the breakpoints even without having to specify media queries at all? Luckily for us Angular has a built-in mechanism to help us out and we’ll also take a look at generating the appropriate images dynamically based on certain conditions by using a third-party service.

Angular Layout Module

Angular comes with a Layout Module which lives in the CDK (Component Dev Kit) toolset. The Angular CDK contains well-tested tools to aid with component development. One part of the CDK is the Layout Module which contains a BreakpointObserver. This helper gives access to media-query breakpoints, meaning that components (and their contents) can adapt to changes when the browser size (screen size) is changed intuitively.

Recommended reading: Layout Module

Now that we have the theory out of the way let’s get down to business and create an application that will implement responsive image breakpoints. In this first iteration, we’ll create the shell of the application via the Angular CLI: ng new bpo and select the necessary options.

To use the BreakpointObserver we also need to install the Angular’s CDK Layout Module, which we can do via npm: npm i @angular/cdk.

After the installation, we will be able to add the necessary import statements to any component that we wish:

// app.component.ts
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';

Using the BreakpointObserver we can subscribe to changes in the viewport width and Angular gives us convenient accessors which mean that we don’t need to use media queries at all! Let’s go ahead and try this out:

// app.component.ts
constructor(public breakpointObserver: BreakpointObserver) { }

ngOnInit() {
    this.breakpointObserver.observe([
      Breakpoints.XSmall,
      Breakpoints.Small,
      Breakpoints.Medium,
      Breakpoints.Large,
      Breakpoints.XLarge
    ]).subscribe(result => {
      if (result.breakpoints[Breakpoints.XSmall]) {
       // handle XSmall breakpoint
      }
      if (result.breakpoints[Breakpoints.Small]) {
       // handle Small breakpoint
      }
      if (result.breakpoints[Breakpoints.Medium]) {
      // handle Medium breakpoint
      }
      if (result.breakpoints[Breakpoints.Large]) {
        // handle Large breakpoint
      }
      if (result.breakpoints[Breakpoints.XLarge]) {
        // handle XLarge breakpoint
      }
    });
  }

As mentioned before the accessor properties above reflect media queries in the following way:

  • Breakpoints.XSmall: max-width = 599.99px
  • Breakpoints.Small: min-width = 600px and max-width = 959.99px
  • Breakpoints.Medium: min-width = 960px and max-width = 1279.99px
  • Breakpoints.Large: min-width = 1280px and max-width = 1919.99px
  • Breakpoints.XLarge: min-width = 1920px

We now have everything in place which means, we can start to generate the appropriate images.

Responsive Breakpoints For Images

We have a few options to generate responsive images:

  1. Responsive Image Breakpoints Generator
    Using this tool, we can upload any image, setup various options, e.g. the number of images that we wish to generate. After running the tool, we’ll have a visual representation about the generated images, and we can download them as a zip file along with some generated code which uses the previously mentioned <picture> element.
  2. Another solution would be to create a build step for our project to generate breakpoints via some packages available in the NPM repository, such as gulp-responsive or grunt-responsive-images. Both of these depend on additional libraries that we are required to install for our operating system. (Please check the appropriate repositories for additional information.)
  3. Yet another solution would be to use a service such as Cloudinary to store the images and serve them in a size and format that we need only by modifying the URL for the requested resource. This will be our approach since this gives us the most flexibility.

Recommended reading: Automating Art Direction With The Responsive Image Breakpoints Generator by Eric Portis

I have uploaded the original image to my Cloudinary account which means that I can access that image via the following URL:

https://res.cloudinary.com/tamas-demo/image/upload/breakpoints-article/tuscany.jpg

This is the full-sized, raw, original and unchanged image that we’ll work with.

We can modify the URL of the image to generate a much smaller version. For example, if we want to have an image with a width of 600 pixels, we could update the Cloudinary URL* to be the following:

https://res.cloudinary.com/tamas-demo/image/upload/w_600/breakpoints-article/tuscany.jpg
 

* Note the w_600 added to the URL.

Hopefully, by this point, you see where all this is going. Based on the approach above, we can very quickly start to generate the right image for the right breakpoint.

Using Cloudinary means that we don’t need to create, store and manage multiple version of the same image — it is done for us by Cloudinary on-the-fly.

Let’s update our code:

<!-- app.component.html -->
<div>
  <h1>Current breakpoint: {{ breakpoint }}</h1>
  <img [src]="imagePath">
</div>
// app.component.ts
import { Component, OnInit } from '@angular/core';
// ...
export class AppComponent implements OnInit {
  imagePath;
  constructor(public breakpointObserver: BreakpointObserver) { }
  ngOnInit() {
    this.breakpointObserver.observe([ ...
  }
}

We can pick any number of breakpoints to observe from the list mentioned previously, and since we have an Observer we can subscribe to the changes and act on them:

this.breakpointObserver.observe([
  Breakpoints.XSmall,
  Breakpoints.Small,
  Breakpoints.Medium,
  Breakpoints.Large,
  Breakpoints.XLarge
]).subscribe(result => {
  if (result.breakpoints[Breakpoints.XSmall]) {
    // handle this case
  }
});

To handle the options for the different images in Cloudinary, we’ll utilize an approach that will be very easy to follow. For each case, we’ll create an options variable and update the final Cloudinary URL.

Add the following at the top of the component definition:

// app.component.ts
imagePath;
  breakpoint;
  cloudinaryOptions;
  baseURL = 'https://res.cloudinary.com/tamas-demo/image/upload/breakpoints-article/tuscany.jpg';

And add the following as well to the first if statement:

// app.component.ts
let url = this.baseURL.split('/');
let insertIndex = url.indexOf('upload');
const options = 'c_thumb,g_auto,f_auto,q_auto,w_400';
url.splice(insertIndex + 1, 0, options);
this.imagePath = url.join('/');
this.breakpoint = Breakpoints.XSmall;

The result is going to be an updated Cloudinary URL:

https://res.cloudinary.com/tamas-demo/image/upload/c_thumb,g_auto,f_auto,q_auto,w_400/breakpoints-article/tuscany.jpg

What are the options that we are setting here?

  • c_thumb (generates a thumbnail of the image);
  • g_auto (focuses on the most interesting part; we see the cathedral in the thumbnail);
  • f_auto (serves the most appropriate format for a given browser, i.e. WebP for Chrome);
  • q_auto (reduces the quality — and therefore the overall size — of the image without impacting the visuals);
  • w_400 (sets the width of the image to 400px).

For the sake of curiosity, let’s compare the original image size with this newly generated image: 2.28 MBs vs 29.08 KBs!

We now have a straightforward job: we need to create different options for different breakpoints. I created a sample application on StackBlitz so you can test it out immediately (you can also see a preview here).

Conclusion

The variety of desktop and mobile devices and the amount of media used in today’s web has reached an outstanding number. As web developers, we must be at the forefront of creating web applications that work on any device and doesn’t impact the visual experience.

There are a good number of methods that make sure the right image is loaded to the right device (or even when resizing a device). In this article, we reviewed an approach that utilizes a built-in Angular feature called BreakPoint Observer which gives us a powerful interface for dealing with responsive images. Furthermore, we also had a look at a service that allows us to serve, transform and manage images in the cloud. Having such compelling tools at our hands, we can still create immersive visual web experiences, without losing visitors.

(dm, il)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
An Introduction To WebBluetooth An Introduction To WebBluetooth Niels Leenheer 2019-02-13T13:00:51+01:00 2019-02-13T12:09:44+00:00

With Progressive Web Apps, the web has been ever more closely moving towards native apps. However, with the added benefits that are inherent to the web such as privacy and cross-platform compatibility.

The web has traditionally been fantastic about talking to servers on the network, and to servers on the Internet specifically. Now that the web is moving towards applications, we also need the same capabilities that native apps have.

The amount of new specifications and features that have been implemented in the last few years in browsers is staggering. We’ve got specifications for dealing with 3D such as WebGL and the upcoming WebGPU. We can stream and generate audio, watch videos and use the webcam as an input device. We can also run code at almost native speeds using WebAssembly. Moreover, despite initially being a network-only medium, the web has moved towards offline support with service workers.

That is great and all, but one area has been almost the exclusive domain for native apps: communicating with devices. That is a problem we’ve been trying to solve for a long time, and it is something that everybody has probably encountered at one point. The web is excellent for talking to servers, but not for talking to devices. Think about, for example, trying to set up a router in your network. Chances are you had to enter an IP address and use a web interface over a plain HTTP connection without any security whatsoever. That is just a poor experience and bad security. On top of that, how do you know what the right IP address is?

Our new book, in which Alla Kholmatova explores how to create effective and maintainable design systems to design great digital products. Meet Design Systems, with common traps, gotchas and the lessons Alla has learned over the years.

Table of Contents →

HTTP is also the first problem we run into when we try to create a Progressive Web App that tries to talk to a device. PWAs are HTTPS only, and local devices are always just HTTP. You need a certificate for HTTPS, and in order to get a certificate, you need a publicly available server with a domain name (I’m talking about devices on our local network that is out of reach).

So for many devices, you need native apps to set the devices up and use them because native apps are not bound to the limitations of the web platform and can offer a pleasant experience for its users. However, I do not want to download a 500 MB app to do that. Maybe the device you have is already a few years old, and the app was never updated to run on your new phone. Perhaps you want to use a desktop or laptop computer, and the manufacturer only built a mobile app. Also not an ideal experience.

WebBluetooth is a new specification that has been implemented in Chrome and Samsung Internet that allows us to communicate directly to Bluetooth Low Energy devices from the browser. Progressive Web Apps in combination with WebBluetooth offer the security and convenience of a web application with the power to directly talk to devices.

Bluetooth has a pretty bad name due to limited range, bad audio quality, and pairing problems. But, pretty much all those problems are a thing of the past. Bluetooth Low Energy is a modern specification that has little to do with the old Bluetooth specifications, apart from using the same frequency spectrum. More than 10 million devices ship with Bluetooth support every single day. That includes computers and phones, but also a variety of devices like heart rate and glucose monitors, IoT devices like light bulbs and toys like remote controllable cars and drones.

Recommended reading: Understanding API-Based Platforms: A Guide For Product Managers

The Boring Theoretical Part

Since Bluetooth itself is not a web technology, it uses some vocabulary that may seem unfamiliar to us. So let’s go over how Bluetooth works and some of the terminology.

Every Bluetooth device is either a ‘Central device’ or a ‘Peripheral’. Only central devices can initiate communication and can only talk to peripherals. An example of a central device would be a computer or a mobile phone.

A peripheral cannot initiate communication and can only talk to a central device. Furthermore, a peripheral can only talk to one central device at the same time. A peripheral cannot talk to another peripheral.

A central device can talk to multiple peripherals. (Large preview)

A central device can talk to multiple peripherals at the same time and could relay messages if it wanted to. So a heart rate monitor could not talk to your lightbulbs, however, you could write a program that runs on a central device that receives your heart rate and turns the lights red if the heart rate gets above a certain threshold.

When we talk about WebBluetooth, we are talking about a specific part of the Bluetooth specification called Generic Attribute Profile, which has the very obvious abbreviation GATT. (Apparently, GAP was already taken.)

In the context of GATT, we are no longer talking about central devices and peripherals, but clients and servers. Your light bulbs are servers. That may seem counter-intuitive, but it actually makes sense if you think about it. The light bulb offers a service, i.e. light. Just like when the browser connects to a server on the Internet, your phone or computer is a client that connects to the GATT server in the light bulb.

Each server offers one or more services. Some of those services are officially part of the standard, but you can also define your own. In the case of the heart rate monitor, there is an official service defined in the specification. In case of the light bulb, there is not, and pretty much every manufacturer tries to re-invent the wheel. Every service has one or more characteristics. Each characteristic has a value that can be read or written. For now, it would be best to think of it as an array of objects, with each object having properties that have values.

A simplified hierarchy of services and characteristics. (Large preview)

Unlike properties of objects, the services and characteristics are not identified by a string. Each service and characteristic has a unique UUID which can be 16 or 128 bits long. Officially, the 16 bit UUID is reserved for official standards, but pretty much nobody follows that rule. Finally, every value is an array of bytes. There are no fancy data types in Bluetooth.

A Closer Look At A Bluetooth Light Bulb

So let’s look at an actual Bluetooth device: a Mipow Playbulb Sphere. You can use an app like BLE Scanner, or nRF Connect to connect to the device and see all the services and characteristics. In this case, I am using the BLE Scanner app for iOS.

Looking at the GATT services and characteristics of the Playbulb Sphere - Vimeo

The first thing you see when you connect to the light bulb is a list of services. There are some standardized ones like the device information service and the battery service. But there are also some custom services. I am particularly interested in the service with the 16 bit UUID of 0xff0f. If you open this service, you can see a long list of characteristics. I have no idea what most of these characteristics do, as they are only identified by a UUID and because they are unfortunately a part of a custom service; they are not standardized, and the manufacturer did not provide any documentation.

The first characteristic with the UUID of 0xfffc seems particularly interesting. It has a value of four bytes. If we change the value of these bytes from 0x00000000 to 0x00ff0000, the light bulb turns red. Changing it to 0x0000ff00 turns the light bulb green, and 0x000000ff blue. These are RGB colors and correspond exactly to the hex colors we use in HTML and CSS.

What does that first byte do? Well, if we change the value to 0xff000000, the lightbulb turns white. The lightbulb contains four different LEDs, and by changing the value of each of the four bytes, we can create every single color we want.

The WebBluetooth API

It is fantastic that we can use a native app to change the color of a light bulb, but how do we do this from the browser? It turns out that with the knowledge about Bluetooth and GATT we just learned, this is relatively simple thanks to the WebBluetooth API. It only takes a couple of lines of JavaScript to change the color of a light bulb.

Let’s go over the WebBluetooth API.

Connecting To A Device

The first thing we need to do is to connect from the browser to the device. We call the function navigator.bluetooth.requestDevice() and provide the function with a configuration object. That object contains information about which device we want to use and which services should be available to our API.

In the following example, we are filtering on the name of the device, as we only want to see devices that contain the prefix PLAYBULB in the name. We are also specifying 0xff0f as a service we want to use. Since the requestDevice() function returns a promise, we can await the result.

let device = await navigator.bluetooth.requestDevice({
    filters: [ 
        { namePrefix: 'PLAYBULB' } 
    ],
    optionalServices: [ 0xff0f ]
});

When we call this function, a window pops up with the list of devices that conform to the filters we’ve specified. Now we have to select the device we want to connect to manually. That is an essential step for security and privacy and gives control to the user. The user decides whether the web app is allowed to connect, and of course, to which device it is allowed to connect. The web app cannot get a list of devices or connect without the user manually selecting a device.

The user has to manually connect by selecting a device. (Large preview)

After we get access to the device, we can connect to the GATT server by calling the connect() function on the gatt property of the device and await the result.

let server = await device.gatt.connect();

Once we have the server, we can call getPrimaryService() on the server with the UUID of the service we want to use as a parameter and await the result.

let service = await server.getPrimaryService(0xff0f);

Then call getCharacteristic() on the service with the UUID of the characteristic as a parameter and again await the result.

We now have our characteristics which we can use to write and read data:

let characteristic = await service.getCharacteristic(0xfffc);
Writing Data

To write data, we can call the function writeValue() on the characteristic with the value we want to write as an ArrayBuffer, which is a storage method for binary data. The reason we cannot use a regular array is that regular arrays can contain data of various types and can even have empty holes.

Since we cannot create or modify an ArrayBuffer directly, we are using a ‘typed array’ instead. Every element of a typed array is always the same type, and it does not have any holes. In our case, we are going to use a Uint8Array, which is unsigned so it cannot contain any negative numbers; an integer, so it cannot contain fractions; and it is 8 bits and can contain only values from 0 to 255. In other words: an array of bytes.

characteristic.writeValue(
    new Uint8Array([ 0, r, g, b  ])
);

We already know how this particular light bulb works. We have to provide four bytes, one for each LED. Each byte has a value between 0 and 255, and in this case, we only want to use the red, green and blue LEDs, so we leave the white LED off, by using the value 0.

Reading Data

To read the current color of the light bulb, we can use the readValue() function and await the result.

let value = await characteristic.readValue();
    
let r = value.getUint8(1); 
let g = value.getUint8(2);
let b = value.getUint8(3);

The value we get back is a DataView of an ArrayBuffer, and it offers a way to get the data out of the ArrayBuffer. In our case, we can use the getUint8() function with an index as a parameter to pull out the individual bytes from the array.

Getting Notified Of Changes

Finally, there is also a way to get notified when the value of a device changes. That isn’t really useful for a lightbulb, but for our heart rate monitor we have constantly changing values, and we don’t want to poll the current value manually every single second.

characteristic.addEventListener(
    'characteristicvaluechanged', e => {
        let r = e.target.value.getUint8(1); 
        let g = e.target.value.getUint8(2);
        let b = e.target.value.getUint8(3);
    }
);

characteristic.startNotifications();

To get a callback whenever a value changes, we have to call the addEventListener() function on the characteristic with the parameter characteristicvaluechanged and a callback function. Whenever the value changes, the callback function will be called with an event object as a parameter, and we can get the data from the value property of the target of the event. And, finally extract the individual bytes again from the DataView of the ArrayBuffer.

Because the bandwidth on the Bluetooth network is limited, we have to manually start this notification mechanism by calling startNotifications() on the characteristic. Otherwise, the network is going to be flooded by unnecessary data. Furthermore, because these devices typically use a battery, every single byte that we do not have to send will definitively improve the battery life of the device because the internal radio does not need to be turned on as often.

Conclusion

We’ve now gone over 90% of the WebBluetooth API. With just a few function calls and sending 4 bytes, you can create a web app that controls the colors of your light bulbs. If you add a few more lines, you can even control a toy car or fly a drone. With more and more Bluetooth devices making their way on to the market, the possibilities are endless.

WebBluetooth demos for Bluetooth.rocks - Vimeo
Further Resources
(dm, ra, il)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
Webhosting Compared: Testing The Uptime Of 32 Hosts In 2018 Webhosting Compared: Testing The Uptime Of 32 Hosts In 2018 John Stevens 2019-02-12T12:00:22+01:00 2019-02-12T13:04:59+00:00

(This is a sponsored article.) Many surveys have indicated that uptime is number one factor when choosing a web host and although most, if not all, web hosting services “promise” 99.99% uptime, it’s not the case with our case-study.

According to our latest research, the average uptime of 32 shared web hosting providers is 99.59%. That’s approximately 35 hours 32 minutes of downtime per year, per website.

And downtime even happens to online giants. A Dun & Bradstreet study found that nearly 60 percent of Fortune 500 companies experience a minimum of 1.6 hours of downtime every week.

As a rule of thumb, if you are experiencing an uptime of 99.90% or below, you should switch your web host. A good web host should provide you with an uptime of at least 99.94%.

To run this series of tests, we have signed up for all of the 32 web hosting providers as a regular user, using the cheapest plan available. After that, we set up a basic WordPress website and start monitoring them with Pingdom.com. (Tools like Pingdom or Appoptics let you regularly check if a website or app is available.) Our uptime check interval was set to 1 minute, which means all of the sites are scanned every minute to get the most accurate statistics.

Please note that many hosts don’t define uptime like that, so they will often refuse to pay out on the guarantee because they say it was “planned maintenance” etc.

Let’s take a closer look.

Web Hosting Provider Average Uptime ↓ Total Outages Total Downtime Per Year
1. MidPhase 99.991% 19 outages 45 minutes
2. Bluehost 99.991% 7 outages 52 minutes
3. DigitalOcean* 99.989% 11 outages 58 minutes
4. SiteGround* 99.988% 26 outages 73 minutes
5. Site5* 99.986% 16 outages 83 minutes
6. HostGator* 99.984% 19 outages 84 minutes
7. A Small Orange* 99.978% 52 outages 125 minutes
8. iPage 99.975% 72 outages 131 minutes
9. HostPapa 99.975% 39 outages 144 minutes
10. FastComet 99.973% 44 outages 146 minutes
11. LunarPages* 99.972% 20 outages 153 minutes
12. Hostinger* 99.971% 28 outages 154 minutes
13. WebHostingBuzz 99.969% 28 outages 163 minutes
14. GreenGeeks* 99.969% 11 outages 164 minutes
15. JustHost 99.968% 28 outages 165 minutes
16. GoDaddy 99.965% 47 outages 184 minutes
17. HostRocket 99.960% 31 outages 202 minutes
18. HostMonster 99.955% 40 outages 235 minutes
19. DreamHost* 99.953% 40 outages 239 minutes
20. Hosting24 99.951% 31 outages 264 minutes
21. WestHost* 99.948% 48 outages 271 minutes
22. WebHostingHub 99.948% 76 outages 278 minutes
23. inMotion Hosting 99.935% 90 outages 341 minutes
24. A2 Hosting 99.928% 64 outages 375 minute
25. HostMetro 99.852% 247 outages 763 minutes
26. MDD Hosting* 99.833% 76 outages 874 minutes
27. FatCow 99.829% 377 outages 899 minutes
28. NameCheap* 99.826% 453 outages 917 minutes
29. HostNine 99.723% 241 outages 1448 minutes
30. One.com 99.593% 419 outages 2132 minutes
31. WebHostingPad 97.588% 1,655 outages 9 days
32. Arvixe* 91.098% 20,051 outages 1 month

* These web hosting providers offer an uptime guarantee. If they’ve failed on promised uptime, you can ask for your money back.

If you’re into each month overviews with more detailed data, take a look at these pages below:

1. MidPhase.com No uptime guarantee:

Although MidPhase doesn’t mention any uptime guarantee on their website, they are the clear winner of this case-study hitting nearly 100% uptime in 2018.

2. Bluehost.com No uptime guarantee:

Similarly to MidPhase, Bluehost doesn’t offer any uptime guarantees either (just a network/server uptime agreement). However, their servers have been working very steadily, with the exception of one bigger outage (42 minutes).

3. DigitalOcean.com Uptime guarantee available:

DigitalOcean is a cheap cloud hosting that promises 99.99% uptime which they have greatly succeeded in our test. If you see uptime less than 99.99% using DigitalOcean, you can ask your money back.

4. SiteGround.com Uptime guarantee available:

SiteGround is a hosting provider with an excellent uptime score. They also offer uptime guarantee, providing you with one month of free service if uptime falls below 99.99% and an additional month if uptime falls below 99.90%.

5. Site5.com Uptime guarantee available:

99.98% is still decent uptime. What’s even better – Site5 comes with an uptime guarantee of 99.9% – anything below that is eligible for a % of credit back. They even offer 100% credit back when uptime falls below 99.5% on their fully managed VPS

6. HostGator.com Uptime guarantee available:

HostGator comes with a decent uptime. On top of that, they even provide an uptime guarantee of 99.9% and you get credit back when it falls below. Just beware that it only applies for the actual server downtime excluding server maintenance.

7. ASmallOrange.com Uptime guarantee available:

ASmallOrange offers an uptime guarantee of 99.9%. When it’s below that, you get a refund of one day of service per every 45-min downtime. Beware of the specific clauses. Just note the high number of outages we experienced in the test period.

8. iPage.com No uptime guarantee:

iPage does not offer an uptime guarantee. Luckily, considering their ranking in overall uptime, we’re pretty sure you wouldn’t need it anyway. One thing to be aware of is the high number of outages we experienced.

9. HostPapa.com No uptime guarantee:

Even though they mention under their Terms of Service using “reasonable efforts to maintain 99.9% of uptime”, HostPapa does not exactly provide an uptime guarantee.

10. FastComet.com No uptime guarantee:

Even though their live chat agent said that they guarantee a 99% uptime, there is no official uptime guarantee on FastComet’s Terms of Service or refund/credit policy if it falls below what’s promised. The total amount of outages is somewhat concerning.

11. LunarPages.com Uptime guarantee available:

For every 15min of downtime, LunarPages credits client’s account with an equal of a full day of service. That guarantee excludes scheduled maintenance.

12. Hostinger.com Uptime guarantee available:

Hostinger’s above average uptime is backed up by their uptime guarantee of 99.9%. As in all cases, scheduled maintenance is excluded.

13. WebHostingBuzz.com No uptime guarantee:

WHB does not provide any uptime guarantee per se. Based on our experience, you most likely wouldn’t need one anyway.

14. GreenGeeks.com Uptime guarantee available:

GreenGeeks offers a 99.9% uptime guarantee. However, it only applies to their own servers and is not applicable for client errors.

15. JustHost.com No uptime guarantee:

There’s no uptime guarantee on their website, whatsoever.

16. GoDaddy.com No uptime guarantee:

Despite their big name, huge client-base and decent service, GoDaddy does not provide any uptime guarantee. You should also beware of their rather high number (compared to other top hosts) of outages.

17. HostRocket.com Limited uptime guarantee:

HostRocket has an official 99.5% uptime guarantee. Like others, it only applies for their own direct services.

18. HostMonster.com 18. HostMonster.com No uptime guarantee:

Even though you can find a statement claiming to strive for their best, there is no official uptime guarantee.

19. DreamHost.com Uptime guarantee available:

Finally, there you have it – an official 100% uptime guarantee.” DreamHost guarantees 100% uptime. A failure to provide 100% uptime will result in customer compensation pursuant to guidelines established herein.”

20. Hosting24.com Limited uptime guarantee:

They offer a service uptime guarantee of 99.9%. It’s solely determined by them and you get 5% of your monthly hosting fee as credit back. It’s only usable to purchase further service of products from Hosting24.

21. WestHost.com
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
A/B Testing For Mobile-First Experiences A/B Testing For Mobile-First Experiences Suzanne Scacca 2019-02-11T12:00:26+01:00 2019-02-11T14:04:30+00:00

Your client’s website is done. They’re thrilled with it. You and your team are satisfied with the results. And visitor reception looks good so far.

While I recognize that a lot of research, experimentation, analysis and review went into the creation of the website, is that all there is to building a winning website these days? I’d argue that the mobile-first web has added a layer of complexity that few are fully prepared for.

Which is why your work shouldn’t stop when you hit the “Publish” button.

If you’re not yet performing post-launch A/B testing for your website clients, that’s a big mistake. Although we have a massive amount of case studies and other research at our disposal that confirm how to design for conversion on desktop, the mobile experience is still relatively new. At least the mobile-first experience as we know it today.

The following guide includes tips for A/B testing for mobile websites and will get you thinking about conversion rate optimization in other ways than just “Buy This Now”.

A Brief Introduction To A/B Testing For Mobile

Once a website has gone live, Google Analytics and any conversion rate optimization (CRO) tools you hook up to the site will start feeding you data about your users. If you choose to do something with these valuable insights, you have two options:

  1. Identify obstacles in the experience and implement changes to the site to resolve them.
  2. Identify a single obstacle in the experience, hypothesize why it occurred and create an alternative version of the site to test the resolution.

The first option seems cut-and-dried. The data tells you there is an issue; you create a solution for it. But like I mentioned already, the chances of succeeding when shooting from the hip like that only work with tried and true desktop design techniques. Even then, it can still be risky if your audience doesn’t align with the average online user’s behavior.

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬

The second option, on the other hand, allows designers to more safely implement changes to a mobile website. Until you have a clear picture of the mobile user’s journey through your website (which, realistically, could involve them jumping from a mobile device to desktop at some point), mobile A/B testing must be an essential part of your job as a web designer.

This is how A/B testing works:

  • Identify a part of the website that you believe needs a change. (This should be based on findings in your data or direct reports from users about problematic experiences.)
  • Hypothesize why there is friction and how you think it can be resolved.
  • Choose just one element to change.
  • Using A/B testing software, set up your test variables. You should pit the control (i.e. original version of the site) against a variation of the element.
  • Run the test against equal parts of mobile visitors.
  • Let the test run for two to four weeks.
  • Monitor results to make sure you’re generating sufficient data and take note of any anomalies along the way.
  • End the test and review the results.
  • If there’s a significant margin between the control and variation results, use your mobile A/B testing tool (like VWO) to implement the winner.

It’s okay if you find that the control is the winner. Take what you’ve learned and apply it to your A/B testing efforts going forward.

Recommended reading: How To Conduct Usability Studies With Participants With Disabilities

Tips For A/B Testing For Mobile-First Experiences

You’re here because you want to know how to increase conversions on the websites you build for clients. The tips below will force you to step outside typical conversion rate optimization planning and think outside the box as you test your theories.

Tip #1: Stop Thinking About Mobile vs. Desktop A/B Testing

With traditional A/B testing, you typically have verifiable proof of what works and what doesn’t. You tweak the wording on a call-to-action and more users click to buy the product. You change the color of the shirt in a photo and sales go up by 25%. You move the placement of the CTA to the bottom of the post and more readers subscribe.

In other words, you know that a change you made will directly impact the business’s bottom line.

However, when it comes to mobile, it’s not that easy.

Qubit published a report called The Influence of Mobile Discovery in 2018.

Qubit demonstrates growth in the mobile halo effect. (Source: Qubit) (Large preview)

The above image depicts the differences in the mobile halo effect from 2016 to 2017.

The mobile halo effect is a term Qubit uses to describe how the activity that takes place on mobile directly influences what happens on desktop. Qubit’s research of over 1.2 billion customer interactions with the web found:

Analyzing the cohort of users in our dataset who logged into their accounts on more than one type of device shows that mobile activity directly influences an average of 19% of computer revenue. In some sub-verticals, this influence is much higher, with Fashion seeing an average of 24%, while some retailers receive as many as 1 in 3 of their computer transactions as a result of mobile-browsing.

What’s more, this information only accounts for mobile users who logged into a website from multiple devices. Qubit suspects that people who simply discover a website through mobile also lead to this halo effect. This, in turn, drives up the value of desktop conversions because of how helpful mobile is during the discovery phase of the customer journey.

This is why you can’t just look at mobile-only results on a mobile-first A/B test.

Instead, conduct your tests in the following manner:

  • Run your test with mobile visitors.
  • Review the results from your A/B testing tool to see if you were able to remove the obstacle from the mobile experience.
  • Then, look at your Google Analytics results from the same time period. Even if mobile traffic continued to drop off at the same point, you may find that desktop traffic and engagement increased as a result.

In sum, don’t go into mobile A/B testing thinking that everything you do must result in a greater amount of sales, subscribers or members on mobile. Instead, focus on how to improve the experience as a whole so that it improves your overall conversion rate.

Tip #2: Start with the Header

Remember that there are four micro-moments (or motivations) that drive mobile users to a website:

  1. I want to know.
  2. I want to go.
  3. I want to do.
  4. I want to buy.

With such a clear purpose driving their journey to and hopefully through your mobile site, don’t force them to wait for what they’re asking for. In terms of design, this translates to shortening their pathway — either to conversion or to completing the mobile experience before moving to desktop.

When you begin mobile-first A/B testing, look at elements that provide an answer to the micro-moments that are most relevant to your website.

Is there a way to place them in the header of the website or within the first scroll or two of the home page? Or can you at least design a one-click shortcut in the navigation to take them to it?

Here are some ideas:

1. I want to know.

Websites with lots of content would do well to test whether or not rearranging the navigation and putting emphasis on relevant and timely categories helps with conversion.

BuzzFeed takes this theory a step further:

BuzzFeed doesn’t hide its mobile navigation. (Source: BuzzFeed) (Large preview)

In addition to customizing the navigation regularly, BuzzFeed has chosen to leave the main navigation out in the open on mobile, with a fun selection of emojis to draw attention to the timeliest of categories.

Another way to answer the “I want to know” search is by providing a point of contact in as streamlined a fashion as possible as SensesLab has done:

The SensesLab includes a recognizable “mailto” icon in the header. (Source: SensesLab) (Large preview)

The “Mail” icon in the top-right corner takes mobile visitors to the Contact page. However, this is no ordinary contact page. While an introduction to their point of contact and email address is given, it’s the contact form below that really shines:

The SensesLab provides a super mobile-friendly contact form at the shortcut. (Source: SensesLab) (Large preview)

The entire form fits within an entire screen-grab on my iPhone above. There’s no wasting of time by providing instructions on how to fill out the form or anything like that. Users just need to click on the highlighted fields to personalize their responses.

Even better:

The SensesLab uses user-friendly contact form fields. (Source: SensesLab) (Large preview)

SensesLab has anticipated their responses and provided pre-populated answers along with custom keyboards to shorten the amount of time anyone has to spend filling this out.

2. I want to go.

I think the solution to test for with this one is obvious. In other words:

Where in the header or above the fold do you place the reservation buttons?

Just don’t be afraid to think outside the box with this. For example, this is The Assemblage website:

The Assemblage includes a 'Book a Tour' icon on the mobile home page. (Source: The Assemblage) (Large preview)

The Assemblage is a coworking space located in New York City. While the mobile site could’ve easily prioritized conversions up top (i.e. “Get your membership now!”), it instead provides a shortcut that makes more sense.

With the focus on booking a tour, mobile visitors can easily claim a date and time. Then, worry about learning all about and seeing the workspace in person later.

The Assemblage prioritizes booking tours of the cowork space. (Source: The..
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 
How People Make Decisions How People Make Decisions Susan Weinschenk 2019-02-07T13:30:37+01:00 2019-02-07T13:05:45+00:00

(This article is sponsored by Adobe.) Kelly’s in charge of choosing IT cloud services at her company. She has signed the company up for a chatbot service, and has had the “Pro” level service (not the “Free” or “Standard”) for two years.

It’s time for the annual renewal. Will she renew? Will she decide to renew, but switch to the free service only? Is there anything about the email notice and/or webpage for the service that will either encourage her or discourage her from renewing?

The pricing plan that is presented to Kelly. (Large preview)

There is a lot of research on human decision-making. Here are some of my favorite insights from the research.

Most Decisions Are Not Made “Logically”

We like to think that we are logical and that when we are making a decision, we carefully weigh all of our alternatives. When it’s time to buy a new car, do we read all the specs and reviews, and choose the one that is the safest and most economical? When it’s time to renew the chatbot service, does Kelly do a study to see how much use she has made of the “Pro” services and evaluate whether she should stay with that level and pay that amount each month?

These would be the logical ways to make the decision, and although we sometimes make decisions rationally and logically, there are hundreds of decisions we make every day, and we don’t do a logical think through of every one. Even the big decisions where we think we are being logical, the research shows that most of our decisions — big or small — are made unconsciously and involve emotion.

Here are some facts about decisions that may surprise you.

Most Of Our Decisions Are Made Unconsciously

By looking at brain activity while making a decision, researchers could predict what choice people would make 7-10 seconds before they themselves were even aware of having made a decision. This means that even when people think they are making a conscious, logical, decision, chances are that they aren’t aware that they’ve already made a decision and that it was unconscious. We aren’t even aware of our own process.

Do you write your messaging and content to appeal to logical thinking?

If so, it’s possible and even probable that your logical, persuasive arguments to your target audience about why they should go with the premium service, or why they should purchase a particular product may be in vain.

Be suspicious of what people say.

Another problem is that if you are diligent in your design process and ask people what factors are important to them, you might not be getting a true answer.

For example, if someone interviewed Kelly and asked her why she chooses the “Pro” level each year, it is likely that she will come up with an answer that sounds very logical (i.e. about the service, how her company uses it and so on) when the real reason she stays with “Pro” rather than the “Free” plan may be emotional (“I don’t want to have things go wrong and if I pay money things won’t go wrong”) or just habit (“It’s what we always sign up for”). What people tell you is the reason for why they do what they do may not be the actual reason.

People need to feel in order to decide.

If you can’t feel emotions, then you can’t make decisions — thanks to our ventro-medial pre-frontal cortex (or ‘vmPFC’).

The vmPFC is part of the prefrontal cortex, i.e. the front of your brain. It is important in regulating fear. Other parts of your brain (in particular the amygdala) tell you when you should be afraid and what you should be afraid of. The amygdala is where “conditioned” fear responses are born and perpetuated. The vmPFC, in contrast, has an opposite role. It mitigates conditioned fear. It stops you from continuing to be afraid in certain situations. When the vmPFC is active then you are able to let go of conditioned fears. As a result, you are then able to make a decision.

You should just assume that all decisions involve emotions. Rather than just making logical arguments to persuade, you are more likely to persuade people to take an action if you understand how they are feeling about the decision and feed their feeling. For example, if Kelly is feeling apprehensive about making a wrong decision then your messaging should be more about making her feel secure and safe than it is about product features.

People buy when they feel confident of their decision.

There is actually a neuron that fires up in the brain that triggers people to take action when the brain decides it is confident of a decision. This is subjective. It’s not necessarily based on the amount of information you’ve collected — it’s a feeling of confidence.

If you want people to take an action then you need to make them feel confident. If you want Kelly to choose the “Pro” level again, then you need to give her messaging about the “Pro” version that makes her confident of her choice. For example, feed data back to her about how much she has used the service. This will make her feel confident that she is making the correct choice.

Don’t Confuse Unconscious With Irrational Or Bad

I take exception with writers who equate unconscious decision making with making poor or irrational decisions. For example, Dan Ariely in his book, “Predictably Irrational: The Hidden Forces That Shape Our Decisions” implies that unless we work hard to prevent it, many to most of our decisions are poor and irrational.

Most of our mental processing is unconscious, and most of our decision-making is unconscious, but that doesn’t mean it’s faulty, irrational, or bad. We are faced with an overwhelming amount of data (11,000,000 pieces of data come into the brain every second according to Dr. Timothy Wilson in his book “Strangers To Ourselves: Discovering The Adaptive Unconscious”) and our conscious minds can’t process all of that.

Our unconscious has evolved to process most of the data and to make decisions for us according to guidelines and rules of thumb that are in our best interest most of the time. This is the genesis of “trusting your gut”, and most of the time it works!

People do like to think that they are being logical and thorough, however, so you may want to offer logical reasons for why a certain decision should be made so that the person making the decision has a rational reason they can give themselves and others. Go ahead and give Kelly the rational reasons she should renew for the “Pro” level, but just understand that that reason is probably not the actual reason.

Recommended reading: Grabbing Visual Attention With The Visual Cortex

Only Give More Information If People Are Making A Goal-Based Decision

There are two different types of decisions that people make. Value-based decisions are made in the orbitofrontal cortex (OFC). So, during those times when you really are comparing the Honda to the Subaru when you are shopping for a car, then you are making a value-based goal decision. If Kelly was comparing the features of the different levels for the chatbot service then she would be making a value-based goal decision.

Habit-based decisions occur in the basal ganglia (deep in the brain). When you pull your usual cereal off the shelf at the grocery store and put it in your cart, that’s a habit-based decision. If Kelly presses the ‘Renew’ button for the Chatbot software then she is making a habit-based decision.

What’s interesting is that if the OFC is quiet then the habit part of the brain takes over. This means that people are either making a goal-directed decision or a habit decision, but not both at the same time.

Structure of the human brain and location of the basal ganglia (Large preview)

If you give someone a lot of information then they will switch from habit to goal-directed. So if you want someone to make a habit decision, don’t give them too much information to review. If you want them to make a goal-directed decision then do give them information to review.

If you want Kelly to renew for the “Pro” level then don’t give her lots of data. Let her make the habit-based decision to renew. If you are hoping that she will go up a level (not down) then you may want to give her data on her options as that will kick her from a habit decision to a goal-directed decision.

Too Many Choices Means People Won’t Choose

You may have heard the idea that people can only remember, or deal with 7 plus or minus 2 things at a time (5 to 9). This actually is not true. It was a theory first mentioned by Miller in 1956 at a talk he gave at the American Psychological Association meeting. But research since then shows that 7 +- 2 is a myth. The real number is 3-4 not 5-9. Refuting research includes:

And most recently, Sheena Iyengar (author of “The Art Of Choosing”), has conducted several studies that clearly show that if you give people too many choices then they end up not choosing anything at all.

People liked having more choices to choose from but they were more satisfied with their choice when there was less to choose from.

So, if you show someone too many choices (in this case of sales/CRM services) they might not choose any and instead abandon the page.

Showing too many options can only overwhelm your users. Choose less with your goals in mind. (Large preview)

Kelly was given five choices for the Chatbot service. Three to four would have been better.

So, is there anything you can do to encourage Kelly to re-subscribe and not change her level of membership?

In this case, the decision is probably a habit-based decision. The best thing to do, then, is to not do much at all. Don’t send her an email with information on all the membership levels. Instead, give her one or two reasons why continuing with her current subscription is the way to go and leave it at that. At a different time (not when she is deciding whether to renew), you can make a pitch for a higher premium level. But if you do that pitch while she is about to renew, you may jeopardize her habit-based renewal.

Recommended reading: Don’t Let Your Brain Deceive You: Avoiding Bias In Your UX Feedback

Takeaways
  • If someone is making a habit-based decision, do not give them a lot of information.
  • Provide people with a brief, but a logical reason for their decision so they can use that to tell themselves and others why they did what they did.
  • Limit the number of choices people have to make to one, two or three. If you provide too many choices then people likely won’t choose at all.

This article is part of the UX design series sponsored by Adobe. Adobe XD tool is made for a fast and fluid UX design process, as it lets you go from idea to prototype faster. Design, prototype and share — all in one app. You can check out more inspiring projects created with Adobe XD on Behance, and also sign up for the Adobe experience design newsletter to stay updated and informed on the latest trends and insights for UX/UI design.

(cm, ms, ra, il)
Read Full Article
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview