Archive for the ‘Others’ Category

Styling An Angular Application With Bootstrap

February 19th, 2019 No comments
Form Design Patterns — a practical guide for anyone who needs to design and code web forms

Styling An Angular Application With Bootstrap

Styling An Angular Application With Bootstrap

Ahmed Bouchefra


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.


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.

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": [
      "scripts": [

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';

  providedIn: 'root'
export class DataService {

  contacts = [
    {id: 1, name: "Contact 001", description: "Contact 001 des", email: ""},
    {id: 2, name: "Contact 002", description: "Contact 002 des", email: ""},
    {id: 3, name: "Contact 003", description: "Contact 003 des", email: ""},
    {id: 4, name: "Contact 004", description: "Contact 004 des", email: ""}

  constructor() { }

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

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}  

  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 class="navbar navbar-expand-md bg-dark navbar-dark fixed-top">
  <a class="navbar-brand" href="#">Angular Bootstrap Demo</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse"
    aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  <div class="collapse navbar-collapse" id="navbarCollapse">
    <ul class="navbar-nav mr-auto">

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


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:

    margin-left: 7px;

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

  <p  class="text-xs-center">© Copyright 2019. All rights reserved.</p>

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:


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 class="jumbotron" style="background-color: #fff; height: calc(95vh);">
  <h1>Angular Bootstrap Demo</h1>
  <p class="lead">
    This demo shows how to integrate Bootstrap 4 with Angular 7  
  <a class="btn btn-lg btn-primary" href="" role="button">View tutorial</a>

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';

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

  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 class="container" style="margin-top: 70px;">
  <table class="table table-hover">
      <tr *ngFor="let contact of contacts">
        <td>{{ }}</td>
        <td> {{ }}</td>
        <td> {{ }}</td>
          <button class="btn btn-primary" (click)="selectContact(contact)"> Show details</button>
  <div class="card text-center" *ngIf="selectedContact">
      <div class="card-header">
        # {{}}
      <div class="card-block">
        <h4 class="card-title">{{}}</h4>
        <p class="card-text">

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';

/* ... */

  declarations: [
  /* ... */
  imports: [
  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';

  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() {
    this.dataService.createContact(; = {id: null, name: "", description: "", email: ""};


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

<div class="container" style="margin-top: 70px;">

  <div class="row">

    <div class="col-sm-8 offset-sm-2">

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

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

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

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

        <button class="btn btn-primary" (click)="createContact()">Create contact</button>

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:

Angular Bootstrap demo: Home page

(Large preview)

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

Angular Bootstrap Demo: Contacts Page

(Large preview)

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

Angular Bootstrap Demo: Create contact page

(Large preview)


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.

Smashing Editorial(dm, il)
Categories: Others Tags:

How @supports Works

February 18th, 2019 No comments

CSS has a neat feature that allows us to test if the browser supports a particular property or property:value combination before applying a block of styles — like how a @media query matches when, say, the width of the browser window is narrower than some specified size and then the CSS within it takes effect. In the same spirit, the CSS inside this feature will take effect when the property:value pair being tested is supported in the current browser. That feature is called @supports and it looks like this:

@supports (display: grid) {
  .main {
    display: grid;

Why? Well, that’s a bit tricky. Personally, I find don’t need it all that regularly. CSS has natural fallback mechanisms such that if the browser doesn’t understand a property:value combination, then it will ignore it and use something declared before it if there is anything, thanks to the cascade. Sometimes that can be used to deal with fallbacks and the end result is a bit less verbose. I’m certainly not a it’s-gotta-be-the-same-in-every-browser kinda guy, but I’m also not a write-elaborate-fallbacks-to-get-close kinda guy either. I generally prefer a situation where a natural failure of a property:value doesn’t do anything drastic to destroy functionality.

That said, @supports certainly has use cases! And as I found out while putting this post together, plenty of people use it for plenty of interesting situations.

A classic use case

The example I used in the intro is a classic one that you’ll see used in lots of writing about this topic. Here it is a bit more fleshed out:

/* We're gonna write a fallback up here in a minute */

@supports (display: grid) {
  .photo-layout {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-gap: 2rem;

Nice grid! Repeating and auto-filling columns is a sweet feature of CSS grid. But, of course, there are browsers that don’t support grid, or don’t support all the specific features of it that I’m using above there.

For example, iOS shipped support for CSS grid in version 10.2, but iOS has had flexbox support since version 7. That’s a decent gap of people with older iOS devices that do support flexbox but not grid. I’m sure there are more example gaps like that, but you probably get the idea.

I was running on an older version of mobile safari and many many many many many sites were flat out broken that used grid

I’m waiting another year or so before messing about with it

— David Wells (@DavidWells) February 6, 2019

It may be acceptable to let the fallback for this be nothing, depending on the requirements. For example, vertically stacked block-level elements rather than a multi-column grid layout. That’s often fine with me. But let’s say it’s not fine, like a photo gallery or something that absolutely needs to have some basic grid-like structure. In that case, starting with flexbox as the default and using @supports to apply grid features where they’re supported may work better…

.photo-layout {
  display: flex;
  flex-wrap: wrap;
  > div {
    flex: 200px;
    margin: 1rem;

@supports (display: grid) {
  .photo-layout {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-gap: 2rem;
    > div {
      margin: 0;

The “fallback” is the code outside of the @supports block (the properties above the block in the example above), and the grid code is either inside or after. The @supports block doesn’t change any specificity, so we need the source order to help make sure the overrides work.

Notice I had to reset the margin on the divs inside the @supports block. That’s the kind of thing I find a bit annoying. There is just enough crossover between the two scenarios that it requires being super aware of how they impact each other.

Doesn’t that make you wish it could be entirely logically separated…

There is “not” logic in @supports blocks, but that doesn’t mean it should always be used

Jen Simmons put this example in an article called Using Feature Queries in CSS a few years ago:

/* Considered a BAD PRACTICE, at least if you're supporting IE 11 and iOS 8 and older */
@supports not (display: grid) {
   /* Isolated code for non-support of grid */
@supports (display: grid) {
   /* Isolated code for support of grid */

Notice the not operator in the first block. That’s checking for browsers that do not support grid in order to apply certain styles to those browsers. The reason this approach is considered bad practice is that the browser support for @supports itself has to be considered!. That’s what makes this so dang tricky.

It’s very appealing to write code in logically separated @supports blocks like that because then it’s starting from scratch each time and doesn’t need to be overriding previous values and dealing with those logical mind-benders. But let’s go back to the same iOS situation we considered before… @supports shipped in iOS in version 9 (right between when flexbox shipped in iOS 7 and grid shipped in iOS 10.2). That means any flexbox fallback code in a @supports block using the not operator to check for (display: grid) {} support wouldn’t work in either iOS 7 or 8, meaning the fallback now needs a fallback from working in browsers it otherwise would have. Phew!

The big reason to reach for @supports is to account for very different implementations of something depending on feature support where it becomes easier to reason and distinguish between those implementations if the blocks of code are separated.

We’ll probably get to a point where we can use mutually-exclusive blocks like that without worry. Speaking of which…

@supports is likely to be more useful over time.

Once @supports is supported in all browsers you need to support, then it’s good to start using it more aggressively and without having to factor in the complication of considering whether @supports itself is supported. Here’s the support grid on that:

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Opera Firefox IE Edge Safari
28 12.1 22 No 12 9

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
9.0-9.2 46 all 4.4 71 64

Basically, IE 11 and any iOS device stuck on iOS 8 are the pain points. If your requirements are already past those, then you’re good to use @supports more freely.

The irony is that there hasn’t been a ton of CSS features shipping that have big clear @supports use cases — but there are some! Apparently, it’s possible to test new fancy stuff like Houdini:

Using it on my wedding website to check for Houdini support ??

— Sam Richard (@Snugug) February 6, 2019

(I’m not sure entirely what you’d put in the @supports block to do that. Has anyone else done this?)

When @supports isn’t doing anything useful

I’ve seen a good amount of @supports uses in the wild where the end result is exactly as it would be without using it. For example…

@supports (transform: rotate(5deg) {
  .avatar {
    transform: rotate(5deg);

On some level, that makes perfect logical sense. If transforms are supported, use them. But it’s unnecessary if nothing different is happening in a non-support scenario. In this case, the transform can fail without the @supports block and the result is the same.

Here’s another example of that shaking out.

There are browser extensions for playing with @supports

There are two of them!

They are both centered around the idea that we can write @supports blocks in CSS and then toggle them on and off as if we’re looking at a rendering of the code in a browser that does or doesn’t support that feature.

Here’s a video of Keith’s tool applied to the scenario using grid with a flexbox fallback:

This is fun to play with and is very neat tech. But in this exact scenario, if I was able to pull off the layout identically with flexbox, then I’d probably just do that and save that little bit of technical debt.

Ire’s tool, which she wrote about in the article Creating The Feature Queries Manager DevTools Extension, has a slightly different approach in that it shows the feature queries that you actually wrote in your CSS and provides toggles to flip them on and off. I don’t think it works through iframes though, so I popped open Debug Mode to use it on CodePen.

More real world use cases for @supports

Here’s one from Erik Vorhes. He’s styling some custom checkboxes and radio buttons here, but wraps all of it in a @supports block. None of the styling gets applied unless the block passes the support check.

@supports (transform: rotate(1turn)) and (opacity: 0) {
  /* all the styling for Erik's custom checkboxes and radio buttons */

Here are several more I’ve come across:

  • Joe Wright and Tiago Nunes mentioned using it for position: sticky;. I’d love to see a demo here! As in, where you go for position: sticky;, but then have to do something different besides let it fail for a non-supporting browser.
  • Keith Grant and Matthias Ott mention using it for object-fit: contain;. Matthias has a demo where positioning trickery is used to make an image sort of fill a container, which is then made easier and better through that property when it’s available.
  • Ryan Filler mentions using it for mix-blend-mode. His example sets more opacity on an element, but if mix-blend-mode is supported, it uses a bit less and that property which can have the effect of seeing through an element on its own.
.thing {
  opacity: 0.5;
@supports (mix-blend-mode: multiply) {
  .thing {
    mix-blend-mode: multiply;
    opacity: 0.75;
  • Rik Schennink mentioned the backdrop-filter property. He says, “when it’s supported the opacity of the background color often needs some fine tuning.”
  • Nour Saud mentioned it can be used to detect Edge through a specific vendor-prefixed property: @supports (-ms-ime-align:auto) { }.
  • Amber Weinberg mentioned using it for clip-path because adjusting the sizing or padding of an element will accommodate when clipping is unavailable.
  • Ralph Holzmann mentioned using it to test for that “notch” stuff (environment variables).
  • Stacy Kvernmo mentioned using it for the variety of properties needed for drop capping characters. Jen Simmons mentions this use case in her article as well. There is an initial-letter CSS property that’s pretty fantastic for drop caps, but is used in conjunction with other properties that you may not want to apply at all if initial-letter isn’t supported (or if there’s a totally different fallback scenario).
  • Here’s a bonus one from Nick Colley that’s not @supports, but @media instead! The spirit is the same. It can prevent that “stuck” hover state on touch devices like this:

    @media (hover: hover) {
      a:hover {
        background: yellow;

    Logic in @supports


    @supports (initial-letter: 4) {


    @supports not (initial-letter: 4) {


    @supports (initial-letter: 4) and (transform: scale(2)) {


    @supports (initial-letter: 4) or (-webkit-initial-letter: 4) {


    @supports ((display: -webkit-flex) or
              (display: -moz-flex) or
              (display: flex)) and (-webkit-appearance: caret) {

    JavaScript Variant

    JavaScript has an API for this. To test if it exists…

    if (window.CSS && window.CSS.supports) {
      // Apparently old Opera had a weird implementation, so you could also do:
      // !!((window.CSS && window.CSS.supports) || window.supportsCSS || false)

    To use it, either pass the property to it in one param and the value in another:

    const supportsGrid = CSS.supports("display", "grid");

    …or give it all in one string mirroring the CSS syntax:

    const supportsGrid = CSS.supports("(display: grid)");

    Selector testing

    At the time of this writing, only Firefox supports this sort of testing (behind an experimental flag), but there is a way to test the support of selectors with @supports. MDN’s demo:

    @supports selector(A > B) {


    Of course, we’d love to see Pens of @supports use cases in the comments. So share ’em!

    The post How @supports Works appeared first on CSS-Tricks.

    Categories: Designing, Others Tags:

    February 18th, 2019 No comments is a pretty cool project from Alexandre Dieulot. Alexandre has been at this idea for half a decade now, as InstantClick is his and is essentially the same exact idea.

    The idea is that there is a significant delay between hovering over a link and clicking that link. Say it takes you 300ms of delay. That 300ms could have been spent preloading the next page. And if you do use that time preloading, that page loads that much faster.

    This new project makes use of newer tech to get it done. It’s hardly any code., the core of which is appending a to the document of the link you’re about to click/touch.

    The page encourages you to hotlink the script, which means possible cache-hits in case you’ve already visited a page using this. It’s not risky in the way other third-party JavaScript can be because the integrity attribute means that if you trust the code as it is now, it can’t ever change unless you change that attribute along with it. It also cleverly uses the type="module" to prevent it from loading anything in browsers that don’t support prefetching anyway.

    Still, you could self-host it if you wanted. I have no idea who’s ponying up the for the bandwidth here, so another risk is a hung script should it stop responding one day.

    You could argue that it doesn’t do the prefetching as absolutely responsibly as it could. Google’s similar quick link library (which we covered here) does two interesting things in which to attempt to be more responsible with prefetching: 1) wait for requestIdleCallback and 2) respects info from navigator.connection, like a user enabling data-saver mode.

    Direct Link to ArticlePermalink

    The post appeared first on CSS-Tricks.

    Categories: Designing, Others Tags:

    IE10-Compatible Grid Auto-Placement with Flexbox

    February 18th, 2019 No comments
    Five orange rectangles in two rows with three on the first row and two on the second row.

    If you work on web applications that support older browsers, and have lusted after CSS Grid from the sidelines like I have, I have some good news: I’ve discovered a clever CSS-only way to use grid auto-placement in IE10+!

    Now, it’s not actually CSS Grid, but without looking at the code itself, you wouldn’t be able to tell. The HTML structure looks like CSS Grid. It has a defined set of columns with an undefined amount of rows and it has gutters that support borders and shadows on the cells without hacks. But what’s actually happening behind the scenes is a combination of flexbox and margins.

    In this article, I’ll walk through the approach. Here’s a demo of what we’re looking at:

    See the Pen
    IE10-compatible CSS-Grid-like column layout
    by Brian Holt (@bholtbholt)
    on CodePen.

    Auto-flowing rows with flexbox wrap

    Flexbox-created auto-placement grid

    Getting the basic grid setup is very simple. If you’re at all familiar with flexbox, I’m certain you’ve already guessed flex-wrap: wrap is the trick here. And you’d be right.

    Let’s get the HTML markup in place before we write any CSS. We want it to resemble the same structure as if we were using auto-placement — a .grid container and an undefined number of .grid__cells.

    <div class="grid">
      <div class="grid__cell">...</div>

    We set three grid breakpoints. A single-column, two-column, and three-column layout for mobile-devices, small screens, and medium screens, respectively. I’m using the breakpoints used in Bootstrap for this article, though we’d want to define them at actual points where the layout breaks if we were working with real content.

    $screen-sm-min: 768px;
    $screen-sm-max: 991px;
    $screen-md-min: 992px;
    Five orange rectangles stacked on top of one another.
    Mobile-first grid collapses into a single column

    A mobile-first approach means our single-column layout is already complete since each .grid__cell is already a block. We set .grid to become a flexbox container after the first breakpoint, and wrap cells.

    @media (min-width: $screen-sm-min) {
      .grid {
        display: flex;
        flex-wrap: wrap;

    Our two- and three-column layouts need explicit widths and flex properties; otherwise they’ll cram onto a single line. While testing IE10, I experienced unexpected behavior with the flex-basis property, and found setting an explicit width with flex-basis: auto was more consistent. This didn’t seem to be a problem with IE11 though.

    .grid__cell {
      min-width: 0;
      flex: 1 1 auto;
    // Two-column grid
    @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
      $width: 50%;
      .grid__cell {
        width: $width;
    // Three-column grid
    @media (min-width: $screen-md-min) {
      $width: 33.33%;
      .grid__cell {
        width: $width;

    We don’t need to wrap .grid__cell in a media query since its flex properties won’t have the effect when the parent isn’t a flexbox container. We also define an upper-limit to the two-column media query so it doesn’t affect the three-column grid.

    And that’s it! We now have a responsive, fluid, wrapping flexbox grid. The easy part is done… well, as long as we only ever have items that are multiples of two and three. With flex: 1 1 auto, the last item will always take up any remaining space in the last row.

    Three rows of orange rectangles. The first two rows have two columns of boxes and the third row has one single box that spans both columns.
    Two-column grid on smaller screens
    Two rows of orange rectangles. The first row has three columns of rectangles and the second row has two rectnagles that span the full width.
    Three-column grid on large screens

    Aligning cells in the last row

    The elusive last row is why we’re here, right? By default, each cell will stretch to the end of the row in a flexbox layout, but grid leaves a blank spot. How do we do that in flexbox? With pseudo-elements!

    The trick is to add a pseudo-element to the .grid container and set it like a cell. We define the :after pseudo-element cell at each of our breakpoints with the same width as a real cell.

    @media (min-width: $screen-sm-min) {
      .grid {
        &:after {
          content: '';
          display: block;
          flex: 1 1 auto;
    @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
      $width: 50%;
      .grid:after {
        width: $width;
    @media (min-width: $screen-md-min) {
      $width: 33.33%;
      .grid:after {
        width: $width;

    This creates a fake cell that will push against our real cells and align our two-column grid when the cells are odd. Leaving its height undefined allows it to collapse to nothing when the cells are even.

    Three rows of orange rectangles. First two rows have two columns, each with a rectangle. Third row has a single rectangle and an empty column.
    Two-column grid with odd cells, snapping into place

    Our three-column grid is a bit more complex because we need to handle multiple states, like when there is one empty cell and when there are two empty cells.

    Three column grid of orange rectangles with two rows. The second row only has one rectangle and an empty column.
    Three-column grid with one empty cell

    Our one empty cell state is already handled because it isn’t really any different from one empty cell in two columns. The :after cell has its width set and completes the row. The story changes when there are two empty cells though because flex: 1 1 auto rears its head again: the last cell now stretches across 50% of the width when pushed against the pseudo-element.

    Three column grid of orange rectangles with two rows. The second row has one rectangle that spans half the grid width leaving an empty white space.
    Three-column grid with two empty cells

    Using CSS :nth-of-type selectors, we can target the first column in each row. Since our rows are multiples of three, we target them with 3n then count backwards by 2 to get the first element in each row.

    @media (min-width: $screen-md-min) {
      .grid__cell {
        &:nth-of-type(3n-2) {
          background-color: red;
    Three column grid of rectangles. The first column of rectangles is red indicating the rectangles that are selected with CSS. The other rectangles are orange.
    Targeting the first cell in each three-column row

    We’re broadly targeting all the cells in the first column, but we need to limit the selection to only the last row. Actually, we need to limit it to when it’s the last cell in the first column of the last row. Luckily, there’s a handy pseudo-selector for targeting the last item of its kind. We chain :last-of-type to create the logical statement.

    @media (min-width: $screen-md-min) {
      .grid__cell {
        &:nth-of-type(3n-2):last-of-type {
          background-color: red;

    Now that we have the last cell in the first column of the last row selected, we use a margin to push the :after cell to the last column and fill the middle cell.

    @media (min-width: $screen-md-min) {
      .grid__cell {
        &:nth-of-type(3n-2):last-of-type {
          margin-right: $width;

    Here’s our flexbox-defined-auto-placement-grid-imitator in full. Look at its beautifully lined up rows. I bet you can’t even tell it’s not CSS Grid!

    Three column grid with three rows of orange rectangles. The last row has a single rectangle in the first column and the other two columns are empty.
    Our complete three-column grid.

    Adding gutters with margins

    CSS Grid’s spec has a column and row gap to provide space between each cell. Creating gutters in flexbox is much more challenging. It looks like it’s coming to flexbox, but we’re not there yet…and IE will never be.

    In Daniel Tonon‘s guide on CSS Grid in IE, he used an inner-cell div with negative margins, borders, a bit of padding, and overflow: hidden. While maybe a bit hacky, the effect works, but it breaks our desire to maintain CSS Grid-like HTML structure. The approach I prefer might feel a bit crude, but I also found it the easiest to read and understand. Further, it continues using :nth-of-type pseudo-selectors which makes the overall approach feel consistent.

    We want gaps between the cells, but not around the outside. We also want our cells to sit flush with the container.

    A three-by-two grid of orange rectangles. A block arrow is pointing at a gap between the rectangles.
    Gaps between the cells, not on the outside.

    Our mobile or single-column grid only needs a bottom margin on the cells. We add that and override the very last cell with margin-bottom: 0 so the cell fits flush against the container. Normally I’d use initial, but there’s no support in IE.

    $col-gap: 16px;
    .grid__cell {
      margin-bottom: $col-gap;
      &:last-of-type {
        margin-bottom: 0;
    A single column of orange rectangles in five rows.
    Single-column grid with gaps between each row

    Our two- and three-column grids need margins on the right of the cells, no right margins in the last column, and no bottom margins on any of the last row’s cells. Because of the margins, we’ll also need to recalculate our widths since the cells will wrap if they don’t fit.

    In a two-column layout, getting the right (or second) column is fairly easy with :nth-of-type(2n) or :nth-of-type(even). I prefer an n-multiplier for consistency with our three-column grid and for calculating the last row.

    Our last row is a bit more tricky. When we have odd cells our mobile-first CSS takes care of removing the bottom margins since the cell is the :last-of-type and our :after cell doesn’t have margins applied.

    A two-by-three grid of orange rectangles. The last rectangle is a little taller than the others.
    Two-columns with even cells

    When we have even cells we need to target the second last cell, but only when it is in the first column position. If we didn’t qualify it, the second last cell will grow vertically with to match the height of the second last row. We can target it with :nth-of-type(2n-1):nth-last-of-type(2).

    @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
      $width: calc(50% - #{$col-gap});
      .grid__cell {
        margin-right: $col-gap;
        // Remove margin in last column
        &:nth-of-type(2n) {
          margin-right: 0;
        // For when the last row is complete
        // . .
        // * .
        &:nth-of-type(2n-1):nth-last-of-type(2) {
          margin-bottom: 0;
    The same two-by-three grid as before, but with the last rectangle at an even height with the rest.
    Two-columns with even cells that sit flush against the container

    Our three-column gutters take the same approach. We add margin-right to all of them, remove it from the third column, and remove bottom margins from the last row. Again our last cell is handled by our mobile-first approach, but now we need to cover when there are two cells in the last row and when when there are three cells. We can qualify our selectors with nth-of-type and nth-last-of-type.

    @media (min-width: $screen-md-min) {
      $width: calc(33% - #{$col-gap});
      .grid__cell {
        margin-right: $col-gap;
        // Remove margin in last column
        &:nth-of-type(3n) {
          margin-right: 0;
        // For when there two items in the last row
        // . . .
        // * .
        &:nth-of-type(3n-2):nth-last-of-type(2) {
          margin-bottom: 0;
        // For when the last row is complete
        // . . .
        // * * .
        &:nth-of-type(3n-2):nth-last-of-type(3) {
          margin-bottom: 0;
    A three-by-three grid of orange rectangles, with the last cell empty.
    Three-column grid with gutters and an empty cell

    We need to adjust the margin of last cell in the last row when it’s alone because of the columns. We use 33% plus a gutter on each side.

    @media (min-width: $screen-md-min) {
      $width: calc(33% - #{$col-gap});
      .grid__cell {
        // When there is only one item in the last rpw
        // Fill the margin so it's like the last item is
        // double the width
        // . . .
        // *->
        &:nth-of-type(3n-2):last-of-type {
          margin-right: calc(33% + #{$col-gap * 2});

    Now our gutters are installed and the grid is complete! Fill them borders, shadows, or whatever your heart desires.

    A three-by-two grid of orange rectangles with the last cell empty.
    Complete three-column grid with gutters using flexbox.

    Wrapping up

    Here’s the final result one more time:

    See the Pen
    IE10-compatible CSS-Grid-like column layout
    by Brian Holt (@bholtbholt)
    on CodePen.

    I believe this technique could also support IE9 with minor adjustments, like using inline-blocks instead of flexbox. We could also expand to a four-column grid by adding another breakpoint and using the same approach as the three-column grid. Feel free to use this approach and I hope it helps!

    The post IE10-Compatible Grid Auto-Placement with Flexbox appeared first on CSS-Tricks.

    Categories: Designing, Others Tags:

    How A Screen Reader User Accesses The Web: A Smashing Video

    February 18th, 2019 No comments
    Smashing Editorial

    How A Screen Reader User Accesses The Web: A Smashing Video

    How A Screen Reader User Accesses The Web: A Smashing Video

    Bruce Lawson


    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.

    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">

    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)
    Categories: Others Tags:

    What’s New for Designers, February 2019

    February 18th, 2019 No comments

    Get ready to create a new list of bookmarks! The new tools featured this month are perfect for saving; some of them you’ll want to come back to over and over, such as a security checklist, cool background maker and a season-specific typeface.

    If we’ve missed something that you think should have been on the list, let us know in the comments. And if you know of a new app or resource that should be featured next month, tweet it to @carriecousins to be considered!

    DiceBear Avatars

    DiceBear Avatars allows you to create placeholder avatars in cool block style. You can create characters or identicons using the free HTTP API.

    React Insta Stories

    React Insta Stories is a namesake component that allows you to create Instagram or Snapchat stories on the web. Install it with npm and use an array of image URLS. It takes care of duration and the loading indicator.


    Sheety lets you turn any Google sheet into an API. It’s free and you can use it to power websites, apps or whatever. Plus, anything you change in the originating spreadsheet, updates to the API in real-time.


    Minisearch is a tiny but powerful in-memory fulltext search engine for JavaScript. It is respectful of resources, and it can comfortably run both in Node and in the browser. The demo search (below) is fun. I was able to search my name as it pertained to all of the Billboard Hot 100 from 1965 to 2015.


    Lobe will let your web app learn through a visual interface. It can read handwriting, see emotion and hear music. Join the beta to find out what this deep learning app can do for your projects.

    Bubble Toggle

    Bubble Toggle is a fun pen by Chris Gannon that features a toggle button with a trendy bubble switch.


    Textblock is a JavaScript tool that helps you adjust leading and size to create more beautiful responsive typography. It works by calculating a setting based on minimum and maximum values for font size, line height, variable grades and container width.


    SocialSizes solves a common problem: Finding the right template and sizing for social media images. The tool includes templates for Sketch, Adobe XD and Photoshop for common social media channels: Facebook, Instagram, LinkedIn, Twitter, Snapchat, YouTube, Pinterest and Twitch. It’s one of those tools that just makes life that much easier.

    Awesome Podcast

    Awesome Podcast might help you find your new favorite show to listen to while working. The list is a compilation of podcasts for software engineers. (And it’s grouped in such a great way to you can find something to listen to about JavaScript or PHP or Ruby or web development or any number of other topics.)

    Palette App

    Palette App is designed to help you build smooth color schemes, where hues flow from one color to the next. The toggles and tools let you fine tune hue, saturation and gradients. You can bring in color palettes from other places and test them or create a new palette right in the app.

    Photo Creator

    Photo Creator is a tool that lets you create your own stock photos. (Seriously!) Mix and match models backgrounds and objects to get just the picture you need for projects. Export images (free and paid options) for use online and in print.

    Snippet Generator

    Snippet Generator lets you create code snippets and copy for quick use. The tool toggles between VSCode, Sublime Text and Atom. It is a tiny React app.

    SVRF Developers

    SVRF Developers lets users search face filters, 360 videos and 360 photos and is free to use on all types of apps from cameras, to messaging to chat or community. What’s cool about the tool is that it helps your users find more AR and VR web experiences.

    Can’t Unsee

    Can’t Unsee is a design skills game. Are you brave enough to pick the right iteration designs on the screen?


    JournalBook is a private – and offline – personal journal. While the tool is filled with prompts to help you get started, your notes and thoughts are stored on your device. It’s a cool concept if you want to practice a little journaling.

    Animated Mesh Lines

    Animated Mesh Lines is a cool set of five WebGL demos over on the Codrops Playground. The library helps you understand how to create customer geometry to create an interesting graphic style.

    Childhood Flat Icons

    Childhood Flat Icons is a fun set of elements that will make you feel like a kid again. The collection includes 100 icons that show the development of a child with representations plus plenty of toys and child-like elements. It comes in AI, SVG and PNG formats.

    Security Checklist

    Security Checklist is a must-have tool. It is an open source list with everything you need to know about keeping yourself and your identity safe on the internet. How many of these things are you already doing?


    BG-Painter is a fun tool to create animated (or still background images). Just start with one of the preset “paint” options and change colors to fit your project. And everything you create is free to use as you like thanks to creator Frank Hsu.

    Static Site Boilerplate

    Static Site Boilerplate is a starting point for building modern static websites. It includes all the tech you need, then add your code and deploy your website. It’s that easy (kind of).


    UXWing might have every icon you’ll ever need. It’s a massive collection of scalable icons for web design and front-end development. Just search for what you need and download.

    Startup Illustration Kit

    Startup Illustration Kit gives you the tools to tell your company story visually, even when you don’t have a lot of photos or elements to showcase your small business. Use it to create a full set of characters to tell your tale. The kit has 30 illustrations with their own characters.


    Lindas is a free-for-personal use font with a full set of upper- and lowercase letters and numerals. It has a more masculine script style that’s widely appropriate.

    Lorden Holen

    Lorden Holen is your simple (and lovely) font for Valentine’s Day. It’s light and connected with just the right feel for love. The glyphs have some great personality as well.

    Reno Mono

    Reno Mono is a monospaced font with a modern style. What’s especially nice about it is that it has more personality than many other similar options and feels more usable, thanks to a rather modern take on monospacing. Plus, this free font is readable at small sizes.

    US Blaak

    US Blaak is a fun slab-style font with a great black weight for display. Each letter in this premium serif style has sharp strokes and interesting angles.


    Venn is a beautiful typeface family with 25 styles and five widths and weights. The great variation in this premium family makes is great for almost any use, from body copy to display.

    Add Realistic Chalk and Sketch Lettering Effects with Sketch’it – only $5!


    Categories: Designing, Others Tags:

    How To Create a Perfect Brand Book For Your Product

    February 18th, 2019 No comments
    How To Create a Perfect Brand Book For Your Product

    To be deemed a competitive and successful brand, you have to develop a thorough brand book.

    The set of rules in a brand book present valuable ideas and pointers for the future, as well as define the entire direction of your brand. For a sustainable, long-term business model, a detailed brand book is essential.

    If your products are to succeed on the market, they have to be in sync with the brand book. There are a lot of different ways to create an amazing brand book, depending on the niche your business is in. However, some tips are universal than others. Follow them, and your product will have a meteoric rise.

    Make an effective introduction

    A brand introduction is much more than a window into your brand. It should be a detailed breakdown of your brand culture and what do you stand for. Begin with a story about how your brand came to be.

    Be sure to emphasize how far you come from the moment your brand came to be. When putting together a brand introduction, you have to offset the brand story with visions of the future.

    It’s quite simple when you observe it from afar. All the success from the past, combined with ideas for the future, adds up to an exciting present. Every brand book for a product should include a strong brand introduction.

    Emphasizing the ideals and goals of your brand is the best way to instruct your employees on the development of a new project. To summarize, an effective introduction consists of answers to three questions:

    • What problem does the brand solve?
    • How does this particular product solve that problem?
    • How effectively does the product tell the story of your brand?

    Choose logos and visual branding elements

    After a brand introduction, it’s time to focus on branding. Every brand book must contain instructions for your team, on how to incorporate branding into that project.

    Remember, the goal is not just to urge people into buying your new product. Instead, it’s to gauge their interest with one product and have them become loyal customers and brand ambassadors.

    Logos are especially important, as they are the most usable and most powerful visual branding tool at your disposal. Work with your team to choose the right logo. If you are going to create a new logo, make sure it doesn’t stand out from your past brand identity.

    In the case of a rebranding effort, you can use the brand book as an inspiration for a whole new identity. Include the logo in your website design plans, while also having the web design contract ready.

    A good logo should be visible, but not in the focus of your design. It should add to the packaging, but not sway attention from the product itself.

    Fuse words with images

    A perfect brand book is neither entirely textual or visual. If you only use images, your target audience will feel like there is a lack of information. A text-only brand book will make it extremely hard to read.

    The best way to prove the point is to have visual elements complement the textual part, and vice versa. Therefore, a large focus of the creation process should include a great copy.

    If you and your team are having trouble with putting your ideas into words, think about outsourcing the descriptions and explanations for each section. The best way to do it is to expert writers from a writing service that specializes in writing college papers, white papers, business writing etc. EssayWritingLand is a good example of an online writing service.

    When using a writing service, you can communicate with the writing team directly. Let them know about your goals, ideas and demands. With regular updates and briefs, you will know exactly how the brand book will look like.

    Involve your entire team

    According to a study by Salesforce, 86% of all employees have cited a lack of teamwork as the main cause of project failures. Brand books are no exception. By involving your entire team, the brand book will be more detailed than ever before.

    Different inputs will give the entire team different ideas. Brainstorming will lead to unison in design, writing and every other element.

    If only one or two people handle the creation of the brand book, they won’t be able to observe every section critically. Allocate responsibilities during the creation process. Not only will this make the process much faster, but the entire team will be able to weigh in and decide accordingly, in case of a dilemma or a problem.

    Define public relation policies clearly

    A well-put-together brand book is a representation of your brand, product and goals. Unfortunately, it cannot aid you in establishing interactive communication. To let the audience know about the right channels of communication, you need to devote an entire section to PR.

    In recent years, influencer marketing has become more important than ever. 60% of all PR executives say it’s a vital part of the future. Thus, it would be a good idea to include a detailed plan concerning collaboration with influencers.

    Insert the names and contact information of people responsible for communicating with clients, business partners, etc. Define social media policies in relation to activity rules, content that should be posted.

    If you want to take a really thorough approach, define the desired tone for posts, color combinations for images and more. The more things you mention, the clearer your brand identity and vision will be.

    Concluding thoughts

    With the right organization and attention towards details, a perfect brand book is a very achievable goal. It’s an effort that will pay dividends for the product launch, as well as the overall success of your brand.

    Categories: Others Tags:

    Is Your Web Design SEO Workflow Optimized?

    February 18th, 2019 No comments

    Search engine optimization projects can be very complex, from ?SEO audits? to content development. Having an optimized strategy on how to approach SEO for web designers not only ensures your design team has clear project direction but also increases client satisfaction. Is your SEO workflow optimized? Here are a few productivity tips to make sure your strategy is fully-optimized.

    Make SEO Project Management Visual

    This is a very important tip to improve productivity and optimize your SEO workflow. Unfortunately, this is where many SEO and marketing agencies fall short on projects. By having a visual representation of a project, you and your team can see the progression of projects and tasks, as well as what is still to do.

    This also helps keep tasks from falling through the cracks, especially since search engine optimization projects are so complex. There are plenty of ways you can approach this. One way is manually, but that can be time consuming. The other is using process documentation software that does the work for you.

    Process documentation is a roadmap for your organization—it helps you identify the current state of a process to know how you can improve it. Any task that is done more than once or completed by multiple people needs to be documented.

    Develop a Task Workflow for Maximum Productivity

    Simply outlining tasks, or sprints within the project backlog is great, but doesn’t necessarily enhance the overall productiveness of your SEO agency. To truly ensure workflow is optimized, you need to develop a workflow for tasks within the project workflow. It is kind of like setting small goals supported by a detailed plan to achieve on big goal down the road.
    There are four elements of a task workflow that is highly productive for SEO, or any other project management process. These include, task planning, daily check-ins, review and feedback sessions, and post task analysis to ?improve strategies?.

    1.Task Planning

    This is the strategizing stage of a task and answers the what and how questions. For example, let’s say one SEO task, or sprint within a client project is to create six location based landing pages to capitalize on local search results. Task planning would consist of the what is needed to accomplish these pages, like location specific keywords, addresses, phone numbers, and content, as well as how to implement these pages.

    It is important to keep task planning time efficient, since some tasks don’t need a lot of strategy to get started. In other words, don’t spend an hour strategizing the what and how when it comes to creating a single web page. Utilize your time efficiently.

    2. Daily Check-Ins

    This is a very important part of increasing project productivity. Essentially, daily check- ins are quick 15 to 20 minute meetings where project anagers, SEO managers, and team members gather to update one another on tasks and the overall pace of the project.

    For instance, if you were a project manager, you would huddle your team and find out what each team member has completed from their task list, what they are currently working on, and any issues that need to be resolved. Then you can jot down notes, move the needle on the visual project board, and address issues.

    Daily check-ins also give you a clear picture of the entire project in a very short amount of time. This helps ?keep team communication open?, and also allows you to update the client on progress and hiccups moving forward.

    3. Review and Feedback Sessions

    These sessions are imperative to ensure projects remain mission focused, based on the client business objectives defined by the project manager and SEO manager. By looking at all completed tasks, project managers can evaluate work done and examine it based on meeting client expectations.
    If something seems out of place, the project manager can connect with the team and make tweaks on those completed tasks to ensure they are perfect before being closed out. These review and feedback sessions are great for client updates too. You can show clients how the project is progressing and highlight the benefits of each task for the main business aim.

    4. Post Task Analysis

    Each SEO project is unique, even if you deal with a specific industry niche. This makes post task analysis vital to keeping your SEO workflow optimized on future projects. For example, you and your team may identify a task or sprint that could have been paired with another task for more efficient progress. These sessions generally happen bi- weekly or monthly.
    ? Main questions to address during the post task analysis include:
    ? What did we learn from the tasks?
    ? What issues did we identify?
    ? How did we solve the problems?
    ? What areas could we make better?
    After the meeting, the project manager and SEO manager can huddle and develop two potential new strategies that can be implemented next time around to increase productivity.

    Wrapping Up . . .

    Optimizing your web design SEO workflow is essential to growing your client list, as well as retaining existing clients. Using a strategic planning model like the one outlined above can make this happen. Search engine optimization is complex and depending on the size of the project, can be downright overwhelming. Is Your Web Design SEO Workflow Optimized?

    Read More at Is Your Web Design SEO Workflow Optimized?

    Categories: Designing, Others Tags:

    Popular Design News of the Week: February 11, 2019 – February 17, 2019

    February 17th, 2019 No comments

    Every week users submit a lot of interesting stuff on our sister site Webdesigner News, highlighting great content from around the web that can be of interest to web designers.

    The best way to keep track of all the great stories and news being posted is simply to check out the Webdesigner News site, however, in case you missed some here’s a quick and useful compilation of the most popular designer news that we curated from the past week.

    Note that this is only a very small selection of the links that were posted, so don’t miss out and subscribe to our newsletter and follow the site daily for all the news.

    Introducing Textblock

    HTML Slides Without Frameworks, Just CSS

    The Best of Slack & Trello in One App

    The Failed Netflix Homepage Redesign Experiment that Nobody even Noticed

    Design Without Color First

    Graphic Artist Peter Saville on Creating Burberry’s New Logo

    Next.js 8 Released

    Making Google Fonts Faster

    Pantone Color Bridge Plus and CMYK Cheat Sheets for Graphic Designers

    UI Goodies 2.0! A Redesign and More Resources for Designers!

    How White Space Killed an Enterprise App (and Why Data Density Matters)

    Pods – Tiny Telegram Groups for Designers

    Choosing the Right UI Animation Tool

    7 Pillars of UI Design: Keep these in Mind

    21 CSS “Hotspot” Examples

    Goodbye, Slack. Hello, Spectrum

    Form Design: Handling Optional Fields

    Designing Magical Interfaces

    Designing Futuristic Interfaces – Become a XR Designer in 5 Minutes

    I Failed as a Designer at a Startup

    The Maze Report – An Instant, Gorgeous UX Report for all your User Tests

    34 Great Free Fonts

    3-colors Gradients Generator

    The Ineffectiveness of Lonely Icons

    Pixar’s Rules of Storytelling Applied to Product Managers & UX Designers

    Want more? No problem! Keep track of top design news from around the web with Webdesigner News.

    Add Realistic Chalk and Sketch Lettering Effects with Sketch’it – only $5!


    Categories: Designing, Others Tags:

    The Cloud is Just Someone Else’s Computer

    February 17th, 2019 No comments

    When we started Discourse in 2013, our server requirements were high:

    • 1GB RAM
    • modern, fast dual core CPU
    • speedy solid state drive with 20G+

    I’m not talking about a cheapo shared cpanel server, either, I mean a dedicated virtual private server with those specifications.

    We were OK with that, because we were building in Ruby for the next decade of the Internet. I predicted early on that the cost of renting a VPS with those specs would drop to $5 per month, and courtesy of Digital Ocean that indeed happened in January 2018.

    The cloud got cheaper, and faster. Not really a surprise, since the price of hardware trends to zero over time. But it’s still the cloud, and that means it isn’t exactly cheap, because it is, after all, someone else’s computer that you pay for the privilege of renting.

    But wait … what if you could put your own computer “in the cloud”?

    Wouldn’t that be the best of both worlds? Reliable connectivity, plus a nice low monthly price for extremely fast hardware? If this sounds crazy, it shouldn’t – Mac users have been doing this for years now.


    I suppose it’s understandable that Mac users would be on the cutting edge here since Apple barely makes server hardware, whereas the PC world has always been the literal de-facto standard for server hardware.


    Given the prevalence and maturity of cloud providers these days, it’s even a little controversial these days to colocate servers, but we’ve also experimented with colocating mini-pcs in various hosting roles. I’m still a little curious why there isn’t more of a cottage industry for colocating mini PCs. Because … I think there should be.

    I originally wrote about the scooter computers we added to our Discourse infrastructure in 2016, plus my own colocation experiment that ran concurrently. Over the last three years of both experiments, I’ve concluded that these little boxes are plenty reliable, with one role specific caveat that I’ll explain in the comments. I remain an unabashed fan of mini-PC colocation. I like it so much I put together a new 2019 iteration:

    2017 — $670 2019 — $820
    2.7-3.5 Ghz, 2c / 4t
    2.2-4.1 Ghz, 6c / 12t

    This year’s iteration of the scooter computer offers 3× the cores, 2× the memory, and 3× faster drive. It is, as the kids say … an absolute unit. ?




    It also has a rather elegant dual-sided internal layout. There is a slot for an old-school 2.5″ drive, plus built in wi-fi, but you won’t see it in these pictures because I physically removed both.

    I vetted each box via my recommended burn in and stability testing and they all passed with flying colors, though I did have to RMA one set of bodgy RAM sticks in the process. The benchmarks tell the story, as compared to the average Digital Ocean droplet:

    Per-core performance
    sysbench cpu --cpu-max-prime=20000 run

    DO Droplet 2,988
    2017 Mini-PC 4,800
    2019 Mini-PC 5,671

    Multi-core performance
    sysbench cpu --cpu-max-prime=40000 --num-threads=8 run

    DO Droplet 2,200
    2017 Mini-PC 5,588
    2019 Mini-PC 14,604

    Disk performance
    dd bs=1M count=512 if=/dev/zero of=test conv=fdatasync hdparm -Tt /dev/sda

    DO Droplet 701 / 8818 / 471 MB/sec
    2017 Mini-PC 444 / 12564 / 505 MB/sec
    2019 Mini-PC 1200 / 17919 / 3115 MB/sec

    Discourse rebuild
    time ./launcher rebuild app

    DO Droplet 6:59
    2017 Mini-PC 3:41
    2019 Mini-PC 3:24

    Power consumption could be a concern, as the 2017 version had a much lower 15 watt TDP, compared to the 45 watts of this version. That 3× increase in core count ain’t free! So I tested that, too, with a combination of i7z, stress, and my handy dandy watt meter.


    (idle login) 800 Mhz 10w
    stress --cpu 1 4.1 GHz 30w
    stress --cpu 2 4.1 GHz 42w
    stress --cpu 3 4.0 GHz 53w
    stress --cpu 4 3.9 GHz 65w
    stress --cpu 5 3.7 GHz 65w
    stress --cpu 6 3.5 GHz 65w
    stress --cpu 12 3.3 Ghz 65w

    I’d expect around 10-15 watts doing typical low-load stuff that isn’t super CPU intensive. Note that running current-ish versions of mprime jacks power consumption up to 75w ? and the overall clock scales down to 3.1 Ghz … let me tell you, I’ve learned to be very, very afraid of AVX2 extensions.

    (If you’re worried about noise, don’t be. This active cooling solution is clearly overkill for a 65w load, because it barely spun up at all even under full core load. It was extremely quiet.)

    So we’re happy that this machine is a slammin’ deal for $820, it’s super fast, and plenty reliable. But how about colocation costs? My colocation provider is EndOffice out of Boston, and they offer very competitive rates, at $29/month for colocating a Mini-PC.

    I personally colocate three Mini-PCs for redundancy and just-in-case; there are discounts for colocating more than one. Here they are racked up and in action. Of course I labelled the front and rear before shipping because that’s how I roll.


    Let’s break this down and see what the actual costs of colocating a Mini-PC are versus the cloud. Let’s assume a useful life of say, three years? Given the plateauing of CPU speeds, I think five years is more realistic, but let’s use the more conservative number to be safe.

    • $880 mini-pc 32GB RAM, 6 CPUs, 500GB SSD
    • $120 taxes / shipping / misc
    • $29 × 12 × 3 = $1,044

    That’s $2,044 for three years of hosting. How can we do on Digital Ocean? Per their current pricing page:

    • 32GB RAM, 8 vCPUs, 640GB SSD
    • $160/month
    • $160 × 12 × 3 = $5,760

    This isn’t quite apples to apples, as we are getting an extra 140GB of disk and 2 bonus CPUs, but let’s assume the CPUs can be partially consumed by multi-tenancy compared to our dedicated, isolated CPUs. Still, you pay almost three times as much for a cloud server. ?

    I’m not saying this is for everyone. If you just need to spin up a quick server or two for testing and experimentation, there’s absolutely no way you need to go to the trouble and up-front cost of building and then racking colocated mini-pcs. There’s no denying that spinning servers up in the cloud offers unparalleled flexibility and redundancy. But if you do have need for dedicated computing resources over a period of years, then building your own small personal cloud, with machines you actually own, is not only one third the cost but also … kinda cool?


    If you’d also like to embark upon this project, you can get the same Partaker B19 box I did for $490 from Amazon, or $460 direct from China via AliExpress. Add memory and drive to taste, build it up, then check out who I can enthusiastically recommend for colocation, or the colocation provider of your choice.

    Let’s do our part to keep the internet fun and weird!

    Categories: Others, Programming Tags: