Smashing magazine

S'abonner à flux Smashing magazine
Recent content in Articles on Smashing Magazine — For Web Designers And Developers
Mis à jour : il y a 10 min 58 sec

Best Practices With React Hooks

mer, 04/15/2020 - 13:00
Best Practices With React Hooks Best Practices With React Hooks Adeneye David Abiodun 2020-04-15T11:00:00+00:00 2020-04-15T12:34:31+00:00

React Hooks are a new addition in React 16.8 that let you use state and other React features without writing a class component. In other words, Hooks are functions that let you “hook into” React state and lifecycle features from function components. (They do not work inside class components.)

React provides a few built-in Hooks like useState. You can also create your own Hooks to reuse stateful behavior between different components. The example below shows a counter whose state is managed using the useState() hook. Each time you click on the button, we make use of setCount() to update the value of count by 1.

See the Pen [React Hook example with Counter](https://codepen.io/smashingmag/pen/QWbXMyM) by Adeneye Abiodun David.

See the Pen React Hook example with Counter by Adeneye Abiodun David.

This example renders a counter with a value of 0. When you click the button, it increments the value by 1. The initial value of the component is defined using useState.

const [count, setCount] = useState(0)

As you can see, we set that to be 0. Then we use the onClick() method to call setCount when we want to increment the value.

<button onClick={() => setCount(count + 1)}> Click me </button>

Before the release of React Hooks, this example would have used more lines of code, as we’d have had to make use of a class component.

Rules Of React Hooks

Before we dive deep into the best practices, we need to understand the rules of React Hooks which are also some of the fundamental concepts of the practices presented in this article.

React Hooks are JavaScript functions, but you need to follow two rules when using them.

  • Call Hooks at the top level,
  • Only call Hooks from React components.

Note: These two rules were introduced in React Hooks, as opposed to being part of JavaScript itself.

Let’s look at these rules in more detail.

Call Hooks At The Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

Let’s make a Form component which will have two states:

  • accountName
  • accountDetail

These states will have default values, we’ll make use of the useEffect hook to persist the state to either the local storage of our browser or to the title of our document.

Now, this component will be maybe to successfully manage its state if it remains the same between multiple calls of useState and useEffect.

function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }

If the order of our Hooks changes (which can be possible when they are called in loops or conditionals), React will have a hard time figuring out how to preserve the state of our component.

// ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...

That’s the order React follows to call our hooks. Since the order remains the same, it will be able to preserve the state of our component. But what happens if we put a Hook call inside a condition?

// 🔴 We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }

The accountName !== '' condition is true on the first render, so we run this Hook. However, on the next render the user might clear the form, making the condition false. Now that we skip this Hook during rendering, the order of the Hook calls becomes different:

useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // 🔴 This Hook was skipped! useState('Active') // 🔴 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 🔴 3 (but was 4). Fail to replace the effect

React wouldn’t know what to return for the second useState Hook call. React expected that the second Hook call in this component corresponds to the persistForm effect, just like during the previous render — but it doesn’t anymore. From that point on, every next Hook call after the one we skipped would also shift by one — leading to bugs.

This is why Hooks must be called on the top level of our components. If we want to run an effect conditionally, we can put that condition inside our Hook.

Note: Check out the React Hook docs to read more on this topic.

Only Call Hooks From React Components

Don’t call Hooks from regular JavaScript functions. Instead, you can call Hooks from React function components. Let’s take look at the difference between JavaScript function and React component below:

JavaScript Function import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;

Here we import the useState hook from the React package, and then declared our function. But this is invalid as it is not a React component.

React Function import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );

Even though the body of both looks similar, the latter becomes a component when we import React into the file. This is what makes it possible for us to use things like JSX and React hooks inside.

If you happened to import your preferred hook without import React which makes it a regular function, you will not be able to make use of the hook you import as the hook is accessible only in React component.

  • ✅ Call Hooks from custom Hooks

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks. For example, useUserName below a custom Hook that calls the useState and useEffect hooks. It fetches data from an API, loops through the data, and calls setIsPresent() if the specific username it received is present in the API data.

export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }

We can then go on to reuse the functionality of this hook in other places where we need such in our application. In such places, except when needed, we don’t have to call useState or useEffect anymore.

By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code.

ESLint Plugin

ESLint plugin called eslint-plugin-react-hooks enforces the rules above. This comes in handy in enforcing the rules when working on a project. I suggest you make use of this plugin when working on your project, especially when working with others. You can add this plugin to your project if you’d like to try it:

// Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }

This plugin is included by default in Create React App. So you don’t need to add it if you bootstrap your React applications using Create-React-App.

Thinking In Hooks

Let’s take a brief look at class components and functional components (with Hooks), before diving into the few Hooks best practices.

The simplest way to define a component in React is to write a JavaScript function that returns a React element:

function Welcome(props) { return <h1>Hello, {props.name}</h1>; }

The Welcome component accepts props which is an object that contains data and returns a React element. We can then import and render this component in another component.

The class component uses a programming methodology called Encapsulation which basically means that everything relevant to the class component will live within it. Life-cycle methods (constructors, componentDidMount(), render, and so on) give components a predictable structure.

Encapsulation is one of the fundamentals of OOP (Object-Oriented Programming). It refers to the bundling of data within the methods that operate on that data, and is used to hide the values or state of a structured data object inside a class — preventing unauthorized parties’ direct access to them.

With Hooks, the composition of a component changes from being a combination of life-cycle Hooks — to functionalities with some render at the end.

Function Component

The example below shows how custom Hooks can be used in a functional component (without showcasing what the body is). However, what it does or can do is not limited. It could be instantiating state variables, consuming contexts, subscribing the component to various side effects — or all of the above if you’re using a custom hook!

function { useHook{...}; useHook{...}; useHook{...}; return ( ... ); } Class Component

A class component requires you to extend from React.Component and create a render function which returns a React element. This requires more code but will also give you some benefits.

class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }

There are some benefits you get by using functional components in React:

  1. It will get easier to separate container and presentational components because you need to think more about your component’s state if you don’t have access to setState() in your component.
  2. Functional components are much easier to read and test because they are plain JavaScript functions without state or lifecycle-hooks.
  3. You end up with less code.
  4. The React team mentioned that there may be a performance boost for functional components in future React versions.

This leads to the first best practice when using React Hooks.

Hooks Best Practices 1. Simplify Your Hooks

Keeping React Hooks simple will give you the power to effectively control and manipulate what goes on in a component throughout its lifetime. Avoid writing custom Hooks as much as possible; you can inline a useState() or useEffect() instead of creating your own hook.

If you find yourself making use of a bunch of custom Hooks that are related in functionality, you can create a custom hook that acts as a wrapper for these. Let’s take a look at two different functional components with hooks below.

Functional Component v1 function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); } Functional Component v2 function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

v2 is a better version because it keeps the hook simple and all other useHooks are inline accordingly. This allows us to create functionality that can be reused across different components and also gives us more power to control and manipulate our components effectively. Instead of adopting v1 in which our components are littered with Hooks, you should make use of v2 which will make debugging easy and your code cleaner.

2. Organize And Structure Your Hooks

One of the advantages of React Hooks is the ability to write less code that is easy to read. In some cases, the amount of useEffect() and useState() can still be confusing. When you keep your component organized it will help in readability and keep the flow of your components consistent and predictable. If your custom Hooks are too complicated, you can always break them down to sub-custom Hooks. Extract the logic of your component to custom Hooks to make your code readable.

3. Use React Hooks Snippets

React Hooks Snippets is a Visual Studio Code extension to make React Hooks easier and faster. Currently, five hooks are supported:

  • useState()
  • useEffect()
  • useContext()
  • useCallback()
  • useMemo()

Other snippets have also been added. I have tried working with these Hooks and it has been one of the best practices I’ve personally used while working with them.

There are two ways you can add React Hooks snippets to your project:

  1. Command
    Launch the VS Code Quick open (Ctrl+P), paste ext install ALDuncanson.react-hooks-snippets and press Enter.
  2. Extension Marketplace
    Launch ‘VS Code Extension Marketplace’ (Ctrl+Shift+X) and search for ‘React Hook Snippets’. Then, look for the ‘Alduncanson’ icon.

I recommend the first snippet. Read more about the snippets here or check for the lastest Hooks snippets here.

4. Put Hooks Rules Into Consideration

Endeavor to always put the two rules of Hooks we learned earlier into consideration while working with React Hooks.

  • Only call your Hooks at the top level. Don’t call Hooks inside loops, conditions or nested functions.
  • Always call Hooks from React function components or from custom Hooks, don’t call Hooks from regular JavaScript functions.

The ESlint plugin called eslint-plugin-react-hooks enforces these two rules, you can add this plugin to your project if you’d like it as we explain above in rules of hooks section.

Best practices have not been fully resolved because Hooks are still relatively new. So adoption should be taken with precaution one would take in adopting in any early technology. With that in mind, Hooks are the way for the future of React.

Conclusion

I hope you enjoyed this tutorial. We’ve learned the two most important rules of React Hooks and how to effectively think in hooks. We looked at functional components (with Hooks) and some best practices in writing hooks the right and effective way. As brief as the rules are, it’s important to make them your guiding compass when writing rules. If you are prone to forget it, you can make use of the ESLint plugin to enforce it.

I hope you will take all of the lessons learned here in your next React project. Good luck!

Resources Smashing Editorial (ks, ra, yk, il)
Catégories: Programmation

How To Create A Particle Trail Animation In JavaScript

mar, 04/14/2020 - 13:00
How To Create A Particle Trail Animation In JavaScript How To Create A Particle Trail Animation In JavaScript Anna Prenzel 2020-04-14T11:00:00+00:00 2020-04-14T13:09:25+00:00

Have you ever thought about distracting visitors of your website with a fancy, glittering particle animation for a few moments, while some data is loaded in the background? Fortunately, it’s not necessary to go very deep into graphics programming with 3D libraries like three.js. All you need instead is some basic knowledge of CSS and JavaScript and a lightweight animation library such as anime.js. In the end, we should have the following result:

A spiral shaped particle trail animation Download And Integration Of Anime.js

You can download the anime.js library from the official GitHub site. Download the file anime.js or anime.min.js from the lib/ folder.

In my example, the HTML part looks like this:

<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Anime.js Particles</title> <!--or use anime.min.js--> <script src="anime.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <div class="anime-container"> </div> <script src="script.js"></script> </body> </html>

The CSS file styles.css defines the background color for the page and for the individual particles. The position settings are necessary so that we can later position the particles freely on the page using the CSS properties left and top.

body { background-color: hsl(30, 3%, 14%); } .anime-container { position: relative; } .anime-container .dot{ position: absolute; /*draw particles as circles:*/ border-radius: 50%; background-color: hsl(60, 100%, 80%); }

The content of the file script.js is covered in the following section.

Generating The Particles

As the name suggests, a particle animation consists of many small particles moving in space while following a certain pattern. All particles are generated simultaneously before the animation starts.

For the following explanation, the official documentation of anime.js will be useful.

In my example, the particles are located on an Archimedean spiral. The x and y position of a particle on the screen (aka left and top in CSS) is calculated from its position angle on the spiral:

x=a*angle*cos(angle) y=a*angle*sin⁡(angle)

The number of angles and thus the length of the spiral is determined by the parameter l. With the parameter a, you can control the density of the spiral.

var container = document.querySelector(".anime-container"); var n = 15; var a = 20; var l = 110; for (var i = 0; i <= l; i += 1) { var angle = 0.1 * i; //shift the particles to the center of the window //by adding half of the screen width and screen height var x = (a*angle) * Math.cos(angle) + window.innerWidth / 2; var y = (a*angle) * Math.sin(angle) + window.innerHeight / 2; var dot = document.createElement("div"); dot.classList.add("dot"); container.appendChild(dot); var size = 5; dot.style.width = size + "px"; dot.style.height = size + "px"; dot.style.left = x + "px"; dot.style.top = y + "px"; dot.style.backgroundColor = "hsl(60, 100%, 80%)"; } } First version of our spiral (Large preview)

This way, we get a spiral with exactly one particle per position, but a real trail effect can only be achieved if more than one particle is generated at each position. For the trail to look bushy, the positions of the individual particles must be slightly different. The anime-library provides a practical helper function for this: anime.random(minValue, maxValue);

The size of the particles also varies randomly:

for (var i = 0; i <= l; i += 1) { var angle = 0.1 * i; //shift particles to the center of the window //by adding half of the screen width and screen height var x = (a*angle) * Math.cos(angle) + window.innerWidth / 2; var y = (a*angle) * Math.sin(angle) + window.innerHeight / 2; var n = 15; //create n particles for each angle for (var j = 0; j < n; j++) { var dot = document.createElement("div"); dot.classList.add("dot"); container.appendChild(dot); var size = anime.random(5, 10); dot.style.width = size + "px"; dot.style.height = size + "px"; dot.style.left = x + anime.random(-15, 15) + "px"; dot.style.top = y + anime.random(-15, 15) + "px"; dot.style.backgroundColor = "hsl(60, 100%, 80%)"; } } The spiral with randomly placed particles (Large preview)

Here you can play around with the intermediate result:

See the Pen [anime js particles wip](https://codepen.io/smashingmag/pen/JjdqBve) by Anna Prenzel.

See the Pen anime js particles wip by Anna Prenzel.

Before the animation starts, all particles have to be invisible. So I will add:

dot.style.opacity = "0"; Animation Of The Particles Basic Settings Of The Animation

The basic settings of my animation are made up as follows:

  • The animation is to be repeated continuously (loop: true),
  • The easing is linear (but you can try different values),
  • The targets are all elements with the class "dot".
anime({ loop: true, easing: "linear", targets: document.querySelectorAll(".dot"), });

In the next step I will animate various CSS properties of my targets. The basic steps for CSS animation can be found in the properties chapter of the anime.js documentation.

Animation Of Opacity

This is what our first property animation looks like, in which all particles are slowly made visible within 50ms:

anime({ loop: true, easing: "linear", targets: document.querySelectorAll(".dot"), opacity: { value: 1, duration: 50} });

And now I will finally reveal the trick that creates a spiral movement of the particles! The idea is to make the particles visible with a certain time delay (e.g. in an interval of 2ms). The particles in the middle of the spiral are made visible at first, followed by all the other particles from inside to outside. The stagger function of anime.js is perfectly suited for this. In my opinion, staggering is one of the biggest strengths of the library that allows you to achieve great effects.

opacity: { value: 1, duration: 50, delay: anime.stagger(2) }

To create the illusion of a flying trail, the particles must start disappearing slowly as soon as they have appeared. Fortunately anime.js provides a keyframe notation for properties:

opacity: [ { value: 1, duration: 50, delay: anime.stagger(2) }, { value: 0, duration: 1200} ],

Here you can see the intermediate result:

See the Pen [anime js particles wip 2](https://codepen.io/smashingmag/pen/ZEGNjjv) by Anna Prenzel.

See the Pen anime js particles wip 2 by Anna Prenzel. Animation Of Size

My comet trail should appear larger at the front end than at the back end. For this purpose, I let the particles shrink within 500ms to a diameter of 2px. It is important to choose the same time delay as for the opacity animation, so that each particle starts to shrink only after it has appeared:

width: { value: 2, duration: 500, delay: anime.stagger(2) }, height: { value: 2, duration: 500, delay: anime.stagger(2) }, Individual Movement Of The Particles

The typical thing about a particle animation is the individual, unpredictable behavior of the particles. I finally bring the particles to life with an individual movement in the x and y direction:

translateX: { value: function() { return anime.random(-30, 30); }, duration: 1500, delay: anime.stagger(2) }, translateY: { value: function() { return anime.random(-30, 30); }, duration: 1500, delay: anime.stagger(2) }

Again, it is important that the movement starts with the same time delay as the appearance of the particles.

Furthermore, it is absolutely necessary in this case to have functions calculating the values for translateX and translateY. Here we are using the parameters as function-based parameters whose values are determined for each target individually. Otherwise all targets would be shifted by the same (albeit randomly determined) amount.

Final Thoughts

You can see the final result over here:

See the Pen [anime js particles](https://codepen.io/smashingmag/pen/yLNWqRP) by Anna Prenzel.

See the Pen anime js particles by Anna Prenzel.

You can modify the animation to your own taste by simply tweaking all the values. I have a little tip for the final touches: Now that we are familiar with function-based parameters, the opacity animation can be improved a bit:

opacity: [ { value: 1, duration: 50, delay: anime.stagger(2) }, { value: 0, duration: function(){return anime.random(500,1500);}} ],

The duration before a particle disappears is now set for each particle individually. This makes our animation visually even more sophisticated.

I hope you are now as excited as I am about the possibilities that anime.js offers for particle animations! I recommend a visit to CodePen where you can see many more impressive examples.

Further Reading on SmashingMag: Smashing Editorial (ra, yk, il)
Catégories: Programmation

How To Create A Particle Trail Animation In JavaScript

mar, 04/14/2020 - 13:00
How To Create A Particle Trail Animation In JavaScript How To Create A Particle Trail Animation In JavaScript Anna Prenzel 2020-04-14T11:00:00+00:00 2020-04-14T13:09:25+00:00

Have you ever thought about distracting visitors of your website with a fancy, glittering particle animation for a few moments, while some data is loaded in the background? Fortunately, it’s not necessary to go very deep into graphics programming with 3D libraries like three.js. All you need instead is some basic knowledge of CSS and JavaScript and a lightweight animation library such as anime.js. In the end, we should have the following result:

A spiral shaped particle trail animation Download And Integration Of Anime.js

You can download the anime.js library from the official GitHub site. Download the file anime.js or anime.min.js from the lib/ folder.

In my example, the HTML part looks like this:

<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Anime.js Particles</title> <!--or use anime.min.js--> <script src="anime.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <div class="anime-container"> </div> <script src="script.js"></script> </body> </html>

The CSS file styles.css defines the background color for the page and for the individual particles. The position settings are necessary so that we can later position the particles freely on the page using the CSS properties left and top.

body { background-color: hsl(30, 3%, 14%); } .anime-container { position: relative; } .anime-container .dot{ position: absolute; /*draw particles as circles:*/ border-radius: 50%; background-color: hsl(60, 100%, 80%); }

The content of the file script.js is covered in the following section.

Generating The Particles

As the name suggests, a particle animation consists of many small particles moving in space while following a certain pattern. All particles are generated simultaneously before the animation starts.

For the following explanation, the official documentation of anime.js will be useful.

In my example, the particles are located on an Archimedean spiral. The x and y position of a particle on the screen (aka left and top in CSS) is calculated from its position angle on the spiral:

x=a*angle*cos(angle) y=a*angle*sin⁡(angle)

The number of angles and thus the length of the spiral is determined by the parameter l. With the parameter a, you can control the density of the spiral.

var container = document.querySelector(".anime-container"); var n = 15; var a = 20; var l = 110; for (var i = 0; i <= l; i += 1) { var angle = 0.1 * i; //shift the particles to the center of the window //by adding half of the screen width and screen height var x = (a*angle) * Math.cos(angle) + window.innerWidth / 2; var y = (a*angle) * Math.sin(angle) + window.innerHeight / 2; var dot = document.createElement("div"); dot.classList.add("dot"); container.appendChild(dot); var size = 5; dot.style.width = size + "px"; dot.style.height = size + "px"; dot.style.left = x + "px"; dot.style.top = y + "px"; dot.style.backgroundColor = "hsl(60, 100%, 80%)"; } } First version of our spiral (Large preview)

This way, we get a spiral with exactly one particle per position, but a real trail effect can only be achieved if more than one particle is generated at each position. For the trail to look bushy, the positions of the individual particles must be slightly different. The anime-library provides a practical helper function for this: anime.random(minValue, maxValue);

The size of the particles also varies randomly:

for (var i = 0; i <= l; i += 1) { var angle = 0.1 * i; //shift particles to the center of the window //by adding half of the screen width and screen height var x = (a*angle) * Math.cos(angle) + window.innerWidth / 2; var y = (a*angle) * Math.sin(angle) + window.innerHeight / 2; var n = 15; //create n particles for each angle for (var j = 0; j < n; j++) { var dot = document.createElement("div"); dot.classList.add("dot"); container.appendChild(dot); var size = anime.random(5, 10); dot.style.width = size + "px"; dot.style.height = size + "px"; dot.style.left = x + anime.random(-15, 15) + "px"; dot.style.top = y + anime.random(-15, 15) + "px"; dot.style.backgroundColor = "hsl(60, 100%, 80%)"; } } The spiral with randomly placed particles (Large preview)

Here you can play around with the intermediate result:

See the Pen [anime js particles wip](https://codepen.io/smashingmag/pen/JjdqBve) by Anna Prenzel.

See the Pen anime js particles wip by Anna Prenzel.

Before the animation starts, all particles have to be invisible. So I will add:

dot.style.opacity = "0"; Animation Of The Particles Basic Settings Of The Animation

The basic settings of my animation are made up as follows:

  • The animation is to be repeated continuously (loop: true),
  • The easing is linear (but you can try different values),
  • The targets are all elements with the class "dot".
anime({ loop: true, easing: "linear", targets: document.querySelectorAll(".dot"), });

In the next step I will animate various CSS properties of my targets. The basic steps for CSS animation can be found in the properties chapter of the anime.js documentation.

Animation Of Opacity

This is what our first property animation looks like, in which all particles are slowly made visible within 50ms:

anime({ loop: true, easing: "linear", targets: document.querySelectorAll(".dot"), opacity: { value: 1, duration: 50} });

And now I will finally reveal the trick that creates a spiral movement of the particles! The idea is to make the particles visible with a certain time delay (e.g. in an interval of 2ms). The particles in the middle of the spiral are made visible at first, followed by all the other particles from inside to outside. The stagger function of anime.js is perfectly suited for this. In my opinion, staggering is one of the biggest strengths of the library that allows you to achieve great effects.

opacity: { value: 1, duration: 50, delay: anime.stagger(2) }

To create the illusion of a flying trail, the particles must start disappearing slowly as soon as they have appeared. Fortunately anime.js provides a keyframe notation for properties:

opacity: [ { value: 1, duration: 50, delay: anime.stagger(2) }, { value: 0, duration: 1200} ],

Here you can see the intermediate result:

See the Pen [anime js particles wip 2](https://codepen.io/smashingmag/pen/ZEGNjjv) by Anna Prenzel.

See the Pen anime js particles wip 2 by Anna Prenzel. Animation Of Size

My comet trail should appear larger at the front end than at the back end. For this purpose, I let the particles shrink within 500ms to a diameter of 2px. It is important to choose the same time delay as for the opacity animation, so that each particle starts to shrink only after it has appeared:

width: { value: 2, duration: 500, delay: anime.stagger(2) }, height: { value: 2, duration: 500, delay: anime.stagger(2) }, Individual Movement Of The Particles

The typical thing about a particle animation is the individual, unpredictable behavior of the particles. I finally bring the particles to life with an individual movement in the x and y direction:

translateX: { value: function() { return anime.random(-30, 30); }, duration: 1500, delay: anime.stagger(2) }, translateY: { value: function() { return anime.random(-30, 30); }, duration: 1500, delay: anime.stagger(2) }

Again, it is important that the movement starts with the same time delay as the appearance of the particles.

Furthermore, it is absolutely necessary in this case to have functions calculating the values for translateX and translateY. Here we are using the parameters as function-based parameters whose values are determined for each target individually. Otherwise all targets would be shifted by the same (albeit randomly determined) amount.

Final Thoughts

You can see the final result over here:

See the Pen [anime js particles](https://codepen.io/smashingmag/pen/yLNWqRP) by Anna Prenzel.

See the Pen anime js particles by Anna Prenzel.

You can modify the animation to your own taste by simply tweaking all the values. I have a little tip for the final touches: Now that we are familiar with function-based parameters, the opacity animation can be improved a bit:

opacity: [ { value: 1, duration: 50, delay: anime.stagger(2) }, { value: 0, duration: function(){return anime.random(500,1500);}} ],

The duration before a particle disappears is now set for each particle individually. This makes our animation visually even more sophisticated.

I hope you are now as excited as I am about the possibilities that anime.js offers for particle animations! I recommend a visit to CodePen where you can see many more impressive examples.

Further Reading on SmashingMag: Smashing Editorial (ra, yk, il)
Catégories: Programmation

Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography

lun, 04/13/2020 - 12:00
Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography Andrew Clarke 2020-04-13T10:00:00+00:00 2020-04-13T12:35:19+00:00

While good use of type helps people to read, great typography can do so much more. Typography can eloquently articulate an idea and colourfully communicate a message in ways which are as powerful as any illustration or photograph.

I’m someone who loves cinema as much as I admire typography. Few things inspire me as much as seeing movie poster typography which either evokes the atmosphere of a film and adds to the telling of its story.

 Pulp Fiction by Indika Entertainment Advertising. Once Upon a Time in Hollywood by BLT and Steve Chorney. Vertigo by Saul Bass. West Side Story by Joseph Caroff. From left: Pulp Fiction by Indika Entertainment Advertising. Once Upon a Time in Hollywood by BLT and Steve Chorney. Vertigo by Saul Bass. West Side Story by Joseph Caroff. (Large preview)

More recently, typography in Quentin Tarantino’s film posters perfectly reflects the atmosphere and character of his movies. In Pulp Fiction, the title’s Aachen Bold typeface is as hardboiled as the film itself. For Once Upon a Time in Hollywood, although the typesetting of the iconic sign deviates from reality as much as other parts of the film, the poster conjures up the spirit of Hollywood.

Saul Bass is possibly the best-known graphic designer of his era and for 1950s and ’60’s Hollywood he created movie posters which are as recognisable as the sign itself. For his poster design for Hitchcock’s Vertigo in 1958, Bass used hand-cut typography which evokes German expressionist films of the 1920s. In 1960, Bass’s slashed title typography for Pyscho — again for Alfred Hitchcock — is both clever and obvious. While Saul Bass is often incorrectly credited with designing one of my favourite film posters from West Side Story, — Bass did design the title sequence — the poster was actually designed by Joseph Caroff who also created James Bond’s famous 007 logo.

Although we don’t yet have the same control over typography on the web as we do in print, new file formats, font delivery services, and web fonts have meant far more typographic flexibility than we had ten years ago. Typography controls in CSS have helped us be more creative with type too. On top of basic font style properties, we can now reliably fine-tune OpenType figures, hyphenation, ligatures, and even kerning.

It’s rare to find such creative uses for type online, studying the work of graphic designers and talented typographers can open our eyes to what we can achieve using today’s type technologies. One of my personal favourite designers and typographers is Herb Lubalin, and learning about him and his work has transformed my own approach to typography.

Read More From The Series Inspired By Herb Lubalin

Herb Lubalin was an American graphic designer who spent his career designing everything from advertising, posters, and even postage stamps. He was fascinated by the look of words and how typographic design can make them sound. Lubalin understood how by combining art, copy, and typography, graphic designers add conviction when communicating messages. He said:

“The better people communicate, the greater will be the need for better typography-expressive typography.”

— Herb Lubalin

Having narrowly passed the entrance exam to the Cooper Union art school in New York, Herbert (Herb) Lubalin was fired from his first job as a graphic artist for asking for a $2 per week raise. In pre-war American advertising agencies, the job of a layout artist was simply to place headlines, copy, and images into available space, but that changed after WW2 with an influx of immigrant designers from Europe. They included Austrian Herbert Bayer, Russian Mehemed Fehmy Agha, and Belarusian Alexey Brodovitch.

U&lc (Uppercase and lowercase) magazine by Herb Lubalin. (Large preview)

These designers imported new processes which brought art directors, layout artists, and writers together to form the creative teams made popular by the famous advertising creative director Bill Bernbach in the 1960s and 1970s.

In 1945, Lubalin became art director at Sudler & Hennessey — a creative studio which specialised in the pharmaceutical industry — where he led a team of designers, illustrators, and photographers. The process which Lubalin established first at Sudler & Hennessey and from 1964 in his own studio is fascinating. He drove the design process by making “tissues” — pen and ink sketches which established the spacial arrangement of its elements — and detailed notes on typographic designs including typeface choices, sizes, and weights.

Fact magazine by Herb Lubalin. (Large preview)

At the start of any new project, Lubalin began by sketching arrangements of headlines, copy, and images onto tissue paper. Then, he’d lay another tissue on top to refine his ideas, then another, and another, to rapidly develop his design. After his assistants recovered discarded tissues from the floor or trash, they became collectors’ items.

Lubalin was an obsessive perfectionist about typography. For “Let’s talk type” — a trade advertisement for Sudler & Hennessey — Lubalin precisely placed the only paragraph. This copy sits perfectly on the baseline alongside the word “let” and its size and leading allow for the descender from the letter “y” above.

From left: Trade press advertisement. The fourth of July means picnics… Announcement of Avant Garde’s anti-war poster competition by Herb Lubalin. (Large preview)

Lubalin was equally as precise about the placement of text in a poster which announced the Avant Garde anti-war poster competition. He would frequently take a scalpel blade to type, adjusting the spacing between letters and altering the height of ascenders and descenders to fit his designs. Letters in the headline for “No More War” are precisely sized and aligned. The tracking of the uppercase blue standfirst creates a block of copy which perfectly fits into its space.

In “The fourth of July means picnics…” Lubalin used perspective to represent the road ahead. This meant considering the tracking of every line of text, sometimes altering words to fit the design. Working with Lubalin’s designs wasn’t easy, and as one of his assistants later described:

“To make everything line up, you’ve got to do it over and over again, and then, if the client alters the text, you’ve got to redo the whole thing. To him (Lubalin,) it was worth it. How long it took or how much it cost wasn’t as important to him as it was to other designers.”

Because of his relentless conviction as well as his talent, Lubalin went on to become one of the most celebrated graphic designers and typographers of the twentieth century. There’s plenty we can learn from how he approached his work and his conviction that design can compellingly communicate.

Various designs by Herb Lubalin. (Large preview)

There are two books on Herb Lubalin and his work you should add to your collection. “Herb Lubalin: Art Director, Graphic Designer and Typographer” (1985) by Gertrude Snyder and Alan Peckolick is out of print, but good copies are available on eBay. Better still is “Herb Lubalin: American Graphic Designer” (2013) by Adrian Shaughnessy and published by Unit Editions. A limited edition of 2000, Shaughnessy’s book features hundreds of examples of Lubalin’s work.

Pre-Formatting Headlines

Headlines are a perfect place to begin being more adventurous with type. Expressive typography needn’t need fancy fonts. You can create an eye-catching headline by using different styles and weights found within many everyday font families. Look for extended families like Montserrat — designed by Julieta Ulanovsky and available on Google Fonts — with its variety of weights ranging from thin and light, to extra-bold, and even black.

For this first Herb Lubalin inspired design, my headline uses black and light weights from this sans-serif typeface. Negative tracking (letter-spacing) and tight leading (line-height) combine to create a block of type which demands attention.

Black and light weights, negative tracking and tight leading. (Large preview)

In the past, developing headlines like this involved hard-coding the design into your HTML by adding breaks between individual words, like this:

<h1><strong>UK’s <br> best-<br> selling <br> car</strong> <br> during <br> the <br> 1970s</h1>

Other times, you might use wrap each word with an inline span element and then change its display property to block:

<h1><strong><span>UK’s</span> <span>best-</span> <span>selling</span> <span>car</span></strong> <span>during</span> <span>the</span> <span>1970s</span></h1>

Instead of these presentational elements, I add explicit line breaks in my HTML:

<h1><strong>UK’s best- selling car</strong> during the 1970s</h1>

Browsers ignore anything more than a single space between words, so on small viewports, this headline reads like a sentence. I only need foundation styles which style its colours, size, and weights, as well as the negative tracking and tight leading which makes this headline distinctive:

h1 { font-size: 6vmax; font-weight: 300; line-height: .75; letter-spacing: -.05em; text-transform: uppercase; color: #fff; } h1 strong { font-weight: 600; color: #bd1f3a; }

Whereas HTML’s pre element respects pre-formatted text and presents it exactly as written in a document, the CSS white-space property enables similar results without sacrificing semantics. Of the six available white-space values, these are the four I use these most often:

  1. white-space: normal;
    Text fills line-boxes and breaks as required
  2. white-space: nowrap;
    The text won’t wrap, and it may overflow its container
  3. white-space: pre;
    Explicit line-breaks are respected, text breaks with new lines and br elements
  4. white-space: pre-wrap;
    White-space is respected, but the text will also wrap to fill line-boxes

I only need the effects of the white-space property on larger viewports, so I isolate it with a media query:

@media (min-width: 64em) { h1 { white-space: pre; } }

Using several styles from one font family adds visual interest. My Lubalin-inspired design incorporates light, bold, and black weights, plus condensed and regular styles of this sans-serif typeface to produce a variety of text-treatments.

Several paragraph styles from one font family adds visual interest. (Large preview)

First, I need two structural elements to accomplish my design, main and aside:

<main>…</main> <aside>…</aside>

While the main element includes my headline and running text, the aside contains four images in a division and five articles about versions of the classic Cortina:

<aside> <div> <img src="img-1.svg" alt="Ford Cortina Mark 1 front profile"> <img src="img-2.svg" alt="Ford Cortina Mark 3 rear"> <img src="img-3.svg" alt="Ford Cortina Mark 4 front"> <img src="img-4.svg" alt="Ford Cortina Mark 5 rear profile"> </div> <article>…</article> <article>…</article> <article>…</article> <article>…</article> <article>…</article> </aside>

First, I specify the styles of paragraphs in each of my articles using pseudo-class selectors. Each paragraph uses a different combination of font styles and weights, with mixed-case and uppercase letters:

article:nth-of-type(1) p { font-family: 'light'; text-transform: uppercase; } article:nth-of-type(2) p { font-family: 'bold-condensed'; font-weight: 600; text-transform: uppercase; } article:nth-of-type(3) p { font-family: 'bold-condensed'; font-weight: 600; } article:nth-of-type(4) p { font-family: 'light'; text-transform: uppercase; } article:nth-of-type(5) p { font-family: 'bold-condensed'; font-weight: 600; }

With those foundation styles in place for every screen size, I introduce layout to the aside element which will be visible on for medium-size screens. For layouts like this, where elements don’t overlap, I often grid-template-areas for their simplicity. This design has nine grid areas. While I could give these areas names which describe the content I’ll place into them — for example, “mark-1” — instead I use letters which makes moving items around my grid a little easier:

@media (min-width: 48em) { aside { display: grid; grid-template-areas: "a b c" "d e f" "g h i"; grid-gap: 1.5rem; } }

I need to place the four images into my template areas, and not the division which contains them. I change the display property of that element to contents, which effectively removes it from the DOM for styling purposes:

aside div { display: contents; }

I place those images using area names. Moving them into another area only involves referencing a different area name and no change to their order in my HTML:

aside img:nth-of-type(1) { grid-area: a; } aside img:nth-of-type(2) { grid-area: e; } aside img:nth-of-type(3) { grid-area: g; } aside img:nth-of-type(4) { grid-area: i; }

Then, I place articles into the five remaining areas to complete my layout:

aside article:nth-of-type(1) { grid-area: b; } aside article:nth-of-type(2) { grid-area: c; } aside article:nth-of-type(3) { grid-area: d; } aside article:nth-of-type(4) { grid-area: f; } aside article:nth-of-type(5) { grid-area: h; }

On small and medium-size screens, the main and aside elements stack vertically in the order they appear in my HTML. The extra space available in larger viewports allows me to place them side-by-side so visual weight is balanced across both sides of a screen. First, I apply a five-column symmetrical grid to the body element:

@media (min-width: 64em) { body { display: grid; grid-template-columns: repeat(5, 1fr); } }

Then, I place both main and aside elements using line numbers. This creates an asymmetrical design with a column of white space between my main content and the articles which support it:

main { grid-column: 1; } aside { grid-column: 3 / -1; } } Reordering And Rotating

CSS Grid is now the best tool to use for implementing inspired layouts, and its powerful properties are also useful for developing intricate typographic designs.

Left: Castrated. Book jacket designed by Herb Lubalin. Right: Intricate header design developed using CSS Grid and Flexbox. (Large preview)

My header contains a headline followed by two paragraphs and their order in HTML means they make sense when read without any styling applied:

<header> <h1>Cortina</h1> <p>UK’s best-selling car</p> <p>From <span>1962–1983</span></p> </header>

To begin this design, I add foundation styles for both elements, setting their alignment, colours, and sizes:

header h1, header p { margin: 0; text-align: center; } header h1 { font-size: 10vmax; color: #ebc76a; line-height: 1; } header p { font-size: 4vmax; line-height: 1.1; text-transform: uppercase; }

I ordered my HTML for a semantic sentence structure, rather than any visual presentation, so to allow me to reorder the elements visually, I add Flexbox properties to my header and a flex-direction value of column:

header { display: flex; flex-direction: column; }

By default, elements appear in the order they occur in HTML, but in my design, the last paragraph in this header appears first, above the headline.

The default order value for all elements is 0, so to change the position of this paragraph without altering my HTML, I add a negative value of -1, which places it at the top:

header p:last-of-type { order: -1; }

My design for medium-size screens includes two large bands of background colours, developed using a CSS gradient. So next, I change the foreground colours of my headline and paragraphs to contrast them against this new background:

@media (min-width: 48em) { body { background-image: linear-gradient(to right, #0a0a08 0%, #0a0a08 50%, #fff 50%, #fff 100%); } header h1 { color: #fff; } header p { color: #ebc76a; } }

The unusual alignment of the three elements in this header is possible by combining CSS Grid with Flexbox. Although it might not be obvious at first, I place the headline and paragraphs in this header onto a four-column symmetrical grid. Leaving one column in the first and last rows empty creates a dynamic diagonal which adds interest to this header:

@media (min-width: 64em) { header { display: grid; grid-template-columns: repeat(4, 1fr); align-items: start; padding-top: 0; } } A dynamic diagonal which adds interest to this header. (Large preview)

My headline spreads across all four columns:

header h1 { grid-column: 1 / -1; }

While the first — which appears at the bottom of my header — leave the first column empty:

header p:first-of-type { grid-column: 2 / -1; }

The final paragraph—now placed at the top of the header — spans the first three columns, leaving a space on the left:

header p:last-of-type { grid-column: 1 / 4; }

It’s unusual to see rotated text elements on the web, but when you do, they’re often memorable and always a nice a surprise. I want my headline rotated anti-clockwise, so I add a transform which rotates it negatively by 30 degrees and moves it vertically down by 150px:

header { transform: rotate(-30deg) translateY(150px); transform-origin: 0 100%; }

transform-origin specifies the point around which transforms happen. You can choose an origin in the centre or any of the four corners of an element — top-left (0 0), top-right (100% 0), bottom-right (100% 100%) or bottom-left (0 100%). You might also specify an origin in pixels, em, or rem units.

The results of 50% 50%, 0 0, 100% 0, 100% 100%, and 0 100% transform-origin values. (Large preview)

For an extra element of surprise, I add a subtle transition to that transform and reduce the amount of rotation when someone passes their cursor over my headline:

header { transition: transform .5s ease-in; } header:hover { transform: rotate(-25deg) translateY(150px); } CSS Grid is now the best tool to use for implementing inspired layouts. (Large preview) Combining Header Elements Left: Graphis Annual Report. Center: American Showcase references USA flag. Right: My design references the United Kingdom’s Union flag. (Large preview)

In my next Lubalin-inspired design, I combine an ordered list of Cortina models with a multi-coloured headline to make a powerful statement with this header:

<header> <div> <h1>…</h1> <ol>…</ol> </div> </header>

This headline includes three lines of text. Whereas I previously avoided using additional elements, to style these lines differently I need three inline span elements:

<h1> <span>Best</span> <span>Selling</span> <span>Cortina</span> </h1>

The most semantic choice to mark up my list of Cortina models and the years during which they were manufactured, is an ordered list. To strongly emphasise each model name, I enclose them within strong elements, which deliver semantic value as well as a bold appearance from default browser styles:

<ol> <li><strong>Mark I</strong> 1962–1966</li> <li><strong>Mark II</strong> 1966–1970</li> <li><strong>Mark III</strong> 1970–1976</li> <li><strong>Mark IV</strong> 1976–1979</li> <li><strong>Mark V</strong> 1979–1983</li> </ol>

For small viewports, I need only a few foundation styles. The large font size and minimal leading create a solid block of text. Then, I change the span element’s display value from inline to block and use pseudo-class selectors to change the foreground colours of the first and third lines:

h1 { font-size: 18vmin; line-height: .9; color: #fff; } h1 span { display: block; } h1 span:nth-of-type(1) { color: #ba0e37; } h1 span:nth-of-type(3) { color: #31609e; }

I want items in my ordered list to form a two-column symmetrical grid where each column occupies an equal amount of available space:

ol { list-style-type: none; display: grid; grid-template-columns: 1fr 1fr; }

Then, I tighten the items’ leading and add a solid blue border to the bottom of all but the last list-item:

li { display: inline-block; line-height: 1.2; } li:not(:last-of-type) { border-bottom: 1px solid #31609e; }

Conveniently, there’s no need to specify column or row numbers for each list-item because CSS Grid arranges them automatically because of normal flow. To add greater emphasis, I change the strong elements’ display values to block and set them in uppercase:

li strong { display: block; font-size: 1.266rem; font-weight: 600; text-transform: uppercase; } A multi-coloured headline combined with an ordered list of Cortina models. (Large preview)

Centring an element both horizontally and vertically used to be tricky, but thankfully, Flexbox has made this alignment trivial to implement. Flexbox has two axes — main axis and cross axis — which change direction if you change the default flex-direction value from a row.

The flex-direction of my header remains row, so I align-items centre on the cross axis (vertical,) then justify-content centre along the main axis (horizontal:)

@media (min-width: 48em) { header { display: flex; align-items: center; justify-content: center; } }

With content now entered in the header, I apply a grid which contains three columns and two rows. Their dimensions will be defined by their content and will resize automatically:

header > div { display: grid; grid-template-columns: repeat(3, min-content); grid-template-rows: auto auto; }

The three multi-coloured lines in the headline are the foundation for this header design. I want to place them into specific columns and rows in this grid, so I add display: contents; to the headline:

h1 { display: contents; }

Then, I place that multi-coloured text into columns and rows using line numbers:

h1 span:nth-of-type(1) { grid-column: 1; grid-row: 2; } h1 span:nth-of-type(2) { grid-column: 2; grid-row: 1 / 3; } h1 span:nth-of-type(3) { grid-column: 3; grid-row: 1 / 3; }

I want the text in my header to appear vertical, so I rotate each span clockwise by 180 degrees, then change their writing-mode to vertical left–right:

h1 span { transform: rotate(180deg); writing-mode: vertical-lr; }

The headline and ordered list in my design form a solid block. To pack these elements tightly together, I change the list’s display property from grid to block. Then, I align content in each list-item to the right, so they sit on my headline’s baseline:

ol { display: block; } li { text-align: right; } SVG And Text

It’s taken me a long time to appreciate SVG and to become familiar with how to get the best value from it, and I’m still learning. SVG is capable of producing far more than basic shapes, and one of its most exciting features is the text element.

Like HTML text, SVG text is accessible and selectable. It’s also infinitely styleable by using clipping paths, fills including gradients, filters, masks, and strokes. Adding text to SVG is just like including it in HTML, using the text element. Only content inside these text elements is rendered by browsers, and they ignore anything outside them. You can add as many text elements as you need, but my next headline needs only one:

<svg> <text>’70’s best-selling Cortina British car</text> </svg>

SVG includes a set of properties and attribute values which can be applied to text. Many SVG properties — like letter and word spacing, and text-decoration — are also in CSS. But it’s styling features unique to SVG which help to make SVG text so appealing.

For example, textLength sets the width of rendered text, which will shrink and stretch to fill the space depending on the lengthAdjust value you choose.

  • textLength
    The text will be scaled to fit. Set textLength in percentages or use any numerical values. I prefer to use text-based units, em or rem.
  • lengthAdjust
    Defines how the text will be compressed or stretched to fit the width defined in the textLength attribute.

When used directly on a text element, SVG properties act the same as inline styles:

<svg> <text textLength="400">’70’s best-selling Cortina British car</text> </svg>

But just as with inline styles, the best value is achieved by styling SVG elements using CSS, whether in an external stylesheet or embedded in HTML. You can even use a style element in an external SVG file or a block of SVG included alongside HTML:

<svg> <text class="display">’70’s best-selling Cortina British car</text> </svg> <style> .display { font-size: 100px; font-family: 'black-extended'; font-weight: 600; letter-spacing: -1px; text-anchor: middle; text-transform: uppercase; } </style>

HTML has its span element and SVG includes a similar element which is useful for separating text into smaller elements so they can be styled uniquely. For this headline, I divide the content of the text element between six tspan elements:

<text> <tspan>’70’s</tspan> <tspan>best-</tspan> <tspan>selling</tspan> <tspan>Cortina</tspan> <tspan>British</tspan> <tspan>car</tspan> </text>

By splitting my headline into multiple elements, I’m able to style each individual word. I can even position them precisely within my SVG, according to the baseline or even relative to each other.

  • x is the horizontal starting point for the text baseline;
  • y is the vertical starting point for the text baseline;
  • dx shifts text horizontally from a previous element;
  • dy shifts text vertically from an earlier element.
(Large preview)

For my headline, I position the first tspan element 80px from the top, then each subsequent element appears 80px below it:

<text> <tspan y="80">’70’s</tspan> <tspan dy="80">best-</tspan> <tspan dy="80">selling</tspan> <tspan dy="80">Cortina</tspan> <tspan dy="80">British</tspan> <tspan dy="80">car</tspan> </text>

tspan elements are useful for precise positioning and individual styling, but they’re not without accessibility concerns. Assistive technology pronounce tspan elements as individual words and even spell them when a tspan wraps a single letter. For example, a screen reader will pronounce this series of tspan elements:

<tspan>C</tspan> <tspan>o</tspan> <tspan>r</tspan> <tspan>t</tspan> <tspan>i</tspan> <tspan>n</tspan> <tspan>a</tspan>

As:

“C”, “o”, “r”, “t”, “i”, “n”, “a”

We shouldn’t inconvenience people who use assistive technology or worse make our content inaccessible because of our styling choices. So avoid using tspan unnecessary and never for single letters.

Stroking Text With CSS And SVG

Adding a stroke often helps legibility when text is placed in front of a background image, and it can also make subtle and striking results. You won’t find an official way to stroke text in any CSS specification. But there is an experimental property which uses a Webkit vendor prefix and is widely supported by contemporary browsers.

(Large preview)

text-stroke is shorthand for two properties: text-stroke-color and text-stroke-width. For my stroked headline, I first set foundation typography styles for family, size, and weight, then adjust the leading and tracking:

h1 { font-size: 100px; font-family: 'black-extended'; font-weight: 600; letter-spacing: -6px; line-height: .8; color: #fff; }

Then I apply text-stroke and add the text-fill-color property with a value of transparent which overrides the white foreground colour:

h1 { /* -webkit-text-stroke-color: #fff; */ /* -webkit-text-stroke-width: 5px; */ -webkit-text-stroke: 5px #fff; -webkit-text-fill-color: transparent; }

Although text-stroke is an experimental property and not in a W3C specification, now that browsers have implemented it, there’s little chance of it being removed. But if you’re still concerned about supporting a legacy browser, consider using a feature query to test for text-stroke support and provide an appropriate fallback for them.

SVG has stroke properties too, plus a few options which aren’t available in CSS. If you need more options and the widest browser support, SVG is the answer. My SVG header includes six tspan elements:

<svg> <text> <tspan>’70’s</tspan> <tspan>best-</tspan> <tspan>selling</tspan> <tspan>Cortina</tspan> <tspan>British</tspan> <tspan>car</tspan> </text> </svg>

On top of foundation typography styles, I add the equivalent SVG properties for text-stroke-color and text-stroke-width. I also reduce the opacity of my stroke, which is an option unavailable in CSS:

text { stroke: #fff; stroke-width: 1.5px; stroke-opacity=".8"; } SVG stroke-dasharray adds a border style not possible using CSS alone. (Large preview)

SVG includes other properties which fine-tune aspects of a stroke. Unlike CSS, SVG strokes can be dashed using the stroke-dasharray property. Alternate values define filled areas and blank areas, so the dashes around my headline text are one unit filled, then ten units blank:

text { stroke-dasharray: 1, 10; }

Should you need more complex patterns, add extra numbers to the pattern, so a stroke-dasharray value of 1, 10, 1 results in a dashed stroke which is 1 (filled,) 10 (blank,) 1 (filled,) 1 (blank,) 10 (filled,) 1 (blank,) and repeats.

My large-screen design, inspired by Herb Lubalin. (Large preview) stroke-linecap defines how ends of lines appear in SVG. Left: butt. Middle: round. Right: square. (Large preview) stroke-linejoin defines how lines join in SVG. Left: bevel. Middle: round. Right: miter. (Large preview) Optimize SVG Accessibility

CSS typography controls are now more powerful than ever, but there are occasions when a design calls for more than styled HTML text. Image replacement techniques have fallen out of fashion, but SVG — whether in an external file or inline within HTML — can deliver scalable text effects. SVG can also be useful for overall performance when optimised well and can be made accessible.

This header contains two typefaces. One is Magehand, a decorative retro-style script by Indonesian type designer Arief Setyo Wahyudi. The other is Mokoko, a slab serif by London-based Dalton Maag which is available in seven weights from thin to black.

Embedding these two fonts in both Web Open Font Format (WOFF) and WOFF2 formats would add over 150kb to my page. Whereas, by converting these fonts to outlines in a graphics editor and delivering the header as an optimised SVG image would add only 17kb.

The SVG image in my header contains three paths:

<svg xmlns="http://www.w3.org/2000/svg"> <path id="top">…</path> <path id="bottom">…</path> <path id="middle">…</path> </svg> (Large preview)

The order of these paths matters, because just as in HTML, elements are stacked in the order they’re written. SVG includes a set of properties and attribute values which can be applied to any element. I use the fill property to colour each path in my header:

<path fill="#bd1f3a">…</path> <path fill="#31609e">…</path> <path fill="#fff">…</path>

For an even more stylish effect, I can define a linear gradient with two colour stops, and reference that to fill my decorative script:

<defs> <linearGradient id="cortina" gradientTransform="rotate(90)"> <stop offset="0%" stop-color="#bd1f3a" /> <stop offset="100%" stop-color="#31609e" /> </linearGradient> </defs> <path fill="#fff">…</path> <path fill="#fff">…</path> <path fill="url('#cortina')">…</path>

SVG files are frequently smaller than bitmap images or the combined size of several font files, but they nevertheless need careful optimisation to achieve the best performance.

Every element, handle, and node increases the size of an SVG file, so replace paths with basic shapes like circles, ellipses, or rectangles where possible. Simplify curves to reduce the number of nodes and use fewer handles. Popular graphic software like Adobe Illustrator, Affinity Designer, and Sketch export files bloated by unoptimised elements and unnecessary metadata. But, tools like SVGOMG by developer Jake Archibald will strip away unneeded items and can often reduce SVG file size substantially.

SVG images which contain text outlines can also be made accessible by using alternative text and ARIA properties. When linking to an external SVG file, add alternative text as you should with any non-decorative image:

<img src="header.svg" alt="Cortina. ’70s best-selling British car">

The best way to help people who use assistive technology is to embed SVG into HTML. Add an ARIA role and a descriptive label and screen readers will treat the SVG as a single element and read the label description aloud:

<svg role="img" aria-label="Cortina. ’70s best-selling British car"> … </svg>

Adding a title element helps assistive technology to understand the difference between several blocks of SVG, but this title won’t be displayed in a browser:

<svg> <title>Cortina. ’70s best-selling british car</title> </svg>

When there are several blocks of SVG in a document, give each one a unique ID and add that to its title:

<svg> <title id="header">…</title> </svg>

ARIA has several attributes which help SVG accessibility. When SVG is purely decorative and has no semantic value, hide it from assistive technology by adding an aria-hidden attribute:

<svg aria-hidden="true"> … </svg>

For my design, I use SVG in place of an HTML heading. To replace the missing semantics for assistive technology, use an ARIA role attribute and a value of heading. Then add a level attribute which matches the missing HTML:

<svg role="heading" aria-level="1"> … </svg> Clipping Type

The CSS background-clip property defines whether an element’s background extends underneath its border-box, padding-box, or content-box, according to the CSS box model:

  • border-box
    Background extends to the outside edge of the border (and underneath the border).
  • padding-box
    Background extends to the outside edge of the padding only.
  • content-box
    The background is rendered within (clipped to) the content box only.
background-clip. Left: border-box. Middle: padding-box. Right: content-box. (Large preview)

But, there’s one more value which offers many more opportunities for inspiring typography. Using text as a value for background-clip clips an element’s background to the space occupied by the text it contains.

Left: Anti-war poster for American Institute of Graphic Arts exhibition. Designed by Herb Lubalin. Right: The background-clip text value clips an element’s background to the space occupied by the text it contains. (Large preview)

In my next example, the brake disk background image is visible only where there’s text in the headline. When my headline includes more content or its text size increases, more of that background image will be visible:

h1 { background-image: url(pattern.svg); background-clip: text; -webkit-background-clip: text; color: transparent; }

You can apply the text value for background-clip to any element except the :root, HTML. As support forbackground-clip is limited, I use a feature query which delivers those styles only to supporting browsers:

h1 { color: #fff; } @supports (background-clip: text) or (-webkit-background-clip: text) { h1 { background-color: #fff; background-image: url(pattern.svg); background-position: 50% 100%; background-repeat: no-repeat; background-size: 50%; background-clip: text; -webkit-background-clip: text; color: transparent; } }

Inspired by Lubalin, I want to place images inside the letters of my next headline, and the SVG image element allows me to do just that.

Left: Trade press advertisement designed by Herb Lubalin. Right: Images inside each letter of my SVG headline. (Large preview)

As this SVG image represents a heading, I add alternative text plus an ARIA role and level to ensure it remains accessible:

<img src="header.svg" alt="Cortina" role="heading" aria-level="1">

In SVG, the defs element stores graphical objects which can be referenced from elsewhere in a file. These include the patterns which contain my images and I add one for each letter:

<svg> <defs> <pattern id="letter-c">…</pattern> <pattern id="letter-o">…</pattern> <pattern id="letter-r">…</pattern> … </defs> … </svg>

Content in the defs element is not rendered directly and to display it I reference them with either a use attribute or url. My SVG contains one path for each of the seven letters in the word “Cortina,” and I fill each path with a pattern using its unique ID:

<svg> <defs>…</defs> <path fill="url(#letter-c)">…</path> <path fill="url(#letter-o)">…</path> <path fill="url(#letter-r)">…</path> … </svg> Images inside each letter of my SVG headline. (Large preview)

Image elements allow either bitmap or vector images to be rendered within an SVG. My design incorporates three car part blueprint images which I link to using a standard href attribute:

<defs> <pattern id="letter-c" width="100%" height="100%"> <image href="pattern-c.png" height="250" width="250"/> </pattern> … </defs>

These three car part pattern images fill each letter, and the result is a striking headline design which demands attention.

Combining Techniques

There’s no doubt that Herb Lubin had a masterful ability to make type talk. For this final Lubin-inspired example, I put together the techniques I’ve demonstrated to create a compelling design for this classic ’70s Ford.

Left: Trade press advertisement designed by Herb Lubalin. Right: Main content placed over a text-based SVG background image. (Large preview)

To develop this design, I need two structural elements which should be very familiar by now, a main and aside:

<main>…</main> <aside>…</aside>

My main element contains a header element with an SVG headline followed by a division which includes my running text. I add an ARIA role and level to my headline to ensure its SVG text is accessible:

<main> <header> <svg role="heading" aria-level="1">…</svg> </header> <div>…</div> </main>

To serve a full image to small screens and half to larger viewports, I use a picture element and a minimum width media query:

<aside> <picture> <source srcset="half.svg" media="(min-width: 74em)"> <img src="full.svg" alt="Ford Cortina"> </picture> </aside>

Lubalin’s designs are often energetic, so to fill my main element with energy, I apply grid properties and use three columns and five rows to develop an asymmetrical layout.

main { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: repeat(5, 1fr); }

This design is dominated by an outline of the charismatic Cortina, and a text-based background image which covers the main element. I scale this SVG to fill the element’s background, and change the background-origin so it appears only behind the content and not its border or padding:

main { background-image: url(main.svg); background-origin: content-box; background-position: top right; background-repeat: no-repeat; background-size: 100% 100%; }

Leaving columns around my header and text division empty creates negative space which helps to lead someone’s eye around the composition. The header occupies the first two of my three columns while the division fills the last two:

header { grid-column: 1 / 3; grid-row: 2 / 3; } main div { grid-column: 2 / 4; grid-row: 3 / 6; }

One of the benefits of using the SVG text element is the ability to position text according to its baseline or relative to each elements. My headline SVG includes two text elements for the name of this car, and a third for the period it was manufactured. I want to place this final text element precisely 250px from the left and 60px from the top of my SVG:

<svg> <text x="0" y="60">Ford</text> <text x="0" dy="70">Cortina</text> <text x="250" y="60">1962–1983</text> </svg> Left: My large-screen design, inspired by Herb Lubalin. Right: To serve a full Cortina image to small screens and only the right half to larger viewports, I use a picture element. (Large preview)

This dazzling design becomes more memorable on larger viewports when the text-based SVG background image and my Cortina outline fit alongside each other. I apply a two-column symmetrical grid to the body element:

@media (min-width: 74em) { body { display: grid; grid-template-columns: [main] 1fr [aside] 1fr; } }

Then, I place the main and aside elements onto my grid using line names:

main { grid-column: main; } aside { grid-column: aside; } }

On the web, inspiring typography should be attractive and readable, but the readability of running text can easily be affected by the background behind it.

The backdrop-filter applies CSS filter effects to elements behind the text. These filters include blur, brightness and contrast, and colour effects which can all help to make the running text more readable against either background images, graphics, or patterns.

Apply one or multiple filters using the same CSS filter syntax I demonstrated in a previous issue:

main { backdrop-filter: brightness(25%); } main { backdrop-filter: brightness(25%) contrast(50%); }

backdrop-filter is part of the Filter Effects Module Level 2 specification. It already has solid support in contemporary browsers, although some still require the Webkit vendor prefix:

main div { -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }

NB: Smashing members have access to a beautifully designed PDF of Andy’s Inspired Design Decisions magazine and full code examples from this article. You can also buy the PDF and examples from this along with every other issue from Andy’s website.

Read More From The Series Smashing Editorial (vf, ra, yk, il)
Catégories: Programmation

Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography

lun, 04/13/2020 - 12:00
Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography Inspired Design Decisions With Herb Lubalin: Typography Can Be As Exciting As Illustration And Photography Andrew Clarke 2020-04-13T10:00:00+00:00 2020-04-13T12:35:19+00:00

While good use of type helps people to read, great typography can do so much more. Typography can eloquently articulate an idea and colourfully communicate a message in ways which are as powerful as any illustration or photograph.

I’m someone who loves cinema as much as I admire typography. Few things inspire me as much as seeing movie poster typography which either evokes the atmosphere of a film and adds to the telling of its story.

 Pulp Fiction by Indika Entertainment Advertising. Once Upon a Time in Hollywood by BLT and Steve Chorney. Vertigo by Saul Bass. West Side Story by Joseph Caroff. From left: Pulp Fiction by Indika Entertainment Advertising. Once Upon a Time in Hollywood by BLT and Steve Chorney. Vertigo by Saul Bass. West Side Story by Joseph Caroff. (Large preview)

More recently, typography in Quentin Tarantino’s film posters perfectly reflects the atmosphere and character of his movies. In Pulp Fiction, the title’s Aachen Bold typeface is as hardboiled as the film itself. For Once Upon a Time in Hollywood, although the typesetting of the iconic sign deviates from reality as much as other parts of the film, the poster conjures up the spirit of Hollywood.

Saul Bass is possibly the best-known graphic designer of his era and for 1950s and ’60’s Hollywood he created movie posters which are as recognisable as the sign itself. For his poster design for Hitchcock’s Vertigo in 1958, Bass used hand-cut typography which evokes German expressionist films of the 1920s. In 1960, Bass’s slashed title typography for Pyscho — again for Alfred Hitchcock — is both clever and obvious. While Saul Bass is often incorrectly credited with designing one of my favourite film posters from West Side Story, — Bass did design the title sequence — the poster was actually designed by Joseph Caroff who also created James Bond’s famous 007 logo.

Although we don’t yet have the same control over typography on the web as we do in print, new file formats, font delivery services, and web fonts have meant far more typographic flexibility than we had ten years ago. Typography controls in CSS have helped us be more creative with type too. On top of basic font style properties, we can now reliably fine-tune OpenType figures, hyphenation, ligatures, and even kerning.

It’s rare to find such creative uses for type online, studying the work of graphic designers and talented typographers can open our eyes to what we can achieve using today’s type technologies. One of my personal favourite designers and typographers is Herb Lubalin, and learning about him and his work has transformed my own approach to typography.

Read More From The Series Inspired By Herb Lubalin

Herb Lubalin was an American graphic designer who spent his career designing everything from advertising, posters, and even postage stamps. He was fascinated by the look of words and how typographic design can make them sound. Lubalin understood how by combining art, copy, and typography, graphic designers add conviction when communicating messages. He said:

“The better people communicate, the greater will be the need for better typography-expressive typography.”

— Herb Lubalin

Having narrowly passed the entrance exam to the Cooper Union art school in New York, Herbert (Herb) Lubalin was fired from his first job as a graphic artist for asking for a $2 per week raise. In pre-war American advertising agencies, the job of a layout artist was simply to place headlines, copy, and images into available space, but that changed after WW2 with an influx of immigrant designers from Europe. They included Austrian Herbert Bayer, Russian Mehemed Fehmy Agha, and Belarusian Alexey Brodovitch.

U&lc (Uppercase and lowercase) magazine by Herb Lubalin. (Large preview)

These designers imported new processes which brought art directors, layout artists, and writers together to form the creative teams made popular by the famous advertising creative director Bill Bernbach in the 1960s and 1970s.

In 1945, Lubalin became art director at Sudler & Hennessey — a creative studio which specialised in the pharmaceutical industry — where he led a team of designers, illustrators, and photographers. The process which Lubalin established first at Sudler & Hennessey and from 1964 in his own studio is fascinating. He drove the design process by making “tissues” — pen and ink sketches which established the spacial arrangement of its elements — and detailed notes on typographic designs including typeface choices, sizes, and weights.

Fact magazine by Herb Lubalin. (Large preview)

At the start of any new project, Lubalin began by sketching arrangements of headlines, copy, and images onto tissue paper. Then, he’d lay another tissue on top to refine his ideas, then another, and another, to rapidly develop his design. After his assistants recovered discarded tissues from the floor or trash, they became collectors’ items.

Lubalin was an obsessive perfectionist about typography. For “Let’s talk type” — a trade advertisement for Sudler & Hennessey — Lubalin precisely placed the only paragraph. This copy sits perfectly on the baseline alongside the word “let” and its size and leading allow for the descender from the letter “y” above.

From left: Trade press advertisement. The fourth of July means picnics… Announcement of Avant Garde’s anti-war poster competition by Herb Lubalin. (Large preview)

Lubalin was equally as precise about the placement of text in a poster which announced the Avant Garde anti-war poster competition. He would frequently take a scalpel blade to type, adjusting the spacing between letters and altering the height of ascenders and descenders to fit his designs. Letters in the headline for “No More War” are precisely sized and aligned. The tracking of the uppercase blue standfirst creates a block of copy which perfectly fits into its space.

In “The fourth of July means picnics…” Lubalin used perspective to represent the road ahead. This meant considering the tracking of every line of text, sometimes altering words to fit the design. Working with Lubalin’s designs wasn’t easy, and as one of his assistants later described:

“To make everything line up, you’ve got to do it over and over again, and then, if the client alters the text, you’ve got to redo the whole thing. To him (Lubalin,) it was worth it. How long it took or how much it cost wasn’t as important to him as it was to other designers.”

Because of his relentless conviction as well as his talent, Lubalin went on to become one of the most celebrated graphic designers and typographers of the twentieth century. There’s plenty we can learn from how he approached his work and his conviction that design can compellingly communicate.

Various designs by Herb Lubalin. (Large preview)

There are two books on Herb Lubalin and his work you should add to your collection. “Herb Lubalin: Art Director, Graphic Designer and Typographer” (1985) by Gertrude Snyder and Alan Peckolick is out of print, but good copies are available on eBay. Better still is “Herb Lubalin: American Graphic Designer” (2013) by Adrian Shaughnessy and published by Unit Editions. A limited edition of 2000, Shaughnessy’s book features hundreds of examples of Lubalin’s work.

Pre-Formatting Headlines

Headlines are a perfect place to begin being more adventurous with type. Expressive typography needn’t need fancy fonts. You can create an eye-catching headline by using different styles and weights found within many everyday font families. Look for extended families like Montserrat — designed by Julieta Ulanovsky and available on Google Fonts — with its variety of weights ranging from thin and light, to extra-bold, and even black.

For this first Herb Lubalin inspired design, my headline uses black and light weights from this sans-serif typeface. Negative tracking (letter-spacing) and tight leading (line-height) combine to create a block of type which demands attention.

Black and light weights, negative tracking and tight leading. (Large preview)

In the past, developing headlines like this involved hard-coding the design into your HTML by adding breaks between individual words, like this:

<h1><strong>UK’s <br> best-<br> selling <br> car</strong> <br> during <br> the <br> 1970s</h1>

Other times, you might use wrap each word with an inline span element and then change its display property to block:

<h1><strong><span>UK’s</span> <span>best-</span> <span>selling</span> <span>car</span></strong> <span>during</span> <span>the</span> <span>1970s</span></h1>

Instead of these presentational elements, I add explicit line breaks in my HTML:

<h1><strong>UK’s best- selling car</strong> during the 1970s</h1>

Browsers ignore anything more than a single space between words, so on small viewports, this headline reads like a sentence. I only need foundation styles which style its colours, size, and weights, as well as the negative tracking and tight leading which makes this headline distinctive:

h1 { font-size: 6vmax; font-weight: 300; line-height: .75; letter-spacing: -.05em; text-transform: uppercase; color: #fff; } h1 strong { font-weight: 600; color: #bd1f3a; }

Whereas HTML’s pre element respects pre-formatted text and presents it exactly as written in a document, the CSS white-space property enables similar results without sacrificing semantics. Of the six available white-space values, these are the four I use these most often:

  1. white-space: normal;
    Text fills line-boxes and breaks as required
  2. white-space: nowrap;
    The text won’t wrap, and it may overflow its container
  3. white-space: pre;
    Explicit line-breaks are respected, text breaks with new lines and br elements
  4. white-space: pre-wrap;
    White-space is respected, but the text will also wrap to fill line-boxes

I only need the effects of the white-space property on larger viewports, so I isolate it with a media query:

@media (min-width: 64em) { h1 { white-space: pre; } }

Using several styles from one font family adds visual interest. My Lubalin-inspired design incorporates light, bold, and black weights, plus condensed and regular styles of this sans-serif typeface to produce a variety of text-treatments.

Several paragraph styles from one font family adds visual interest. (Large preview)

First, I need two structural elements to accomplish my design, main and aside:

<main>…</main> <aside>…</aside>

While the main element includes my headline and running text, the aside contains four images in a division and five articles about versions of the classic Cortina:

<aside> <div> <img src="img-1.svg" alt="Ford Cortina Mark 1 front profile"> <img src="img-2.svg" alt="Ford Cortina Mark 3 rear"> <img src="img-3.svg" alt="Ford Cortina Mark 4 front"> <img src="img-4.svg" alt="Ford Cortina Mark 5 rear profile"> </div> <article>…</article> <article>…</article> <article>…</article> <article>…</article> <article>…</article> </aside>

First, I specify the styles of paragraphs in each of my articles using pseudo-class selectors. Each paragraph uses a different combination of font styles and weights, with mixed-case and uppercase letters:

article:nth-of-type(1) p { font-family: 'light'; text-transform: uppercase; } article:nth-of-type(2) p { font-family: 'bold-condensed'; font-weight: 600; text-transform: uppercase; } article:nth-of-type(3) p { font-family: 'bold-condensed'; font-weight: 600; } article:nth-of-type(4) p { font-family: 'light'; text-transform: uppercase; } article:nth-of-type(5) p { font-family: 'bold-condensed'; font-weight: 600; }

With those foundation styles in place for every screen size, I introduce layout to the aside element which will be visible on for medium-size screens. For layouts like this, where elements don’t overlap, I often grid-template-areas for their simplicity. This design has nine grid areas. While I could give these areas names which describe the content I’ll place into them — for example, “mark-1” — instead I use letters which makes moving items around my grid a little easier:

@media (min-width: 48em) { aside { display: grid; grid-template-areas: "a b c" "d e f" "g h i"; grid-gap: 1.5rem; } }

I need to place the four images into my template areas, and not the division which contains them. I change the display property of that element to contents, which effectively removes it from the DOM for styling purposes:

aside div { display: contents; }

I place those images using area names. Moving them into another area only involves referencing a different area name and no change to their order in my HTML:

aside img:nth-of-type(1) { grid-area: a; } aside img:nth-of-type(2) { grid-area: e; } aside img:nth-of-type(3) { grid-area: g; } aside img:nth-of-type(4) { grid-area: i; }

Then, I place articles into the five remaining areas to complete my layout:

aside article:nth-of-type(1) { grid-area: b; } aside article:nth-of-type(2) { grid-area: c; } aside article:nth-of-type(3) { grid-area: d; } aside article:nth-of-type(4) { grid-area: f; } aside article:nth-of-type(5) { grid-area: h; }

On small and medium-size screens, the main and aside elements stack vertically in the order they appear in my HTML. The extra space available in larger viewports allows me to place them side-by-side so visual weight is balanced across both sides of a screen. First, I apply a five-column symmetrical grid to the body element:

@media (min-width: 64em) { body { display: grid; grid-template-columns: repeat(5, 1fr); } }

Then, I place both main and aside elements using line numbers. This creates an asymmetrical design with a column of white space between my main content and the articles which support it:

main { grid-column: 1; } aside { grid-column: 3 / -1; } } Reordering And Rotating

CSS Grid is now the best tool to use for implementing inspired layouts, and its powerful properties are also useful for developing intricate typographic designs.

Left: Castrated. Book jacket designed by Herb Lubalin. Right: Intricate header design developed using CSS Grid and Flexbox. (Large preview)

My header contains a headline followed by two paragraphs and their order in HTML means they make sense when read without any styling applied:

<header> <h1>Cortina</h1> <p>UK’s best-selling car</p> <p>From <span>1962–1983</span></p> </header>

To begin this design, I add foundation styles for both elements, setting their alignment, colours, and sizes:

header h1, header p { margin: 0; text-align: center; } header h1 { font-size: 10vmax; color: #ebc76a; line-height: 1; } header p { font-size: 4vmax; line-height: 1.1; text-transform: uppercase; }

I ordered my HTML for a semantic sentence structure, rather than any visual presentation, so to allow me to reorder the elements visually, I add Flexbox properties to my header and a flex-direction value of column:

header { display: flex; flex-direction: column; }

By default, elements appear in the order they occur in HTML, but in my design, the last paragraph in this header appears first, above the headline.

The default order value for all elements is 0, so to change the position of this paragraph without altering my HTML, I add a negative value of -1, which places it at the top:

header p:last-of-type { order: -1; }

My design for medium-size screens includes two large bands of background colours, developed using a CSS gradient. So next, I change the foreground colours of my headline and paragraphs to contrast them against this new background:

@media (min-width: 48em) { body { background-image: linear-gradient(to right, #0a0a08 0%, #0a0a08 50%, #fff 50%, #fff 100%); } header h1 { color: #fff; } header p { color: #ebc76a; } }

The unusual alignment of the three elements in this header is possible by combining CSS Grid with Flexbox. Although it might not be obvious at first, I place the headline and paragraphs in this header onto a four-column symmetrical grid. Leaving one column in the first and last rows empty creates a dynamic diagonal which adds interest to this header:

@media (min-width: 64em) { header { display: grid; grid-template-columns: repeat(4, 1fr); align-items: start; padding-top: 0; } } A dynamic diagonal which adds interest to this header. (Large preview)

My headline spreads across all four columns:

header h1 { grid-column: 1 / -1; }

While the first — which appears at the bottom of my header — leave the first column empty:

header p:first-of-type { grid-column: 2 / -1; }

The final paragraph—now placed at the top of the header — spans the first three columns, leaving a space on the left:

header p:last-of-type { grid-column: 1 / 4; }

It’s unusual to see rotated text elements on the web, but when you do, they’re often memorable and always a nice a surprise. I want my headline rotated anti-clockwise, so I add a transform which rotates it negatively by 30 degrees and moves it vertically down by 150px:

header { transform: rotate(-30deg) translateY(150px); transform-origin: 0 100%; }

transform-origin specifies the point around which transforms happen. You can choose an origin in the centre or any of the four corners of an element — top-left (0 0), top-right (100% 0), bottom-right (100% 100%) or bottom-left (0 100%). You might also specify an origin in pixels, em, or rem units.

The results of 50% 50%, 0 0, 100% 0, 100% 100%, and 0 100% transform-origin values. (Large preview)

For an extra element of surprise, I add a subtle transition to that transform and reduce the amount of rotation when someone passes their cursor over my headline:

header { transition: transform .5s ease-in; } header:hover { transform: rotate(-25deg) translateY(150px); } CSS Grid is now the best tool to use for implementing inspired layouts. (Large preview) Combining Header Elements Left: Graphis Annual Report. Center: American Showcase references USA flag. Right: My design references the United Kingdom’s Union flag. (Large preview)

In my next Lubalin-inspired design, I combine an ordered list of Cortina models with a multi-coloured headline to make a powerful statement with this header:

<header> <div> <h1>…</h1> <ol>…</ol> </div> </header>

This headline includes three lines of text. Whereas I previously avoided using additional elements, to style these lines differently I need three inline span elements:

<h1> <span>Best</span> <span>Selling</span> <span>Cortina</span> </h1>

The most semantic choice to mark up my list of Cortina models and the years during which they were manufactured, is an ordered list. To strongly emphasise each model name, I enclose them within strong elements, which deliver semantic value as well as a bold appearance from default browser styles:

<ol> <li><strong>Mark I</strong> 1962–1966</li> <li><strong>Mark II</strong> 1966–1970</li> <li><strong>Mark III</strong> 1970–1976</li> <li><strong>Mark IV</strong> 1976–1979</li> <li><strong>Mark V</strong> 1979–1983</li> </ol>

For small viewports, I need only a few foundation styles. The large font size and minimal leading create a solid block of text. Then, I change the span element’s display value from inline to block and use pseudo-class selectors to change the foreground colours of the first and third lines:

h1 { font-size: 18vmin; line-height: .9; color: #fff; } h1 span { display: block; } h1 span:nth-of-type(1) { color: #ba0e37; } h1 span:nth-of-type(3) { color: #31609e; }

I want items in my ordered list to form a two-column symmetrical grid where each column occupies an equal amount of available space:

ol { list-style-type: none; display: grid; grid-template-columns: 1fr 1fr; }

Then, I tighten the items’ leading and add a solid blue border to the bottom of all but the last list-item:

li { display: inline-block; line-height: 1.2; } li:not(:last-of-type) { border-bottom: 1px solid #31609e; }

Conveniently, there’s no need to specify column or row numbers for each list-item because CSS Grid arranges them automatically because of normal flow. To add greater emphasis, I change the strong elements’ display values to block and set them in uppercase:

li strong { display: block; font-size: 1.266rem; font-weight: 600; text-transform: uppercase; } A multi-coloured headline combined with an ordered list of Cortina models. (Large preview)

Centring an element both horizontally and vertically used to be tricky, but thankfully, Flexbox has made this alignment trivial to implement. Flexbox has two axes — main axis and cross axis — which change direction if you change the default flex-direction value from a row.

The flex-direction of my header remains row, so I align-items centre on the cross axis (vertical,) then justify-content centre along the main axis (horizontal:)

@media (min-width: 48em) { header { display: flex; align-items: center; justify-content: center; } }

With content now entered in the header, I apply a grid which contains three columns and two rows. Their dimensions will be defined by their content and will resize automatically:

header > div { display: grid; grid-template-columns: repeat(3, min-content); grid-template-rows: auto auto; }

The three multi-coloured lines in the headline are the foundation for this header design. I want to place them into specific columns and rows in this grid, so I add display: contents; to the headline:

h1 { display: contents; }

Then, I place that multi-coloured text into columns and rows using line numbers:

h1 span:nth-of-type(1) { grid-column: 1; grid-row: 2; } h1 span:nth-of-type(2) { grid-column: 2; grid-row: 1 / 3; } h1 span:nth-of-type(3) { grid-column: 3; grid-row: 1 / 3; }

I want the text in my header to appear vertical, so I rotate each span clockwise by 180 degrees, then change their writing-mode to vertical left–right:

h1 span { transform: rotate(180deg); writing-mode: vertical-lr; }

The headline and ordered list in my design form a solid block. To pack these elements tightly together, I change the list’s display property from grid to block. Then, I align content in each list-item to the right, so they sit on my headline’s baseline:

ol { display: block; } li { text-align: right; } SVG And Text

It’s taken me a long time to appreciate SVG and to become familiar with how to get the best value from it, and I’m still learning. SVG is capable of producing far more than basic shapes, and one of its most exciting features is the text element.

Like HTML text, SVG text is accessible and selectable. It’s also infinitely styleable by using clipping paths, fills including gradients, filters, masks, and strokes. Adding text to SVG is just like including it in HTML, using the text element. Only content inside these text elements is rendered by browsers, and they ignore anything outside them. You can add as many text elements as you need, but my next headline needs only one:

<svg> <text>’70’s best-selling Cortina British car</text> </svg>

SVG includes a set of properties and attribute values which can be applied to text. Many SVG properties — like letter and word spacing, and text-decoration — are also in CSS. But it’s styling features unique to SVG which help to make SVG text so appealing.

For example, textLength sets the width of rendered text, which will shrink and stretch to fill the space depending on the lengthAdjust value you choose.

  • textLength
    The text will be scaled to fit. Set textLength in percentages or use any numerical values. I prefer to use text-based units, em or rem.
  • lengthAdjust
    Defines how the text will be compressed or stretched to fit the width defined in the textLength attribute.

When used directly on a text element, SVG properties act the same as inline styles:

<svg> <text textLength="400">’70’s best-selling Cortina British car</text> </svg>

But just as with inline styles, the best value is achieved by styling SVG elements using CSS, whether in an external stylesheet or embedded in HTML. You can even use a style element in an external SVG file or a block of SVG included alongside HTML:

<svg> <text class="display">’70’s best-selling Cortina British car</text> </svg> <style> .display { font-size: 100px; font-family: 'black-extended'; font-weight: 600; letter-spacing: -1px; text-anchor: middle; text-transform: uppercase; } </style>

HTML has its span element and SVG includes a similar element which is useful for separating text into smaller elements so they can be styled uniquely. For this headline, I divide the content of the text element between six tspan elements:

<text> <tspan>’70’s</tspan> <tspan>best-</tspan> <tspan>selling</tspan> <tspan>Cortina</tspan> <tspan>British</tspan> <tspan>car</tspan> </text>

By splitting my headline into multiple elements, I’m able to style each individual word. I can even position them precisely within my SVG, according to the baseline or even relative to each other.

  • x is the horizontal starting point for the text baseline;
  • y is the vertical starting point for the text baseline;
  • dx shifts text horizontally from a previous element;
  • dy shifts text vertically from an earlier element.
(Large preview)

For my headline, I position the first tspan element 80px from the top, then each subsequent element appears 80px below it:

<text> <tspan y="80">’70’s</tspan> <tspan dy="80">best-</tspan> <tspan dy="80">selling</tspan> <tspan dy="80">Cortina</tspan> <tspan dy="80">British</tspan> <tspan dy="80">car</tspan> </text>

tspan elements are useful for precise positioning and individual styling, but they’re not without accessibility concerns. Assistive technology pronounce tspan elements as individual words and even spell them when a tspan wraps a single letter. For example, a screen reader will pronounce this series of tspan elements:

<tspan>C</tspan> <tspan>o</tspan> <tspan>r</tspan> <tspan>t</tspan> <tspan>i</tspan> <tspan>n</tspan> <tspan>a</tspan>

As:

“C”, “o”, “r”, “t”, “i”, “n”, “a”

We shouldn’t inconvenience people who use assistive technology or worse make our content inaccessible because of our styling choices. So avoid using tspan unnecessary and never for single letters.

Stroking Text With CSS And SVG

Adding a stroke often helps legibility when text is placed in front of a background image, and it can also make subtle and striking results. You won’t find an official way to stroke text in any CSS specification. But there is an experimental property which uses a Webkit vendor prefix and is widely supported by contemporary browsers.

(Large preview)

text-stroke is shorthand for two properties: text-stroke-color and text-stroke-width. For my stroked headline, I first set foundation typography styles for family, size, and weight, then adjust the leading and tracking:

h1 { font-size: 100px; font-family: 'black-extended'; font-weight: 600; letter-spacing: -6px; line-height: .8; color: #fff; }

Then I apply text-stroke and add the text-fill-color property with a value of transparent which overrides the white foreground colour:

h1 { /* -webkit-text-stroke-color: #fff; */ /* -webkit-text-stroke-width: 5px; */ -webkit-text-stroke: 5px #fff; -webkit-text-fill-color: transparent; }

Although text-stroke is an experimental property and not in a W3C specification, now that browsers have implemented it, there’s little chance of it being removed. But if you’re still concerned about supporting a legacy browser, consider using a feature query to test for text-stroke support and provide an appropriate fallback for them.

SVG has stroke properties too, plus a few options which aren’t available in CSS. If you need more options and the widest browser support, SVG is the answer. My SVG header includes six tspan elements:

<svg> <text> <tspan>’70’s</tspan> <tspan>best-</tspan> <tspan>selling</tspan> <tspan>Cortina</tspan> <tspan>British</tspan> <tspan>car</tspan> </text> </svg>

On top of foundation typography styles, I add the equivalent SVG properties for text-stroke-color and text-stroke-width. I also reduce the opacity of my stroke, which is an option unavailable in CSS:

text { stroke: #fff; stroke-width: 1.5px; stroke-opacity=".8"; } SVG stroke-dasharray adds a border style not possible using CSS alone. (Large preview)

SVG includes other properties which fine-tune aspects of a stroke. Unlike CSS, SVG strokes can be dashed using the stroke-dasharray property. Alternate values define filled areas and blank areas, so the dashes around my headline text are one unit filled, then ten units blank:

text { stroke-dasharray: 1, 10; }

Should you need more complex patterns, add extra numbers to the pattern, so a stroke-dasharray value of 1, 10, 1 results in a dashed stroke which is 1 (filled,) 10 (blank,) 1 (filled,) 1 (blank,) 10 (filled,) 1 (blank,) and repeats.

My large-screen design, inspired by Herb Lubalin. (Large preview) stroke-linecap defines how ends of lines appear in SVG. Left: butt. Middle: round. Right: square. (Large preview) stroke-linejoin defines how lines join in SVG. Left: bevel. Middle: round. Right: miter. (Large preview) Optimize SVG Accessibility

CSS typography controls are now more powerful than ever, but there are occasions when a design calls for more than styled HTML text. Image replacement techniques have fallen out of fashion, but SVG — whether in an external file or inline within HTML — can deliver scalable text effects. SVG can also be useful for overall performance when optimised well and can be made accessible.

This header contains two typefaces. One is Magehand, a decorative retro-style script by Indonesian type designer Arief Setyo Wahyudi. The other is Mokoko, a slab serif by London-based Dalton Maag which is available in seven weights from thin to black.

Embedding these two fonts in both Web Open Font Format (WOFF) and WOFF2 formats would add over 150kb to my page. Whereas, by converting these fonts to outlines in a graphics editor and delivering the header as an optimised SVG image would add only 17kb.

The SVG image in my header contains three paths:

<svg xmlns="http://www.w3.org/2000/svg"> <path id="top">…</path> <path id="bottom">…</path> <path id="middle">…</path> </svg> (Large preview)

The order of these paths matters, because just as in HTML, elements are stacked in the order they’re written. SVG includes a set of properties and attribute values which can be applied to any element. I use the fill property to colour each path in my header:

<path fill="#bd1f3a">…</path> <path fill="#31609e">…</path> <path fill="#fff">…</path>

For an even more stylish effect, I can define a linear gradient with two colour stops, and reference that to fill my decorative script:

<defs> <linearGradient id="cortina" gradientTransform="rotate(90)"> <stop offset="0%" stop-color="#bd1f3a" /> <stop offset="100%" stop-color="#31609e" /> </linearGradient> </defs> <path fill="#fff">…</path> <path fill="#fff">…</path> <path fill="url('#cortina')">…</path>

SVG files are frequently smaller than bitmap images or the combined size of several font files, but they nevertheless need careful optimisation to achieve the best performance.

Every element, handle, and node increases the size of an SVG file, so replace paths with basic shapes like circles, ellipses, or rectangles where possible. Simplify curves to reduce the number of nodes and use fewer handles. Popular graphic software like Adobe Illustrator, Affinity Designer, and Sketch export files bloated by unoptimised elements and unnecessary metadata. But, tools like SVGOMG by developer Jake Archibald will strip away unneeded items and can often reduce SVG file size substantially.

SVG images which contain text outlines can also be made accessible by using alternative text and ARIA properties. When linking to an external SVG file, add alternative text as you should with any non-decorative image:

<img src="header.svg" alt="Cortina. ’70s best-selling British car">

The best way to help people who use assistive technology is to embed SVG into HTML. Add an ARIA role and a descriptive label and screen readers will treat the SVG as a single element and read the label description aloud:

<svg role="img" aria-label="Cortina. ’70s best-selling British car"> … </svg>

Adding a title element helps assistive technology to understand the difference between several blocks of SVG, but this title won’t be displayed in a browser:

<svg> <title>Cortina. ’70s best-selling british car</title> </svg>

When there are several blocks of SVG in a document, give each one a unique ID and add that to its title:

<svg> <title id="header">…</title> </svg>

ARIA has several attributes which help SVG accessibility. When SVG is purely decorative and has no semantic value, hide it from assistive technology by adding an aria-hidden attribute:

<svg aria-hidden="true"> … </svg>

For my design, I use SVG in place of an HTML heading. To replace the missing semantics for assistive technology, use an ARIA role attribute and a value of heading. Then add a level attribute which matches the missing HTML:

<svg role="heading" aria-level="1"> … </svg> Clipping Type

The CSS background-clip property defines whether an element’s background extends underneath its border-box, padding-box, or content-box, according to the CSS box model:

  • border-box
    Background extends to the outside edge of the border (and underneath the border).
  • padding-box
    Background extends to the outside edge of the padding only.
  • content-box
    The background is rendered within (clipped to) the content box only.
background-clip. Left: border-box. Middle: padding-box. Right: content-box. (Large preview)

But, there’s one more value which offers many more opportunities for inspiring typography. Using text as a value for background-clip clips an element’s background to the space occupied by the text it contains.

Left: Anti-war poster for American Institute of Graphic Arts exhibition. Designed by Herb Lubalin. Right: The background-clip text value clips an element’s background to the space occupied by the text it contains. (Large preview)

In my next example, the brake disk background image is visible only where there’s text in the headline. When my headline includes more content or its text size increases, more of that background image will be visible:

h1 { background-image: url(pattern.svg); background-clip: text; -webkit-background-clip: text; color: transparent; }

You can apply the text value for background-clip to any element except the :root, HTML. As support forbackground-clip is limited, I use a feature query which delivers those styles only to supporting browsers:

h1 { color: #fff; } @supports (background-clip: text) or (-webkit-background-clip: text) { h1 { background-color: #fff; background-image: url(pattern.svg); background-position: 50% 100%; background-repeat: no-repeat; background-size: 50%; background-clip: text; -webkit-background-clip: text; color: transparent; } }

Inspired by Lubalin, I want to place images inside the letters of my next headline, and the SVG image element allows me to do just that.

Left: Trade press advertisement designed by Herb Lubalin. Right: Images inside each letter of my SVG headline. (Large preview)

As this SVG image represents a heading, I add alternative text plus an ARIA role and level to ensure it remains accessible:

<img src="header.svg" alt="Cortina" role="heading" aria-level="1">

In SVG, the defs element stores graphical objects which can be referenced from elsewhere in a file. These include the patterns which contain my images and I add one for each letter:

<svg> <defs> <pattern id="letter-c">…</pattern> <pattern id="letter-o">…</pattern> <pattern id="letter-r">…</pattern> … </defs> … </svg>

Content in the defs element is not rendered directly and to display it I reference them with either a use attribute or url. My SVG contains one path for each of the seven letters in the word “Cortina,” and I fill each path with a pattern using its unique ID:

<svg> <defs>…</defs> <path fill="url(#letter-c)">…</path> <path fill="url(#letter-o)">…</path> <path fill="url(#letter-r)">…</path> … </svg> Images inside each letter of my SVG headline. (Large preview)

Image elements allow either bitmap or vector images to be rendered within an SVG. My design incorporates three car part blueprint images which I link to using a standard href attribute:

<defs> <pattern id="letter-c" width="100%" height="100%"> <image href="pattern-c.png" height="250" width="250"/> </pattern> … </defs>

These three car part pattern images fill each letter, and the result is a striking headline design which demands attention.

Combining Techniques

There’s no doubt that Herb Lubin had a masterful ability to make type talk. For this final Lubin-inspired example, I put together the techniques I’ve demonstrated to create a compelling design for this classic ’70s Ford.

Left: Trade press advertisement designed by Herb Lubalin. Right: Main content placed over a text-based SVG background image. (Large preview)

To develop this design, I need two structural elements which should be very familiar by now, a main and aside:

<main>…</main> <aside>…</aside>

My main element contains a header element with an SVG headline followed by a division which includes my running text. I add an ARIA role and level to my headline to ensure its SVG text is accessible:

<main> <header> <svg role="heading" aria-level="1">…</svg> </header> <div>…</div> </main>

To serve a full image to small screens and half to larger viewports, I use a picture element and a minimum width media query:

<aside> <picture> <source srcset="half.svg" media="(min-width: 74em)"> <img src="full.svg" alt="Ford Cortina"> </picture> </aside>

Lubalin’s designs are often energetic, so to fill my main element with energy, I apply grid properties and use three columns and five rows to develop an asymmetrical layout.

main { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: repeat(5, 1fr); }

This design is dominated by an outline of the charismatic Cortina, and a text-based background image which covers the main element. I scale this SVG to fill the element’s background, and change the background-origin so it appears only behind the content and not its border or padding:

main { background-image: url(main.svg); background-origin: content-box; background-position: top right; background-repeat: no-repeat; background-size: 100% 100%; }

Leaving columns around my header and text division empty creates negative space which helps to lead someone’s eye around the composition. The header occupies the first two of my three columns while the division fills the last two:

header { grid-column: 1 / 3; grid-row: 2 / 3; } main div { grid-column: 2 / 4; grid-row: 3 / 6; }

One of the benefits of using the SVG text element is the ability to position text according to its baseline or relative to each elements. My headline SVG includes two text elements for the name of this car, and a third for the period it was manufactured. I want to place this final text element precisely 250px from the left and 60px from the top of my SVG:

<svg> <text x="0" y="60">Ford</text> <text x="0" dy="70">Cortina</text> <text x="250" y="60">1962–1983</text> </svg> Left: My large-screen design, inspired by Herb Lubalin. Right: To serve a full Cortina image to small screens and only the right half to larger viewports, I use a picture element. (Large preview)

This dazzling design becomes more memorable on larger viewports when the text-based SVG background image and my Cortina outline fit alongside each other. I apply a two-column symmetrical grid to the body element:

@media (min-width: 74em) { body { display: grid; grid-template-columns: [main] 1fr [aside] 1fr; } }

Then, I place the main and aside elements onto my grid using line names:

main { grid-column: main; } aside { grid-column: aside; } }

On the web, inspiring typography should be attractive and readable, but the readability of running text can easily be affected by the background behind it.

The backdrop-filter applies CSS filter effects to elements behind the text. These filters include blur, brightness and contrast, and colour effects which can all help to make the running text more readable against either background images, graphics, or patterns.

Apply one or multiple filters using the same CSS filter syntax I demonstrated in a previous issue:

main { backdrop-filter: brightness(25%); } main { backdrop-filter: brightness(25%) contrast(50%); }

backdrop-filter is part of the Filter Effects Module Level 2 specification. It already has solid support in contemporary browsers, although some still require the Webkit vendor prefix:

main div { -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }

NB: Smashing members have access to a beautifully designed PDF of Andy’s Inspired Design Decisions magazine and full code examples from this article. You can also buy the PDF and examples from this along with every other issue from Andy’s website.

Read More From The Series Smashing Editorial (vf, ra, yk, il)
Catégories: Programmation

Getting Started With The React Hooks API

ven, 04/10/2020 - 11:30
Getting Started With The React Hooks API Getting Started With The React Hooks API Shedrack Akintayo 2020-04-10T09:30:00+00:00 2020-04-10T10:05:42+00:00

When React 16.8 was released officially in early February 2019, it shipped with an additional API that lets you use state and other features in React without writing a class. This additional API is called Hooks and they’re becoming popular in the React ecosystem, from open-sourced projects to being used in production applications.

React Hooks are completely opt-in which means that rewriting existing code is unecessary, they do not contain any breaking changes, and they’re available for use with the release of React 16.8. Some curious developers have been making use of the Hooks API even before it was released officially, but back then it was not stable and was only an experimental feature. Now it is stable and recommended for React developers to use.

Note: We won’t be talking about React or JavaScript in general. A good knowledge of ReactJS and JavaScript will come in handy as you work through this tutorial.

What Are React Hooks?

React Hooks are in-built functions that allow React developers to use state and lifecycle methods inside functional components, they also work together with existing code, so they can easily be adopted into a codebase. The way Hooks were pitched to the public was that they allow developers to use state in functional components but under the hood, Hooks are much more powerful than that. They allow React Developers to enjoy the following benefits:

  • Improved code reuse;
  • Better code composition;
  • Better defaults;
  • Sharing non-visual logic with the use of custom hooks;
  • Flexibility in moving up and down the components tree.

With React Hooks, developers get the power to use functional components for almost everything they need to do from just rendering UI to also handling state and also logic — which is pretty neat.

Motivation Behind The Release Of React Hooks

According to the ReactJS official documentation, the following are the motivation behind the release of React Hooks:

  • Reusing stateful logic between components is difficult.
    With Hooks, you can reuse logic between your components without changing their architecture or structure.
  • Complex components can be difficult to understand.
    When components become larger and carry out many operations, it becomes difficult to understand in the long run. Hooks solve this by allowing you separate a particular single component into various smaller functions based upon what pieces of this separated component are related (such as setting up a subscription or fetching data), rather than having to force a split based on lifecycle methods.
  • Classes are quite confusing.
    Classes are a hindrance to learning React properly; you would need to understand how this in JavaScript works which differs from other languages. React Hooks solves this problem by allowing developers to use the best of React features without having to use classes.
The Rules Of Hooks

There are two main rules that are strictly to be adhered to as stated by the React core team in which they outlined in the hooks proposal documentation.

  • Make sure to not use Hooks inside loops, conditions, or nested functions;
  • Only use Hooks from inside React Functions.
Basic React Hooks

There are 10 in-built hooks that was shipped with React 16.8 but the basic (commonly used) hooks include:

These are the 4 basic hooks that are commonly used by React developers that have adopted React Hooks into their codebases.

useState()

The useState() hook allows React developers to update, handle and manipulate state inside functional components without needing to convert it to a class component. Let’s use the code snippet below is a simple Age counter component and we will use it to explain the power and syntax of the useState() hook.

function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }

If you’ve noticed, our component looks pretty simple, concise and it’s now a functional component and also does not have the level of complexity that a class component would have.

The useState() hook receives an initial state as an argument and then returns, by making use of array destructuring in JavaScript, the two variables in the array can be named what. The first variable is the actual state, while the second variable is a function that is meant for updating the state by providing a new state.

Our finished React app (Large preview)

This is how our component should look when it is rendered in our React application. By clicking on the “Increase my Age” button, the state of the age will change and the component would work just like a class component with state.

useEffect()

The useEffect() hook accepts a function that would contain effectual code. In functional components, effects like mutations, subscriptions, timers, logging, and other effects are not allowed to be placed inside a functional component because doing so would lead to a lot of inconsistencies when the UI is rendered and also confusing bugs.

In using the useEffect() hook, the effectual function passed into it will execute right after the render has been displayed on the screen. Effects are basically peeked into the imperative way of building UIs that is quite different from React’s functional way.

By default, effects are executed mainly after the render has been completed, but you have the option to also fire them when certain values change.

The useEffect() hook mostly into play for side-effects that are usually used for interactions with the Browser/DOM API or external API-like data fetching or subscriptions. Also, if you are already familiar with how React lifecycle methods work, you can also think of useEffect() hook as component mounting, updating and unmounting — all combined in one function. It lets us replicate the lifecycle methods in functional components.

We will use the code snippets below to explain the most basic way that we can by using the useEffect() hook.

Step 1: Define The State Of Your Application import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Just like we discussed in the previous section on how to use the useState() hook to handle state inside functional components, we used it in our code snippet to set the state for our app that renders my full name.

Step 2: Call The useEffect Hook import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({name: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surame}</h3> </div> ); }; export default App

We have now imported the useEffect hook and also made use of the useEffect() function to set the state of our the name and surname property which is pretty neat and concise.

You may have noticed the useEffect hook in the second argument which is an empty array; this is because it contains a call to the setFullName which does not have a list of dependencies. Passing the second argument will prevent an infinite chain of updates (componentDidUpdate()) and it’ll also allow our useEffect() hook to act as a componentDidMount lifecycle method and render once without re-rendering on every change in the tree.

Our React app should now look like this:

React app using the useEffect Hook (Large preview)

We can also use change the title property of our application inside the useEffect() function by calling the setTitle() function, like so:

import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({name: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surame}</h3> </div> ); }; export default App

Now after our application has rerendered, it now shows the new title.

Our finished project (Large preview) useContext()

The useContext() hook accepts a context object, i.e the value that is returned from React.createContext, and then it returns the current context value for that context.

This hook gives functional components easy access to your React app context. Before the useContext hook was introduced you would need to set up a contextType or a <Consumer> to access your global state passed down from some provider in a class component.

Basically, the useContext hook works with the React Context API which is a way to share data deeply throughout your app without the need to manually pass your app props down through various levels. Now, the useContext() makes using Context a little easier.

The code snippets below will show how the Context API works and how the useContext Hook makes it better.

The Normal Way To Use The Context API import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Let’s now break down the code snippet and explain each concept.

Below, we are creating a context called NumberContext. It is meant to return an object with two values: { Provider, Consumer }.

const NumberContext = React.createContext();

Then we use the Provider value that was returned from the NumberContext we created to make a particular value available to all the children.

function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }

With that, we can use the Consumer value that was returned from the NumberContext we created to get the value we made available to all children. If you have noticed, this component did not get any props.

function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Note how we were able to get the value from the App component into the Display component by wrapping our content in a NumberContext.Consumer and using the render props method to retrieve the value and render it.

Everything works well and the render props method we used is a really good pattern for handling dynamic data, but in the long run, it does introduce some unnecessary nesting and confusion if you’re not used to it.

Using The useContext Method

To explain the useContext method we will rewrite the Display component using the useContext hook.

// import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }

That’s all we need to do in order to display our value. Pretty neat, right? You call the useContext() hook and pass in the context object we created and we grab the value from it.

Note: Don’t forget that the argument that is passed to the useContext hook must be the context object itself and any component calling the useContext will always re-render when the context value changes.

useReducer()

The useReducer hook is used for handling complex states and transitions in state. It takes in a reducer function and also an initial state input; then, it returns the current state and also a dispatch function as output by the means of array destructuring.

The code below is the proper syntax for using the useReducer hook.

const [state, dispatch] = useReducer(reducer, initialArg, init);

It is sort of an alternative to the useState hook; it is usually preferable to useState when you have complex state logic that has to do with multiple sub-values or when the next state is dependent on the previous one.

Other React Hooks Available useCallback This hook returns a callback function that is memoized and that only changes if one dependency in the dependency tree changes. useMemo This hook returns a memoized value, you can pass in a “create” function and also an array of dependencies. The value it returns will only use the memoized value again if one of the dependencies in the dependency tree changes. useRef This hook returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will be available for the full lifetime of the component. useImperativeHandle This hook is used for customizing the instance value that is made available for parent components when using refs in React. useLayoutEffect This hook similar to the useEffect hook, however, it fires synchronously after all DOM mutations. It also renders in the same way as componentDidUpdate and componentDidMount. useDebugValue This hook can be used to display a label for custom hooks in the React Dev Tools. It is very useful for debugging with the React Dev Tools. Custom React Hooks

A “custom Hook” is a JavaScript function whose names are prefixed with the word use and can be used to call other Hooks. It also lets you to extract component logic into reusable functions; they are normal JavaScript functions that can make use of other Hooks inside of it, and also contain a common stateful logic that can be made use of within multiple components.

The code snippets below demonstrate an example of a custom React Hook for implementing infinite scroll (by Paulo Levy):

import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };

This custom Hook accepts two arguments which are start and pace. The start argument is the starting number of elements to be rendered while the pace argument is the subsequent number of elements that are to be rendered. By default, the start and pace arguments are set to 30 and 10 respectively which means you can actually call the Hook without any arguments and those default values will be used instead.

So in order to use this Hook within a React app, we would use it with an online API that returns ‘fake’ data:

import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;

The code above will render a list of fake data (userID and title) that make use of the infinite scroll hook to display the initial number of data on the screen.

Conclusion

I hope you enjoyed working through this tutorial. You could always read more on React Hooks from the references below.

If you have any questions, you can leave them in the comments section and I’ll be happy to answer every single one!

The supporting repo for this article is available on Github.

Resources And Further Reading Smashing Editorial (ks, ra, yk, il)
Catégories: Programmation

Baking Structured Data Into The Design Process

jeu, 04/09/2020 - 13:30
Baking Structured Data Into The Design Process Baking Structured Data Into The Design Process Frederick O’Brien 2020-04-09T11:30:00+00:00 2020-04-09T13:07:04+00:00

Search engine optimization (SEO) is essential for almost every kind of website, but its finer points remain something of a specialty. Even today SEO is often treated as something that can be tacked on after the fact. It can up to a point, but it really shouldn’t be. Search engines get smarter every day and there are ways for websites to be smarter too.

The foundations of SEO are the same as they’ve always been: great content clearly labeled will win the day sooner or later — regardless of how many people try to game the system. The thing is, those labels are far more sophisticated than they used to be. Meta titles, image alt text, and backlinks are important, but in 2020, they’re also fairly primitive. There is another tier of metadata that only a fraction of sites are currently using: structured data.

All search engines share the same purpose: to organize the web’s content and deliver the most relevant, useful results possible to search queries. How they achieve this has changed enormously since the days of Lycos and Ask Jeeves. Google alone uses more than 200 ranking factors, and those are just the ones we know about.

SEO is a huge field nowadays, and I put it to you that structured data is a really, really important factor to understand and implement in the coming years. It doesn’t just improve your chances of ranking highly for relevant queries. More importantly, it helps make your websites better — opening it up to all sorts of useful web experiences.

Recommended reading: Where Does SEO Belong In Your Web Design Process?

What Is Structured Data?

Structured data is a way of labeling content on web pages. Using vocabulary from Schema.org, it removes much of the ambiguity from SEO. Instead of trusting the likes of Google, Bing, Baidu, and DuckDuckGo to work out what your content is about, you tell them. It’s the difference between a search engine guessing what a page is about and knowing for sure.

As Schema.org puts it:

By adding additional tags to the HTML of your web pages — tags that say, "Hey search engine, this information describes this specific movie, or place, or person, or video" — you can help search engines and other applications better understand your content and display it in a useful, relevant way.

Schema.org launched in 2011, a project shared by Google, Microsoft, Yahoo, and Yandex. In other words, it’s a ‘bipartisan’ effort — if you like. The markup transcends any one search engine. In Schema.org’s own words,

“A shared vocabulary makes it easier for webmasters and developers to decide on a schema and get the maximum benefit for their efforts.”

It is in many respects a more expansive cousin of microformats (launched around 2005) which embed semantics and structured data in HTML, mainly for the benefit of search engines and aggregators. Although microformats are currently still supported, the ‘official’ nature of the Schema.org library makes it a safer bet for longevity.

JSON for Linked Data (JSON-LD) has emerged as the dominant underlying standard for structured data, although Microdata and RDFa are also supported and serve the same purpose. Schema.org provides examples for each type depending on what you’re most comfortable with.

As an example, let’s say Joe Bloggs writes a review of Joseph Heller’s 1961 novel Catch-22 and publishes it on his blog. Sadly, Bloggs has poor taste and gives it two out of five stars. For a person looking at the page, this information would be understood unthinkingly, but computer programs would have to connect several dots to reach the same conclusion.

With structured data, the following markup could be added to the page’s <head> code. (This is a JSON-LD approach. Microdata and RDFa can be used to weave the same information into <body> content):

<script type="application/ld+json"> { "@context" : "http://schema.org", "@type" : "Book", "name" : "Catch-22", "author" : { "@type" : "Person", "name" : "Joseph Heller" }, "datePublished" : "1961-11-10", "review" : { "@type" : "Review", "author" : { "@type" : "Person", "name" : "Joe Bloggs" }, "reviewRating" : { "@type" : "Rating", "ratingValue" : "2", "worstRating" : "0", "bestRating" : "5" }, "reviewBody" : "A disaster. The worst book I've ever read, and I've read The Da Vinci Code." } } </script>

This sets in stone that the page is about Catch-22, a novel by Joseph Heller published on November 10th, 1961. The reviewer has been identified, as has the parameters of the scoring system. Different schemas can be combined (or tiered) to describe different things. For example, through tagging of this sort, you could make clear a page is the event listing for an open-air film screening, and the film in question is The Life Aquatic with Steve Zissou by Wes Anderson.

Recommended reading: Better Research, Better Design, Better Results

Why Does It Matter?

Ok, wonderful. I can label my website up to its eyeballs and it will look exactly the same, but what are the benefits? To my mind, there are two main benefits to including structured data in websites:

  1. It makes search engine’s jobs much easier.
    They can index content more accurately, which in turn means they can present it more richly.
  2. It helps web content to be more thorough and useful.
    Structured data gives you a ‘computer perspective’ on content. Quality content is fabulous. Quality content thoroughly tagged is the stuff of dreams.

You know when you see snazzy search results that include star ratings? That’s structured data. Rich snippets of film reviews? Structured data. When a selection of recipes appear, ingredients, preparation time and all? You guessed it. Dig into the code of any of these pages and you’ll find the markup somewhere. Search engines reward sites using structured data because it tells them exactly what they’re dealing with.

Review snippets using structured data markup on Google Search (Large preview) Recipe snippets using structured data markup on Google Search Examine the code on the websites featured above and sure enough, structured data is there. (Large preview)

It’s not just search either, to be clear. That’s a big part of it but it’s not the whole deal. Structured data is primarily about tagging and organizing content. Rich search results are just one way for said content to be used. Google Dataset Search uses Schema.org/Dataset markup, for example.

Below are a handful of examples of structured data being useful:

There are thousands more. Like, literally. Schema.org even fast-tracked the release of markup for Covid-19 recently. It’s an ever-growing library.

In many respects, structured data is a branch of the Semantic Web, which strives for a fully machine-readable Internet. It gives you a machine-readable perspective on web content that (when properly implemented) feeds back into richer functionality for people.

As such, just about anyone with a website would benefit from knowing what structured data is and how it works. According to W3Techs, only 29.6% of websites use JSON-LD, and 43.2% don’t use any structured data formats at all. There’s no obligation, of course. Not everyone cares about SEO or being machine-readable. On the flip side, for those who do there’s currently a big opportunity to one-up rival sites.

In the same way that HTML forces you to think about how content is organized, structured data gets you thinking about the substance. It makes you more thorough. Whatever your website is about, if you comb through the relevant schema documentation you’ll almost certainly spot details that you didn’t think to include beforehand.

As humans, it is easy to take for granted the connections between information. Search engines and computer programs are smart, but they’re not that smart. Not yet. Structured data translates content into terms they can understand. This, in turn, allows them to deliver richer experiences.

Resources And Further Reading Incorporating Structured Data Into Website Design

Weaving structured data into a website isn’t as straightforward as, say, changing a meta title. It’s the data DNA of your web content. If you want to implement it properly, then you need to be willing to get into the weeds — at least a little bit. Below are a few simple steps developers can take to weave structured data into the design process.

Note: I personally subscribe to a holistic approach to design, where design and substance go hand in hand. Juggling a bunch of disciplines is nothing new to web design, this is just another one, and if it’s incorporated well it can strengthen other elements around it. Think of it as an enhancement to your site’s engine. The car may not look all that different but it handles a hell of a lot better.

Start With A Concept

I’ll use myself as an example. For five years, two friends and I have been reviewing an album a week as a hobby (with others stepping in from time to time). Our sneering, insufferable prose is currently housed in a WordPress site, which — under my well-meaning but altogether ignorant care — had grown into a Frankenstein’s monster of plugins.

We are in the process of redesigning the site which (among other things) has entailed bringing structured data into the core design. Here, as with any other project, the first thing to do is establish what your content is about. The better you answer this question, the easier everything that follows will be.

In our case, these are the essentials:

  • We review music albums;
  • Each review has three reviewers who each write a summary by choosing up to three favorite tracks and assigning a personal score out of ten;
  • These three scores are combined into a final score out of 30;
  • From the three summaries, a passage is chosen to serve as an ‘at-a-glance’ roundup of all our thoughts.

Some of this may sound a bit specific or even a bit arbitrary (because it is), but you’d be surprised how much of it can be woven together using structured data.

Below is a mockup of what the revamped review pages will look like, and the information that can be translated into schema markup:

A web page annotated with structured data markup Even the most sprawling content is packed full of information just waiting to be tagged and structured. (Large preview)

There’s no trick to this process. I know what the content is about, so I know where to look in the documentation. In this case, I go to Schema.org/MusicAlbum and am met with all manner of potential properties, including:

  • albumReleaseType
  • byArtist
  • genre
  • producer
  • datePublished
  • recordedAt

There are dozens; some exclusive to MusicAlbum, others falling under the larger umbrella of CreativeWork. Digging deeper into the documentation, I find that the markup can connect to MusicBrainz, a music metadata encyclopedia. The same process unfolds when I go to the Review documentation.

From that one simple page, the following information can be gleaned and organized:

<script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Review", "reviewBody": "Whereas My Love is Cool was guilty of trying too hard no such thing can be said of Visions. The riffs roar and the melodies soar, with the band playing beautifully to Ellie Rowsell's strengths.", "datePublished": "October 4, 2017", "author": [{ "@type": "Person", "name": "André Dack" }, { "@type": "Person", "name": "Frederick O'Brien" }, { "@type": "Person", "name": "Marcus Lawrence" }], "itemReviewed": { "@type": "MusicAlbum", "@id": "https://musicbrainz.org/release-group/7f231c61-20b2-49d6-ac66-1cacc4cc775f", "byArtist": { "@type": "MusicGroup", "name": "Wolf Alice", "@id": "https://musicbrainz.org/artist/3547f34a-db02-4ab7-b4a0-380e1ef951a9" }, "image": "https://lesoreillescurieuses.files.wordpress.com/2017/10/a1320370042_10.jpg", "albumProductionType": "http://schema.org/StudioAlbum", "albumReleaseType": "http://schema.org/AlbumRelease", "name": "Visions of a Life", "numTracks": "12", "datePublished": "September 29, 2017" }, "reviewRating": { "@type": "Rating", "ratingValue": 27, "worstRating": 0, "bestRating": 30 } } </script>

And honestly, I may yet add a lot more. Initially, I found the things that are already part of a review page’s structures (i.e. artist, album name, overall score) but then new questions began to present themselves. What could be clearer? What could I add?

This should obviously be counterbalanced by questions of what’s unnecessary. Just because you can do something doesn’t mean that you should. There is such a thing as ‘too much information’. Still, sometimes a bit more detail can really take a page up a notch.

Familiarize Yourself With Schema

There’s no way around it; the best way to get the ball rolling is to immerse yourself in the documentation. There are tools that implement it for you (more on those below), but you’ll get more out of the markup if you have a proper sense of how it works.

Trawl through the Schema.org documentation. Whoever you are and whatever your website’s for, the odds are that there are plenty of relevant schemas. The site is very good with examples, so it needn’t remain theoretical.

The step beyond that, of course, is to find rich search results you would like to emulate, visiting the page, and using browser dev tools to look at what they’re doing. They are often excellent examples of websites that know their content inside out. You can also feed code snippets or URLs into Google’s Structured Data Markup Helper, which then generates appropriate schema.

Example of Google Structured Data Markup Helper in action Tools like Google’’s Structured Data Markup Helper are excellent for getting to grips with how structured data works. (Large preview)

The fundamentals are actually very simple. Once you get your head around them, it’s the breadth of options that take time to explore and play around with. You don’t want to be that person who gets to the end of a design process, looks into schema options, and starts second-guessing everything that’s been done.

Ask The Right Questions

Now that you’re armed with your wealth of structured data knowledge, you’re better positioned to lay the foundations for a strong website. Structured data rides a fairly unique line. In the immediate sense, it exists ‘under the hood’ and is there for the benefit of computers. At the same time, it can enable richer experiences for the user.

Therefore, it pays to look at structured data from both a technical and user perspective. How can structured data help my website be better understood? What other resources, online databases, or hardware (e.g. smart speakers) might be interested in what you’re doing? What options appear in the documentation that I hadn’t accounted for? Do I want to add them?

It is especially important to identify recurring types of content. It’s safe to say a blog can expect lots of blog posts over time, so incorporating structured data into post templates will yield the most results. The example I gave above is all well and good on its own, but there’s no reason why the markup process can’t be automated. That’s the plan for us.

Consider also the ways that people might find your content. If there are opportunities to, say, highlight a snippet of copy for use in voice search, do it. It’s that, or leave it to search engines to work it out for themselves. No-one knows your content better than you do, so make use of that understanding with descriptive markup.

You don’t need to guess how content will be understood with structured data. With tools like Google’s Rich Results Tester, you can see exactly how it gives content form and meaning that might otherwise have been overlooked.

Resources And Further Reading Quality Content Deserves Quality Markup

You’ll find no greater advocate of great content than me. The SEO industry loses its collective mind whenever Google rolls out a major search update. The response to the hysteria is always the same: make quality content. To that I add: mark it up properly.

Familiarize yourself with the documentation and be clear on what your site is about. Every piece of information you tag makes it that much easier for it to be indexed and shared with the right people.

Whether you’re a Google devotee or a DuckDuckGo convert, the spirit remains the same. It’s not about ranking so much as it is about making websites as good as possible. Accommodating structured data will make other aspects of your website better.

You don’t need to trust tech to understand what your content is about — you can tell it. From reviews to recipes to audio search, developers can add a whole new level of sophistication to their content.

The heart and soul of optimizing a website for search have never changed: produce great content and make it as clear as possible what it is and why it’s useful. Structured data is another tool for that purpose, so use it.

Smashing Editorial (ra, yk, il)
Catégories: Programmation

Baking Structured Data Into The Design Process

jeu, 04/09/2020 - 13:30
Baking Structured Data Into The Design Process Baking Structured Data Into The Design Process Frederick O’Brien 2020-04-09T11:30:00+00:00 2020-04-09T13:07:04+00:00

Search engine optimization (SEO) is essential for almost every kind of website, but its finer points remain something of a specialty. Even today SEO is often treated as something that can be tacked on after the fact. It can up to a point, but it really shouldn’t be. Search engines get smarter every day and there are ways for websites to be smarter too.

The foundations of SEO are the same as they’ve always been: great content clearly labeled will win the day sooner or later — regardless of how many people try to game the system. The thing is, those labels are far more sophisticated than they used to be. Meta titles, image alt text, and backlinks are important, but in 2020, they’re also fairly primitive. There is another tier of metadata that only a fraction of sites are currently using: structured data.

All search engines share the same purpose: to organize the web’s content and deliver the most relevant, useful results possible to search queries. How they achieve this has changed enormously since the days of Lycos and Ask Jeeves. Google alone uses more than 200 ranking factors, and those are just the ones we know about.

SEO is a huge field nowadays, and I put it to you that structured data is a really, really important factor to understand and implement in the coming years. It doesn’t just improve your chances of ranking highly for relevant queries. More importantly, it helps make your websites better — opening it up to all sorts of useful web experiences.

Recommended reading: Where Does SEO Belong In Your Web Design Process?

What Is Structured Data?

Structured data is a way of labeling content on web pages. Using vocabulary from Schema.org, it removes much of the ambiguity from SEO. Instead of trusting the likes of Google, Bing, Baidu, and DuckDuckGo to work out what your content is about, you tell them. It’s the difference between a search engine guessing what a page is about and knowing for sure.

As Schema.org puts it:

By adding additional tags to the HTML of your web pages — tags that say, "Hey search engine, this information describes this specific movie, or place, or person, or video" — you can help search engines and other applications better understand your content and display it in a useful, relevant way.

Schema.org launched in 2011, a project shared by Google, Microsoft, Yahoo, and Yandex. In other words, it’s a ‘bipartisan’ effort — if you like. The markup transcends any one search engine. In Schema.org’s own words,

“A shared vocabulary makes it easier for webmasters and developers to decide on a schema and get the maximum benefit for their efforts.”

It is in many respects a more expansive cousin of microformats (launched around 2005) which embed semantics and structured data in HTML, mainly for the benefit of search engines and aggregators. Although microformats are currently still supported, the ‘official’ nature of the Schema.org library makes it a safer bet for longevity.

JSON for Linked Data (JSON-LD) has emerged as the dominant underlying standard for structured data, although Microdata and RDFa are also supported and serve the same purpose. Schema.org provides examples for each type depending on what you’re most comfortable with.

As an example, let’s say Joe Bloggs writes a review of Joseph Heller’s 1961 novel Catch-22 and publishes it on his blog. Sadly, Bloggs has poor taste and gives it two out of five stars. For a person looking at the page, this information would be understood unthinkingly, but computer programs would have to connect several dots to reach the same conclusion.

With structured data, the following markup could be added to the page’s <head> code. (This is a JSON-LD approach. Microdata and RDFa can be used to weave the same information into <body> content):

<script type="application/ld+json"> { "@context" : "http://schema.org", "@type" : "Book", "name" : "Catch-22", "author" : { "@type" : "Person", "name" : "Joseph Heller" }, "datePublished" : "1961-11-10", "review" : { "@type" : "Review", "author" : { "@type" : "Person", "name" : "Joe Bloggs" }, "reviewRating" : { "@type" : "Rating", "ratingValue" : "2", "worstRating" : "0", "bestRating" : "5" }, "reviewBody" : "A disaster. The worst book I've ever read, and I've read The Da Vinci Code." } } </script>

This sets in stone that the page is about Catch-22, a novel by Joseph Heller published on November 10th, 1961. The reviewer has been identified, as has the parameters of the scoring system. Different schemas can be combined (or tiered) to describe different things. For example, through tagging of this sort, you could make clear a page is the event listing for an open-air film screening, and the film in question is The Life Aquatic with Steve Zissou by Wes Anderson.

Recommended reading: Better Research, Better Design, Better Results

Why Does It Matter?

Ok, wonderful. I can label my website up to its eyeballs and it will look exactly the same, but what are the benefits? To my mind, there are two main benefits to including structured data in websites:

  1. It makes search engine’s jobs much easier.
    They can index content more accurately, which in turn means they can present it more richly.
  2. It helps web content to be more thorough and useful.
    Structured data gives you a ‘computer perspective’ on content. Quality content is fabulous. Quality content thoroughly tagged is the stuff of dreams.

You know when you see snazzy search results that include star ratings? That’s structured data. Rich snippets of film reviews? Structured data. When a selection of recipes appear, ingredients, preparation time and all? You guessed it. Dig into the code of any of these pages and you’ll find the markup somewhere. Search engines reward sites using structured data because it tells them exactly what they’re dealing with.

Review snippets using structured data markup on Google Search (Large preview) Recipe snippets using structured data markup on Google Search Examine the code on the websites featured above and sure enough, structured data is there. (Large preview)

It’s not just search either, to be clear. That’s a big part of it but it’s not the whole deal. Structured data is primarily about tagging and organizing content. Rich search results are just one way for said content to be used. Google Dataset Search uses Schema.org/Dataset markup, for example.

Below are a handful of examples of structured data being useful:

There are thousands more. Like, literally. Schema.org even fast-tracked the release of markup for Covid-19 recently. It’s an ever-growing library.

In many respects, structured data is a branch of the Semantic Web, which strives for a fully machine-readable Internet. It gives you a machine-readable perspective on web content that (when properly implemented) feeds back into richer functionality for people.

As such, just about anyone with a website would benefit from knowing what structured data is and how it works. According to W3Techs, only 29.6% of websites use JSON-LD, and 43.2% don’t use any structured data formats at all. There’s no obligation, of course. Not everyone cares about SEO or being machine-readable. On the flip side, for those who do there’s currently a big opportunity to one-up rival sites.

In the same way that HTML forces you to think about how content is organized, structured data gets you thinking about the substance. It makes you more thorough. Whatever your website is about, if you comb through the relevant schema documentation you’ll almost certainly spot details that you didn’t think to include beforehand.

As humans, it is easy to take for granted the connections between information. Search engines and computer programs are smart, but they’re not that smart. Not yet. Structured data translates content into terms they can understand. This, in turn, allows them to deliver richer experiences.

Resources And Further Reading Incorporating Structured Data Into Website Design

Weaving structured data into a website isn’t as straightforward as, say, changing a meta title. It’s the data DNA of your web content. If you want to implement it properly, then you need to be willing to get into the weeds — at least a little bit. Below are a few simple steps developers can take to weave structured data into the design process.

Note: I personally subscribe to a holistic approach to design, where design and substance go hand in hand. Juggling a bunch of disciplines is nothing new to web design, this is just another one, and if it’s incorporated well it can strengthen other elements around it. Think of it as an enhancement to your site’s engine. The car may not look all that different but it handles a hell of a lot better.

Start With A Concept

I’ll use myself as an example. For five years, two friends and I have been reviewing an album a week as a hobby (with others stepping in from time to time). Our sneering, insufferable prose is currently housed in a WordPress site, which — under my well-meaning but altogether ignorant care — had grown into a Frankenstein’s monster of plugins.

We are in the process of redesigning the site which (among other things) has entailed bringing structured data into the core design. Here, as with any other project, the first thing to do is establish what your content is about. The better you answer this question, the easier everything that follows will be.

In our case, these are the essentials:

  • We review music albums;
  • Each review has three reviewers who each write a summary by choosing up to three favorite tracks and assigning a personal score out of ten;
  • These three scores are combined into a final score out of 30;
  • From the three summaries, a passage is chosen to serve as an ‘at-a-glance’ roundup of all our thoughts.

Some of this may sound a bit specific or even a bit arbitrary (because it is), but you’d be surprised how much of it can be woven together using structured data.

Below is a mockup of what the revamped review pages will look like, and the information that can be translated into schema markup:

A web page annotated with structured data markup Even the most sprawling content is packed full of information just waiting to be tagged and structured. (Large preview)

There’s no trick to this process. I know what the content is about, so I know where to look in the documentation. In this case, I go to Schema.org/MusicAlbum and am met with all manner of potential properties, including:

  • albumReleaseType
  • byArtist
  • genre
  • producer
  • datePublished
  • recordedAt

There are dozens; some exclusive to MusicAlbum, others falling under the larger umbrella of CreativeWork. Digging deeper into the documentation, I find that the markup can connect to MusicBrainz, a music metadata encyclopedia. The same process unfolds when I go to the Review documentation.

From that one simple page, the following information can be gleaned and organized:

<script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Review", "reviewBody": "Whereas My Love is Cool was guilty of trying too hard no such thing can be said of Visions. The riffs roar and the melodies soar, with the band playing beautifully to Ellie Rowsell's strengths.", "datePublished": "October 4, 2017", "author": [{ "@type": "Person", "name": "André Dack" }, { "@type": "Person", "name": "Frederick O'Brien" }, { "@type": "Person", "name": "Marcus Lawrence" }], "itemReviewed": { "@type": "MusicAlbum", "@id": "https://musicbrainz.org/release-group/7f231c61-20b2-49d6-ac66-1cacc4cc775f", "byArtist": { "@type": "MusicGroup", "name": "Wolf Alice", "@id": "https://musicbrainz.org/artist/3547f34a-db02-4ab7-b4a0-380e1ef951a9" }, "image": "https://lesoreillescurieuses.files.wordpress.com/2017/10/a1320370042_10.jpg", "albumProductionType": "http://schema.org/StudioAlbum", "albumReleaseType": "http://schema.org/AlbumRelease", "name": "Visions of a Life", "numTracks": "12", "datePublished": "September 29, 2017" }, "reviewRating": { "@type": "Rating", "ratingValue": 27, "worstRating": 0, "bestRating": 30 } } </script>

And honestly, I may yet add a lot more. Initially, I found the things that are already part of a review page’s structures (i.e. artist, album name, overall score) but then new questions began to present themselves. What could be clearer? What could I add?

This should obviously be counterbalanced by questions of what’s unnecessary. Just because you can do something doesn’t mean that you should. There is such a thing as ‘too much information’. Still, sometimes a bit more detail can really take a page up a notch.

Familiarize Yourself With Schema

There’s no way around it; the best way to get the ball rolling is to immerse yourself in the documentation. There are tools that implement it for you (more on those below), but you’ll get more out of the markup if you have a proper sense of how it works.

Trawl through the Schema.org documentation. Whoever you are and whatever your website’s for, the odds are that there are plenty of relevant schemas. The site is very good with examples, so it needn’t remain theoretical.

The step beyond that, of course, is to find rich search results you would like to emulate, visiting the page, and using browser dev tools to look at what they’re doing. They are often excellent examples of websites that know their content inside out. You can also feed code snippets or URLs into Google’s Structured Data Markup Helper, which then generates appropriate schema.

Example of Google Structured Data Markup Helper in action Tools like Google’’s Structured Data Markup Helper are excellent for getting to grips with how structured data works. (Large preview)

The fundamentals are actually very simple. Once you get your head around them, it’s the breadth of options that take time to explore and play around with. You don’t want to be that person who gets to the end of a design process, looks into schema options, and starts second-guessing everything that’s been done.

Ask The Right Questions

Now that you’re armed with your wealth of structured data knowledge, you’re better positioned to lay the foundations for a strong website. Structured data rides a fairly unique line. In the immediate sense, it exists ‘under the hood’ and is there for the benefit of computers. At the same time, it can enable richer experiences for the user.

Therefore, it pays to look at structured data from both a technical and user perspective. How can structured data help my website be better understood? What other resources, online databases, or hardware (e.g. smart speakers) might be interested in what you’re doing? What options appear in the documentation that I hadn’t accounted for? Do I want to add them?

It is especially important to identify recurring types of content. It’s safe to say a blog can expect lots of blog posts over time, so incorporating structured data into post templates will yield the most results. The example I gave above is all well and good on its own, but there’s no reason why the markup process can’t be automated. That’s the plan for us.

Consider also the ways that people might find your content. If there are opportunities to, say, highlight a snippet of copy for use in voice search, do it. It’s that, or leave it to search engines to work it out for themselves. No-one knows your content better than you do, so make use of that understanding with descriptive markup.

You don’t need to guess how content will be understood with structured data. With tools like Google’s Rich Results Tester, you can see exactly how it gives content form and meaning that might otherwise have been overlooked.

Resources And Further Reading Quality Content Deserves Quality Markup

You’ll find no greater advocate of great content than me. The SEO industry loses its collective mind whenever Google rolls out a major search update. The response to the hysteria is always the same: make quality content. To that I add: mark it up properly.

Familiarize yourself with the documentation and be clear on what your site is about. Every piece of information you tag makes it that much easier for it to be indexed and shared with the right people.

Whether you’re a Google devotee or a DuckDuckGo convert, the spirit remains the same. It’s not about ranking so much as it is about making websites as good as possible. Accommodating structured data will make other aspects of your website better.

You don’t need to trust tech to understand what your content is about — you can tell it. From reviews to recipes to audio search, developers can add a whole new level of sophistication to their content.

The heart and soul of optimizing a website for search have never changed: produce great content and make it as clear as possible what it is and why it’s useful. Structured data is another tool for that purpose, so use it.

Smashing Editorial (ra, yk, il)
Catégories: Programmation

Baking Structured Data Into The Design Process

jeu, 04/09/2020 - 13:30
Baking Structured Data Into The Design Process Baking Structured Data Into The Design Process Frederick O’Brien 2020-04-09T11:30:00+00:00 2020-04-09T13:07:04+00:00

Search engine optimization (SEO) is essential for almost every kind of website, but its finer points remain something of a specialty. Even today SEO is often treated as something that can be tacked on after the fact. It can up to a point, but it really shouldn’t be. Search engines get smarter every day and there are ways for websites to be smarter too.

The foundations of SEO are the same as they’ve always been: great content clearly labeled will win the day sooner or later — regardless of how many people try to game the system. The thing is, those labels are far more sophisticated than they used to be. Meta titles, image alt text, and backlinks are important, but in 2020, they’re also fairly primitive. There is another tier of metadata that only a fraction of sites are currently using: structured data.

All search engines share the same purpose: to organize the web’s content and deliver the most relevant, useful results possible to search queries. How they achieve this has changed enormously since the days of Lycos and Ask Jeeves. Google alone uses more than 200 ranking factors, and those are just the ones we know about.

SEO is a huge field nowadays, and I put it to you that structured data is a really, really important factor to understand and implement in the coming years. It doesn’t just improve your chances of ranking highly for relevant queries. More importantly, it helps make your websites better — opening it up to all sorts of useful web experiences.

Recommended reading: Where Does SEO Belong In Your Web Design Process?

What Is Structured Data?

Structured data is a way of labeling content on web pages. Using vocabulary from Schema.org, it removes much of the ambiguity from SEO. Instead of trusting the likes of Google, Bing, Baidu, and DuckDuckGo to work out what your content is about, you tell them. It’s the difference between a search engine guessing what a page is about and knowing for sure.

As Schema.org puts it:

By adding additional tags to the HTML of your web pages — tags that say, "Hey search engine, this information describes this specific movie, or place, or person, or video" — you can help search engines and other applications better understand your content and display it in a useful, relevant way.

Schema.org launched in 2011, a project shared by Google, Microsoft, Yahoo, and Yandex. In other words, it’s a ‘bipartisan’ effort — if you like. The markup transcends any one search engine. In Schema.org’s own words,

“A shared vocabulary makes it easier for webmasters and developers to decide on a schema and get the maximum benefit for their efforts.”

It is in many respects a more expansive cousin of microformats (launched around 2005) which embed semantics and structured data in HTML, mainly for the benefit of search engines and aggregators. Although microformats are currently still supported, the ‘official’ nature of the Schema.org library makes it a safer bet for longevity.

JSON for Linked Data (JSON-LD) has emerged as the dominant underlying standard for structured data, although Microdata and RDFa are also supported and serve the same purpose. Schema.org provides examples for each type depending on what you’re most comfortable with.

As an example, let’s say Joe Bloggs writes a review of Joseph Heller’s 1961 novel Catch-22 and publishes it on his blog. Sadly, Bloggs has poor taste and gives it two out of five stars. For a person looking at the page, this information would be understood unthinkingly, but computer programs would have to connect several dots to reach the same conclusion.

With structured data, the following markup could be added to the page’s <head> code. (This is a JSON-LD approach. Microdata and RDFa can be used to weave the same information into <body> content):

<script type="application/ld+json"> { "@context" : "http://schema.org", "@type" : "Book", "name" : "Catch-22", "author" : { "@type" : "Person", "name" : "Joseph Heller" }, "datePublished" : "1961-11-10", "review" : { "@type" : "Review", "author" : { "@type" : "Person", "name" : "Joe Bloggs" }, "reviewRating" : { "@type" : "Rating", "ratingValue" : "2", "worstRating" : "0", "bestRating" : "5" }, "reviewBody" : "A disaster. The worst book I've ever read, and I've read The Da Vinci Code." } } </script>

This sets in stone that the page is about Catch-22, a novel by Joseph Heller published on November 10th, 1961. The reviewer has been identified, as has the parameters of the scoring system. Different schemas can be combined (or tiered) to describe different things. For example, through tagging of this sort, you could make clear a page is the event listing for an open-air film screening, and the film in question is The Life Aquatic with Steve Zissou by Wes Anderson.

Recommended reading: Better Research, Better Design, Better Results

Why Does It Matter?

Ok, wonderful. I can label my website up to its eyeballs and it will look exactly the same, but what are the benefits? To my mind, there are two main benefits to including structured data in websites:

  1. It makes search engine’s jobs much easier.
    They can index content more accurately, which in turn means they can present it more richly.
  2. It helps web content to be more thorough and useful.
    Structured data gives you a ‘computer perspective’ on content. Quality content is fabulous. Quality content thoroughly tagged is the stuff of dreams.

You know when you see snazzy search results that include star ratings? That’s structured data. Rich snippets of film reviews? Structured data. When a selection of recipes appear, ingredients, preparation time and all? You guessed it. Dig into the code of any of these pages and you’ll find the markup somewhere. Search engines reward sites using structured data because it tells them exactly what they’re dealing with.

Review snippets using structured data markup on Google Search (Large preview) Recipe snippets using structured data markup on Google Search Examine the code on the websites featured above and sure enough, structured data is there. (Large preview)

It’s not just search either, to be clear. That’s a big part of it but it’s not the whole deal. Structured data is primarily about tagging and organizing content. Rich search results are just one way for said content to be used. Google Dataset Search uses Schema.org/Dataset markup, for example.

Below are a handful of examples of structured data being useful:

There are thousands more. Like, literally. Schema.org even fast-tracked the release of markup for Covid-19 recently. It’s an ever-growing library.

In many respects, structured data is a branch of the Semantic Web, which strives for a fully machine-readable Internet. It gives you a machine-readable perspective on web content that (when properly implemented) feeds back into richer functionality for people.

As such, just about anyone with a website would benefit from knowing what structured data is and how it works. According to W3Techs, only 29.6% of websites use JSON-LD, and 43.2% don’t use any structured data formats at all. There’s no obligation, of course. Not everyone cares about SEO or being machine-readable. On the flip side, for those who do there’s currently a big opportunity to one-up rival sites.

In the same way that HTML forces you to think about how content is organized, structured data gets you thinking about the substance. It makes you more thorough. Whatever your website is about, if you comb through the relevant schema documentation you’ll almost certainly spot details that you didn’t think to include beforehand.

As humans, it is easy to take for granted the connections between information. Search engines and computer programs are smart, but they’re not that smart. Not yet. Structured data translates content into terms they can understand. This, in turn, allows them to deliver richer experiences.

Resources And Further Reading Incorporating Structured Data Into Website Design

Weaving structured data into a website isn’t as straightforward as, say, changing a meta title. It’s the data DNA of your web content. If you want to implement it properly, then you need to be willing to get into the weeds — at least a little bit. Below are a few simple steps developers can take to weave structured data into the design process.

Note: I personally subscribe to a holistic approach to design, where design and substance go hand in hand. Juggling a bunch of disciplines is nothing new to web design, this is just another one, and if it’s incorporated well it can strengthen other elements around it. Think of it as an enhancement to your site’s engine. The car may not look all that different but it handles a hell of a lot better.

Start With A Concept

I’ll use myself as an example. For five years, two friends and I have been reviewing an album a week as a hobby (with others stepping in from time to time). Our sneering, insufferable prose is currently housed in a WordPress site, which — under my well-meaning but altogether ignorant care — had grown into a Frankenstein’s monster of plugins.

We are in the process of redesigning the site which (among other things) has entailed bringing structured data into the core design. Here, as with any other project, the first thing to do is establish what your content is about. The better you answer this question, the easier everything that follows will be.

In our case, these are the essentials:

  • We review music albums;
  • Each review has three reviewers who each write a summary by choosing up to three favorite tracks and assigning a personal score out of ten;
  • These three scores are combined into a final score out of 30;
  • From the three summaries, a passage is chosen to serve as an ‘at-a-glance’ roundup of all our thoughts.

Some of this may sound a bit specific or even a bit arbitrary (because it is), but you’d be surprised how much of it can be woven together using structured data.

Below is a mockup of what the revamped review pages will look like, and the information that can be translated into schema markup:

A web page annotated with structured data markup Even the most sprawling content is packed full of information just waiting to be tagged and structured. (Large preview)

There’s no trick to this process. I know what the content is about, so I know where to look in the documentation. In this case, I go to Schema.org/MusicAlbum and am met with all manner of potential properties, including:

  • albumReleaseType
  • byArtist
  • genre
  • producer
  • datePublished
  • recordedAt

There are dozens; some exclusive to MusicAlbum, others falling under the larger umbrella of CreativeWork. Digging deeper into the documentation, I find that the markup can connect to MusicBrainz, a music metadata encyclopedia. The same process unfolds when I go to the Review documentation.

From that one simple page, the following information can be gleaned and organized:

<script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Review", "reviewBody": "Whereas My Love is Cool was guilty of trying too hard no such thing can be said of Visions. The riffs roar and the melodies soar, with the band playing beautifully to Ellie Rowsell's strengths.", "datePublished": "October 4, 2017", "author": [{ "@type": "Person", "name": "André Dack" }, { "@type": "Person", "name": "Frederick O'Brien" }, { "@type": "Person", "name": "Marcus Lawrence" }], "itemReviewed": { "@type": "MusicAlbum", "@id": "https://musicbrainz.org/release-group/7f231c61-20b2-49d6-ac66-1cacc4cc775f", "byArtist": { "@type": "MusicGroup", "name": "Wolf Alice", "@id": "https://musicbrainz.org/artist/3547f34a-db02-4ab7-b4a0-380e1ef951a9" }, "image": "https://lesoreillescurieuses.files.wordpress.com/2017/10/a1320370042_10.jpg", "albumProductionType": "http://schema.org/StudioAlbum", "albumReleaseType": "http://schema.org/AlbumRelease", "name": "Visions of a Life", "numTracks": "12", "datePublished": "September 29, 2017" }, "reviewRating": { "@type": "Rating", "ratingValue": 27, "worstRating": 0, "bestRating": 30 } } </script>

And honestly, I may yet add a lot more. Initially, I found the things that are already part of a review page’s structures (i.e. artist, album name, overall score) but then new questions began to present themselves. What could be clearer? What could I add?

This should obviously be counterbalanced by questions of what’s unnecessary. Just because you can do something doesn’t mean that you should. There is such a thing as ‘too much information’. Still, sometimes a bit more detail can really take a page up a notch.

Familiarize Yourself With Schema

There’s no way around it; the best way to get the ball rolling is to immerse yourself in the documentation. There are tools that implement it for you (more on those below), but you’ll get more out of the markup if you have a proper sense of how it works.

Trawl through the Schema.org documentation. Whoever you are and whatever your website’s for, the odds are that there are plenty of relevant schemas. The site is very good with examples, so it needn’t remain theoretical.

The step beyond that, of course, is to find rich search results you would like to emulate, visiting the page, and using browser dev tools to look at what they’re doing. They are often excellent examples of websites that know their content inside out. You can also feed code snippets or URLs into Google’s Structured Data Markup Helper, which then generates appropriate schema.

Example of Google Structured Data Markup Helper in action Tools like Google’’s Structured Data Markup Helper are excellent for getting to grips with how structured data works. (Large preview)

The fundamentals are actually very simple. Once you get your head around them, it’s the breadth of options that take time to explore and play around with. You don’t want to be that person who gets to the end of a design process, looks into schema options, and starts second-guessing everything that’s been done.

Ask The Right Questions

Now that you’re armed with your wealth of structured data knowledge, you’re better positioned to lay the foundations for a strong website. Structured data rides a fairly unique line. In the immediate sense, it exists ‘under the hood’ and is there for the benefit of computers. At the same time, it can enable richer experiences for the user.

Therefore, it pays to look at structured data from both a technical and user perspective. How can structured data help my website be better understood? What other resources, online databases, or hardware (e.g. smart speakers) might be interested in what you’re doing? What options appear in the documentation that I hadn’t accounted for? Do I want to add them?

It is especially important to identify recurring types of content. It’s safe to say a blog can expect lots of blog posts over time, so incorporating structured data into post templates will yield the most results. The example I gave above is all well and good on its own, but there’s no reason why the markup process can’t be automated. That’s the plan for us.

Consider also the ways that people might find your content. If there are opportunities to, say, highlight a snippet of copy for use in voice search, do it. It’s that, or leave it to search engines to work it out for themselves. No-one knows your content better than you do, so make use of that understanding with descriptive markup.

You don’t need to guess how content will be understood with structured data. With tools like Google’s Rich Results Tester, you can see exactly how it gives content form and meaning that might otherwise have been overlooked.

Resources And Further Reading Quality Content Deserves Quality Markup

You’ll find no greater advocate of great content than me. The SEO industry loses its collective mind whenever Google rolls out a major search update. The response to the hysteria is always the same: make quality content. To that I add: mark it up properly.

Familiarize yourself with the documentation and be clear on what your site is about. Every piece of information you tag makes it that much easier for it to be indexed and shared with the right people.

Whether you’re a Google devotee or a DuckDuckGo convert, the spirit remains the same. It’s not about ranking so much as it is about making websites as good as possible. Accommodating structured data will make other aspects of your website better.

You don’t need to trust tech to understand what your content is about — you can tell it. From reviews to recipes to audio search, developers can add a whole new level of sophistication to their content.

The heart and soul of optimizing a website for search have never changed: produce great content and make it as clear as possible what it is and why it’s useful. Structured data is another tool for that purpose, so use it.

Smashing Editorial (ra, yk, il)
Catégories: Programmation

How To Set Up An Express API Backend Project With PostgreSQL

mer, 04/08/2020 - 13:00
How To Set Up An Express API Backend Project With PostgreSQL How To Set Up An Express API Backend Project With PostgreSQL Chidi Orji 2020-04-08T11:00:00+00:00 2020-04-08T13:07:30+00:00

We will take a Test-Driven Development (TDD) approach and the set up Continuous Integration (CI) job to automatically run our tests on Travis CI and AppVeyor, complete with code quality and coverage reporting. We will learn about controllers, models (with PostgreSQL), error handling, and asynchronous Express middleware. Finally, we’ll complete the CI/CD pipeline by configuring automatic deploy on Heroku.

It sounds like a lot, but this tutorial is aimed at beginners who are ready to try their hands on a backend project with some level of complexity, and who may still be confused as to how all the pieces fit together in a real project.

It is robust without being overwhelming and is broken down into sections that you can complete in a reasonable length of time.

Getting Started

The first step is to create a new directory for the project and start a new node project. Node is required to continue with this tutorial. If you don’t have it installed, head over to the official website, download, and install it before continuing.

I will be using yarn as my package manager for this project. There are installation instructions for your specific operating system here. Feel free to use npm if you like.

Open your terminal, create a new directory, and start a Node.js project.

# create a new directory mkdir express-api-template # change to the newly-created directory cd express-api-template # initialize a new Node.js project npm init

Answer the questions that follow to generate a package.json file. This file holds information about your project. Example of such information includes what dependencies it uses, the command to start the project, and so on.

You may now open the project folder in your editor of choice. I use visual studio code. It’s a free IDE with tons of plugins to make your life easier, and it’s available for all major platforms. You can download it from the official website.

Create the following files in the project folder:

  • README.md
  • .editorconfig

Here’s a description of what .editorconfig does from the EditorConfig website. (You probably don’t need it if you’re working solo, but it does no harm, so I’ll leave it here.)

“EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.”

Open .editorconfig and paste the following code:

root = true [*] indent_style = space indent_size = 2 charset = utf-8 trim_trailing_whitespace = false insert_final_newline = true

The [*] means that we want to apply the rules that come under it to every file in the project. We want an indent size of two spaces and UTF-8 character set. We also want to trim trailing white space and insert a final empty line in our file.

Open README.md and add the project name as a first-level element.

# Express API template

Let’s add version control right away.

# initialize the project folder as a git repository git init

Create a .gitignore file and enter the following lines:

node_modules/ yarn-error.log .env .nyc_output coverage build/

These are all the files and folders we don’t want to track. We don’t have them in our project yet, but we’ll see them as we proceed.

At this point, you should have the following folder structure.

EXPRESS-API-TEMPLATE ├── .editorconfig ├── .gitignore ├── package.json └── README.md

I consider this to be a good point to commit my changes and push them to GitHub.

Starting A New Express Project

Express is a Node.js framework for building web applications. According to the official website, it is a

Fast, unopinionated, minimalist web framework for Node.js.

There are other great web application frameworks for Node.js, but Express is very popular, with over 47k GitHub stars at the time of this writing.

In this article, we will not be having a lot of discussions about all the parts that make up Express. For that discussion, I recommend you check out Jamie’s series. The first part is here, and the second part is here.

Install Express and start a new Express project. It’s possible to manually set up an Express server from scratch but to make our life easier we’ll use the express-generator to set up the app skeleton.

# install the express generator globally yarn global add express-generator # install express yarn add express # generate the express project in the current folder express -f

The -f flag forces Express to create the project in the current directory.

We’ll now perform some house-cleaning operations.

  1. Delete the file index/users.js.
  2. Delete the folders public/ and views/.
  3. Rename the file bin/www to bin/www.js.
  4. Uninstall jade with the command yarn remove jade.
  5. Create a new folder named src/ and move the following inside it: 1. app.js file 2. bin/ folder 3. routes/ folder inside.
  6. Open up package.json and update the start script to look like below.
"start": "node ./src/bin/www"

At this point, your project folder structure looks like below. You can see how VS Code highlights the file changes that have taken place.

EXPRESS-API-TEMPLATE ├── node_modules ├── src | ├── bin │ │ ├── www.js │ ├── routes │ | ├── index.js │ └── app.js ├── .editorconfig ├── .gitignore ├── package.json ├── README.md └── yarn.lock

Open src/app.js and replace the content with the below code.

var logger = require('morgan'); var express = require('express'); var cookieParser = require('cookie-parser'); var indexRouter = require('./routes/index'); var app = express(); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use('/v1', indexRouter); module.exports = app;

After requiring some libraries, we instruct Express to handle every request coming to /v1 with indexRouter.

Replace the content of routes/index.js with the below code:

var express = require('express'); var router = express.Router(); router.get('/', function(req, res, next) { return res.status(200).json({ message: 'Welcome to Express API template' }); }); module.exports = router;

We grab Express, create a router from it and serve the / route, which returns a status code of 200 and a JSON message.

Start the app with the below command:

# start the app yarn start

If you’ve set up everything correctly you should only see $ node ./src/bin/www in your terminal.

Visit http://localhost:3000/v1 in your browser. You should see the following message:

{ "message": "Welcome to Express API template" }

This is a good point to commit our changes.

Converting Our Code To ES6

The code generated by express-generator is in ES5, but in this article, we will be writing all our code in ES6 syntax. So, let’s convert our existing code to ES6.

Replace the content of routes/index.js with the below code:

import express from 'express'; const indexRouter = express.Router(); indexRouter.get('/', (req, res) => res.status(200).json({ message: 'Welcome to Express API template' }) ); export default indexRouter;

It is the same code as we saw above, but with the import statement and an arrow function in the / route handler.

Replace the content of src/app.js with the below code:

import logger from 'morgan'; import express from 'express'; import cookieParser from 'cookie-parser'; import indexRouter from './routes/index'; const app = express(); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use('/v1', indexRouter); export default app;

Let’s now take a look at the content of src/bin/www.js. We will build it incrementally. Delete the content of src/bin/www.js and paste in the below code block.

#!/usr/bin/env node /** * Module dependencies. */ import debug from 'debug'; import http from 'http'; import app from '../app'; /** * Normalize a port into a number, string, or false. */ const normalizePort = val => { const port = parseInt(val, 10); if (Number.isNaN(port)) { // named pipe return val; } if (port >= 0) { // port number return port; } return false; }; /** * Get port from environment and store in Express. */ const port = normalizePort(process.env.PORT || '3000'); app.set('port', port); /** * Create HTTP server. */ const server = http.createServer(app); // next code block goes here

This code checks if a custom port is specified in the environment variables. If none is set the default port value of 3000 is set on the app instance, after being normalized to either a string or a number by normalizePort. The server is then created from the http module, with app as the callback function.

The #!/usr/bin/env node line is optional since we would specify node when we want to execute this file. But make sure it is on line 1 of src/bin/www.js file or remove it completely.

Let’s take a look at the error handling function. Copy and paste this code block after the line where the server is created.

/** * Event listener for HTTP server "error" event. */ const onError = error => { if (error.syscall !== 'listen') { throw error; } const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': alert(`${bind} requires elevated privileges`); process.exit(1); break; case 'EADDRINUSE': alert(`${bind} is already in use`); process.exit(1); break; default: throw error; } }; /** * Event listener for HTTP server "listening" event. */ const onListening = () => { const addr = server.address(); const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; debug(`Listening on ${bind}`); }; /** * Listen on provided port, on all network interfaces. */ server.listen(port); server.on('error', onError); server.on('listening', onListening);

The onError function listens for errors in the http server and displays appropriate error messages. The onListening function simply outputs the port the server is listening on to the console. Finally, the server listens for incoming requests at the specified address and port.

At this point, all our existing code is in ES6 syntax. Stop your server (use Ctrl + C) and run yarn start. You’ll get an error SyntaxError: Invalid or unexpected token. This happens because Node (at the time of writing) doesn’t support some of the syntax we’ve used in our code.

We’ll now fix that in the following section.

Configuring Development Dependencies: babel, nodemon, eslint, And prettier

It’s time to set up most of the scripts we’re going to need at this phase of the project.

Install the required libraries with the below commands. You can just copy everything and paste it in your terminal. The comment lines will be skipped.

# install babel scripts yarn add @babel/cli @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/register @babel/runtime @babel/node --dev

This installs all the listed babel scripts as development dependencies. Check your package.json file and you should see a devDependencies section. All the installed scripts will be listed there.

The babel scripts we’re using are explained below:

@babel/cli A required install for using babel. It allows the use of Babel from the terminal and is available as ./node_modules/.bin/babel. @babel/core Core Babel functionality. This is a required installation. @babel/node This works exactly like the Node.js CLI, with the added benefit of compiling with babel presets and plugins. This is required for use with nodemon. @babel/plugin-transform-runtime This helps to avoid duplication in the compiled output. @babel/preset-env A collection of plugins that are responsible for carrying out code transformations. @babel/register This compiles files on the fly and is specified as a requirement during tests. @babel/runtime This works in conjunction with @babel/plugin-transform-runtime.

Create a file named .babelrc at the root of your project and add the following code:

{ "presets": ["@babel/preset-env"], "plugins": ["@babel/transform-runtime"] }

Let’s install nodemon

# install nodemon yarn add nodemon --dev

nodemon is a library that monitors our project source code and automatically restarts our server whenever it observes any changes.

Create a file named nodemon.json at the root of your project and add the code below:

{ "watch": [ "package.json", "nodemon.json", ".eslintrc.json", ".babelrc", ".prettierrc", "src/" ], "verbose": true, "ignore": ["*.test.js", "*.spec.js"] }

The watch key tells nodemon which files and folders to watch for changes. So, whenever any of these files changes, nodemon restarts the server. The ignore key tells it the files not to watch for changes.

Now update the scripts section of your package.json file to look like the following:

# build the content of the src folder "prestart": "babel ./src --out-dir build" # start server from the build folder "start": "node ./build/bin/www" # start server in development mode "startdev": "nodemon --exec babel-node ./src/bin/www"
  1. prestart scripts builds the content of the src/ folder and puts it in the build/ folder. When you issue the yarn start command, this script runs first before the start script.
  2. start script now serves the content of the build/ folder instead of the src/ folder we were serving previously. This is the script you’ll use when serving the file in production. In fact, services like Heroku automatically run this script when you deploy.
  3. yarn startdev is used to start the server during development. From now on we will be using this script as we develop the app. Notice that we’re now using babel-node to run the app instead of regular node. The --exec flag forces babel-node to serve the src/ folder. For the start script, we use node since the files in the build/ folder have been compiled to ES5.

Run yarn startdev and visit http://localhost:3000/v1. Your server should be up and running again.

The final step in this section is to configure ESLint and prettier. ESLint helps with enforcing syntax rules while prettier helps for formatting our code properly for readability.

Add both of them with the command below. You should run this on a separate terminal while observing the terminal where our server is running. You should see the server restarting. This is because we’re monitoring package.json file for changes.

# install elsint and prettier yarn add eslint eslint-config-airbnb-base eslint-plugin-import prettier --dev

Now create the .eslintrc.json file in the project root and add the below code:

{ "env": { "browser": true, "es6": true, "node": true, "mocha": true }, "extends": ["airbnb-base"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, "rules": { "indent": ["warn", 2], "linebreak-style": ["error", "unix"], "quotes": ["error", "single"], "semi": ["error", "always"], "no-console": 1, "comma-dangle": [0], "arrow-parens": [0], "object-curly-spacing": ["warn", "always"], "array-bracket-spacing": ["warn", "always"], "import/prefer-default-export": [0] } }

This file mostly defines some rules against which eslint will check our code. You can see that we’re extending the style rules used by Airbnb.

In the "rules" section, we define whether eslint should show a warning or an error when it encounters certain violations. For instance, it shows a warning message on our terminal for any indentation that does not use 2 spaces. A value of [0] turns off a rule, which means that we won’t get a warning or an error if we violate that rule.

Create a file named .prettierrc and add the code below:

{ "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": true }

We’re setting a tab width of 2 and enforcing the use of single quotes throughout our application. Do check the prettier guide for more styling options.

Now add the following scripts to your package.json:

# add these one after the other "lint": "./node_modules/.bin/eslint ./src" "pretty": "prettier --write '**/*.{js,json}' '!node_modules/**'" "postpretty": "yarn lint --fix"

Run yarn lint. You should see a number of errors and warnings in the console.

The pretty command prettifies our code. The postpretty command is run immediately after. It runs the lint command with the --fix flag appended. This flag tells ESLint to automatically fix common linting issues. In this way, I mostly run the yarn pretty command without bothering about the lint command.

Run yarn pretty. You should see that we have only two warnings about the presence of alert in the bin/www.js file.

Here’s what our project structure looks like at this point.

EXPRESS-API-TEMPLATE ├── build ├── node_modules ├── src | ├── bin │ │ ├── www.js │ ├── routes │ | ├── index.js │ └── app.js ├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── nodemon.json ├── package.json ├── README.md └── yarn.lock

You may find that you have an additional file, yarn-error.log in your project root. Add it to .gitignore file. Commit your changes.

Settings And Environment Variables In Our .env File

In nearly every project, you’ll need somewhere to store settings that will be used throughout your app e.g. an AWS secret key. We store such settings as environment variables. This keeps them away from prying eyes, and we can use them within our application as needed.

I like having a settings.js file with which I read all my environment variables. Then, I can refer to the settings file from anywhere within my app. You’re at liberty to name this file whatever you want, but there’s some kind of consensus about naming such files settings.js or config.js.

For our environment variables, we’ll keep them in a .env file and read them into our settings file from there.

Create the .env file at the root of your project and enter the below line:

TEST_ENV_VARIABLE="Environment variable is coming across"

To be able to read environment variables into our project, there’s a nice library, dotenv that reads our .env file and gives us access to the environment variables defined inside. Let’s install it.

# install dotenv yarn add dotenv

Add the .env file to the list of files being watched by nodemon.

Now, create the settings.js file inside the src/ folder and add the below code:

import dotenv from 'dotenv'; dotenv.config(); export const testEnvironmentVariable = process.env.TEST_ENV_VARIABLE;

We import the dotenv package and call its config method. We then export the testEnvironmentVariable which we set in our .env file.

Open src/routes/index.js and replace the code with the one below.

import express from 'express'; import { testEnvironmentVariable } from '../settings'; const indexRouter = express.Router(); indexRouter.get('/', (req, res) => res.status(200).json({ message: testEnvironmentVariable })); export default indexRouter;

The only change we’ve made here is that we import testEnvironmentVariable from our settings file and use is as the return message for a request from the / route.

Visit http://localhost:3000/v1 and you should see the message, as shown below.

{ "message": "Environment variable is coming across." }

And that’s it. From now on we can add as many environment variables as we want and we can export them from our settings.js file.

This is a good point to commit your code. Remember to prettify and lint your code.

Writing Our First Test

It’s time to incorporate testing into our app. One of the things that give the developer confidence in their code is tests. I’m sure you’ve seen countless articles on the web preaching Test-Driven Development (TDD). It cannot be emphasized enough that your code needs some measure of testing. TDD is very easy to follow when you’re working with Express.js.

In our tests, we will make calls to our API endpoints and check to see if what is returned is what we expect.

Install the required dependencies:

# install dependencies yarn add mocha chai nyc sinon-chai supertest coveralls --dev

Each of these libraries has its own role to play in our tests.

mocha test runner chai used to make assertions nyc collect test coverage report sinon-chai extends chai’s assertions supertest used to make HTTP calls to our API endpoints coveralls for uploading test coverage to coveralls.io

Create a new test/ folder at the root of your project. Create two files inside this folder:

  • test/setup.js
  • test/index.test.js

Mocha will find the test/ folder automatically.

Open up test/setup.js and paste the below code. This is just a helper file that helps us organize all the imports we need in our test files.

import supertest from 'supertest'; import chai from 'chai'; import sinonChai from 'sinon-chai'; import app from '../src/app'; chai.use(sinonChai); export const { expect } = chai; export const server = supertest.agent(app); export const BASE_URL = '/v1';

This is like a settings file, but for our tests. This way we don’t have to initialize everything inside each of our test files. So we import the necessary packages and export what we initialized — which we can then import in the files that need them.

Open up index.test.js and paste the following test code.

import { expect, server, BASE_URL } from './setup'; describe('Index page test', () => { it('gets base url', done => { server .get(`${BASE_URL}/`) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.message).to.equal( 'Environment variable is coming across.' ); done(); }); }); });

Here we make a request to get the base endpoint, which is / and assert that the res.body object has a message key with a value of Environment variable is coming across.

If you’re not familiar with the describe, it pattern, I encourage you to take a quick look at Mocha’s “Getting Started” doc.

Add the test command to the scripts section of package.json.

"test": "nyc --reporter=html --reporter=text --reporter=lcov mocha -r @babel/register"

This script executes our test with nyc and generates three kinds of coverage report: an HTML report, outputted to the coverage/ folder; a text report outputted to the terminal and an lcov report outputted to the .nyc_output/ folder.

Now run yarn test. You should see a text report in your terminal just like the one in the below photo.

Test coverage report (Large preview)

Notice that two additional folders are generated:

  • .nyc_output/
  • coverage/

Look inside .gitignore and you’ll see that we’re already ignoring both. I encourage you to open up coverage/index.html in a browser and view the test report for each file.

This is a good point to commit your changes.

Continuous Integration(CD) And Badges: Travis, Coveralls, Code Climate, AppVeyor

It’s now time to configure continuous integration and deployment (CI/CD) tools. We will configure common services such as travis-ci, coveralls, AppVeyor, and codeclimate and add badges to our README file.

Let’s get started.

Travis CI

Travis CI is a tool that runs our tests automatically each time we push a commit to GitHub (and recently, Bitbucket) and each time we create a pull request. This is mostly useful when making pull requests by showing us if the our new code has broken any of our tests.

  1. Visit travis-ci.com or travis-ci.org and create an account if you don’t have one. You have to sign up with your GitHub account.
  2. Hover over the dropdown arrow next to your profile picture and click on settings.
  3. Under Repositories tab click Manage repositories on Github to be redirected to Github.
  4. On the GitHub page, scroll down to Repository access and click the checkbox next to Only select repositories.
  5. Click the Select repositories dropdown and find the express-api-template repo. Click it to add it to the list of repositories you want to add to travis-ci.
  6. Click Approve and install and wait to be redirected back to travis-ci.
  7. At the top of the repo page, close to the repo name, click on the build unknown icon. From the Status Image modal, select markdown from the format dropdown.
  8. Copy the resulting code and paste it in your README.md file.
  9. On the project page, click on More options > Settings. Under Environment Variables section, add the TEST_ENV_VARIABLE env variable. When entering its value, be sure to have it within double quotes like this "Environment variable is coming across."
  10. Create .travis.yml file at the root of your project and paste in the below code (We’ll set the value of CC_TEST_REPORTER_ID in the Code Climate section).
language: node_js env: global: - CC_TEST_REPORTER_ID=get-this-from-code-climate-repo-page matrix: include: - node_js: '12' cache: directories: [node_modules] install: yarn after_success: yarn coverage before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build script: - yarn test after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESUL

First, we tell Travis to run our test with Node.js, then set the CC_TEST_REPORTER_ID global environment variable (we’ll get to this in the Code Climate section). In the matrix section, we tell Travis to run our tests with Node.js v12. We also want to cache the node_modules/ directory so it doesn’t have to be regenerated every time.

We install our dependencies using the yarn command which is a shorthand for yarn install. The before_script and after_script commands are used to upload coverage results to codeclimate. We’ll configure codeclimate shortly. After yarn test runs successfully, we want to also run yarn coverage which will upload our coverage report to coveralls.io.

Coveralls

Coveralls uploads test coverage data for easy visualization. We can view the test coverage on our local machine from the coverage folder, but Coveralls makes it available outside our local machine.

  1. Visit coveralls.io and either sign in or sign up with your Github account.
  2. Hover over the left-hand side of the screen to reveal the navigation menu. Click on ADD REPOS.
  3. Search for the express-api-template repo and turn on coverage using the toggle button on the left-hand side. If you can’t find it, click on SYNC REPOS on the upper right-hand corner and try again. Note that your repo has to be public, unless you have a PRO account.
  4. Click details to go to the repo details page.
  5. Create the .coveralls.yml file at the root of your project and enter the below code. To get the repo_token, click on the repo details. You will find it easily on that page. You could just do a browser search for repo_token.
repo_token: get-this-from-repo-settings-on-coveralls.io

This token maps your coverage data to a repo on Coveralls. Now, add the coverage command to the scripts section of your package.json file:

"coverage": "nyc report --reporter=text-lcov | coveralls"

This command uploads the coverage report in the .nyc_output folder to coveralls.io. Turn on your Internet connection and run:

yarn coverage

This should upload the existing coverage report to coveralls. Refresh the repo page on coveralls to see the full report.

On the details page, scroll down to find the BADGE YOUR REPO section. Click on the EMBED dropdown and copy the markdown code and paste it into your README file.

Code Climate

Code Climate is a tool that helps us measure code quality. It shows us maintenance metrics by checking our code against some defined patterns. It detects things such as unnecessary repetition and deeply nested for loops. It also collects test coverage data just like coveralls.io.

  1. Visit codeclimate.com and click on ‘Sign up with GitHub’. Log in if you already have an account.
  2. Once in your dashboard, click on Add a repository.
  3. Find the express-api-template repo from the list and click on Add Repo.
  4. Wait for the build to complete and redirect to the repo dashboard.
  5. Under Codebase Summary, click on Test Coverage. Under the Test coverage menu, copy the TEST REPORTER ID and paste it in your .travis.yml as the value of CC_TEST_REPORTER_ID.
  6. Still on the same page, on the left-hand navigation, under EXTRAS, click on Badges. Copy the maintainability and test coverage badges in markdown format and paste them into your README.md file.

It’s important to note that there are two ways of configuring maintainability checks. There are the default settings that are applied to every repo, but if you like, you could provide a .codeclimate.yml file at the root of your project. I’ll be using the default settings, which you can find under the Maintainability tab of the repo settings page. I encourage you to take a look at least. If you still want to configure your own settings, this guide will give you all the information you need.

AppVeyor

AppVeyor and Travis CI are both automated test runners. The main difference is that travis-ci runs tests in a Linux environment while AppVeyor runs tests in a Windows environment. This section is included to show how to get started with AppVeyor.

  • Visit AppVeyor and log in or sign up.
  • On the next page, click on NEW PROJECT.
  • From the repo list, find the express-api-template repo. Hover over it and click ADD.
  • Click on the Settings tab. Click on Environment on the left navigation. Add TEST_ENV_VARIABLE and its value. Click ‘Save’ at the bottom of the page.
  • Create the appveyor.yml file at the root of your project and paste in the below code.
environment: matrix: - nodejs_version: "12" install: - yarn test_script: - yarn test build: off

This code instructs AppVeyor to run our tests using Node.js v12. We then install our project dependencies with the yarn command. test_script specifies the command to run our test. The last line tells AppVeyor not to create a build folder.

Click on the Settings tab. On the left-hand navigation, click on badges. Copy the markdown code and paste it in your README.md file.

Commit your code and push to GitHub. If you have done everything as instructed all tests should pass and you should see your shiny new badges as shown below. Check again that you have set the environment variables on Travis and AppVeyor.

Repo CI/CD badges. (Large preview)

Now is a good time to commit our changes.

  • The corresponding branch in my repo is 05-ci.
Adding A Controller

Currently, we’re handling the GET request to the root URL, /v1, inside the src/routes/index.js. This works as expected and there is nothing wrong with it. However, as your application grows, you want to keep things tidy. You want concerns to be separated — you want a clear separation between the code that handles the request and the code that generates the response that will be sent back to the client. To achieve this, we write controllers. Controllers are simply functions that handle requests coming through a particular URL.

To get started, create a controllers/ folder inside the src/ folder. Inside controllers create two files: index.js and home.js. We would export our functions from within index.js. You could name home.js anything you want, but typically you want to name controllers after what they control. For example, you might have a file usersController.js to hold every function related to users in your app.

Open src/controllers/home.js and enter the code below:

import { testEnvironmentVariable } from '../settings'; export const indexPage = (req, res) => res.status(200).json({ message: testEnvironmentVariable });

You will notice that we only moved the function that handles the request for the / route.

Open src/controllers/index.js and enter the below code.

// export everything from home.js export * from './home';

We export everything from the home.js file. This allows us shorten our import statements to import { indexPage } from '../controllers';

Open src/routes/index.js and replace the code there with the one below:

import express from 'express'; import { indexPage } from '../controllers'; const indexRouter = express.Router(); indexRouter.get('/', indexPage); export default indexRouter;

The only change here is that we’ve provided a function to handle the request to the / route.

You just successfully wrote your first controller. From here it’s a matter of adding more files and functions as needed.

Go ahead and play with the app by adding a few more routes and controllers. You could add a route and a controller for the about page. Remember to update your test, though.

Run yarn test to confirm that we’ve not broken anything. Does your test pass? That’s cool.

This is a good point to commit our changes.

Connecting The PostgreSQL Database And Writing A Model

Our controller currently returns hard-coded text messages. In a real-world app, we often need to store and retrieve information from a database. In this section, we will connect our app to a PostgreSQL database.

We’re going to implement the storage and retrieval of simple text messages using a database. We have two options for setting a database: we could provision one from a cloud server, or we could set up our own locally.

I would recommend you provision a database from a cloud server. ElephantSQL has a free plan that gives 20MB of free storage which is sufficient for this tutorial. Visit the site and click on Get a managed database today. Create an account (if you don’t have one) and follow the instructions to create a free plan. Take note of the URL on the database details page. We’ll be needing it soon.

ElephantSQL turtle plan details page (Large preview)

If you would rather set up a database locally, you should visit the PostgreSQL and PgAdmin sites for further instructions.

Once we have a database set up, we need to find a way to allow our Express app to communicate with our database. Node.js by default doesn’t support reading and writing to PostgreSQL database, so we’ll be using an excellent library, appropriately named, node-postgres.

node-postgres executes SQL queries in node and returns the result as an object, from which we can grab items from the rows key.

Let’s connect node-postgres to our application.

# install node-postgres yarn add pg

Open settings.js and add the line below:

export const connectionString = process.env.CONNECTION_STRING;

Open your .env file and add the CONNECTION_STRING variable. This is the connection string we’ll be using to establish a connection to our database. The general form of the connection string is shown below.

CONNECTION_STRING="postgresql://dbuser:dbpassword@localhost:5432/dbname"

If you’re using elephantSQL you should copy the URL from the database details page.

Inside your /src folder, create a new folder called models/. Inside this folder, create two files:

  • pool.js
  • model.js

Open pools.js and paste the following code:

import { Pool } from 'pg'; import dotenv from 'dotenv'; import { connectionString } from '../settings'; dotenv.config(); export const pool = new Pool({ connectionString });

First, we import the Pool and dotenv from the pg and dotenv packages, and then import the settings we created for our postgres database before initializing dotenv. We establish a connection to our database with the Pool object. In node-postgres, every query is executed by a client. A Pool is a collection of clients for communicating with the database.

To create the connection, the pool constructor takes a config object. You can read more about all the possible configurations here. It also accepts a single connection string, which I will use here.

Open model.js and paste the following code:

import { pool } from './pool'; class Model { constructor(table) { this.pool = pool; this.table = table; this.pool.on('error', (err, client) => `Error, ${err}, on idle client${client}`); } async select(columns, clause) { let query = `SELECT ${columns} FROM ${this.table}`; if (clause) query += clause; return this.pool.query(query); } } export default Model;

We create a model class whose constructor accepts the database table we wish to operate on. We’ll be using a single pool for all our models.

We then create a select method which we will use to retrieve items from our database. This method accepts the columns we want to retrieve and a clause, such as a WHERE clause. It returns the result of the query, which is a Promise. Remember we said earlier that every query is executed by a client, but here we execute the query with pool. This is because, when we use pool.query, node-postgres executes the query using the first available idle client.

The query you write is entirely up to you, provided it is a valid SQL statement that can be executed by a Postgres engine.

The next step is to actually create an API endpoint to utilize our newly connected database. Before we do that, I’d like us to create some utility functions. The goal is for us to have a way to perform common database operations from the command line.

Create a folder, utils/ inside the src/ folder. Create three files inside this folder:

  • queries.js
  • queryFunctions.js
  • runQuery.js

We’re going to create functions to create a table in our database, insert seed data in the table, and to delete the table.

Open up queries.js and paste the following code:

export const createMessageTable = ` DROP TABLE IF EXISTS messages; CREATE TABLE IF NOT EXISTS messages ( id SERIAL PRIMARY KEY, name VARCHAR DEFAULT '', message VARCHAR NOT NULL ) `; export const insertMessages = ` INSERT INTO messages(name, message) VALUES ('chidimo', 'first message'), ('orji', 'second message') `; export const dropMessagesTable = 'DROP TABLE messages';

In this file, we define three SQL query strings. The first query deletes and recreates the messages table. The second query inserts two rows into the messages table. Feel free to add more items here. The last query drops/deletes the messages table.

Open queryFunctions.js and paste the following code:

import { pool } from '../models/pool'; import { insertMessages, dropMessagesTable, createMessageTable, } from './queries'; export const executeQueryArray = async arr => new Promise(resolve => { const stop = arr.length; arr.forEach(async (q, index) => { await pool.query(q); if (index + 1 === stop) resolve(); }); }); export const dropTables = () => executeQueryArray([ dropMessagesTable ]); export const createTables = () => executeQueryArray([ createMessageTable ]); export const insertIntoTables = () => executeQueryArray([ insertMessages ]);

Here, we create functions to execute the queries we defined earlier. Note that the executeQueryArray function executes an array of queries and waits for each one to complete inside the loop. (Don’t do such a thing in production code though). Then, we only resolve the promise once we have executed the last query in the list. The reason for using an array is that the number of such queries will grow as the number of tables in our database grows.

Open runQuery.js and paste the following code:

import { createTables, insertIntoTables } from './queryFunctions'; (async () => { await createTables(); await insertIntoTables(); })();

This is where we execute the functions to create the table and insert the messages in the table. Let’s add a command in the scripts section of our package.json to execute this file.

"runQuery": "babel-node ./src/utils/runQuery"

Now run:

yarn runQuery

If you inspect your database, you will see that the messages table has been created and that the messages were inserted into the table.

If you’re using ElephantSQL, on the database details page, click on BROWSER from the left navigation menu. Select the messages table and click Execute. You should see the messages from the queries.js file.

Let’s create a controller and route to display the messages from our database.

Create a new controller file src/controllers/messages.js and paste the following code:

import Model from '../models/model'; const messagesModel = new Model('messages'); export const messagesPage = async (req, res) => { try { const data = await messagesModel.select('name, message'); res.status(200).json({ messages: data.rows }); } catch (err) { res.status(200).json({ messages: err.stack }); } };

We import our Model class and create a new instance of that model. This represents the messages table in our database. We then use the select method of the model to query our database. The data (name and message) we get is sent as JSON in the response.

We define the messagesPage controller as an async function. Since node-postgres queries return a promise, we await the result of that query. If we encounter an error during the query we catch it and display the stack to the user. You should decide how choose to handle the error.

Add the get messages endpoint to src/routes/index.js and update the import line.

# update the import line import { indexPage, messagesPage } from '../controllers'; # add the get messages endpoint indexRouter.get('/messages', messagesPage)

Visit http://localhost:3000/v1/messages and you should see the messages displayed as shown below.

Messages from database. (Large preview)

Now, let’s update our test file. When doing TDD, you usually write your tests before implementing the code that makes the test pass. I’m taking the opposite approach here because we’re still working on setting up the database.

Create a new file, hooks.js in the test/ folder and enter the below code:

import { dropTables, createTables, insertIntoTables, } from '../src/utils/queryFunctions'; before(async () => { await createTables(); await insertIntoTables(); }); after(async () => { await dropTables(); });

When our test starts, Mocha finds this file and executes it before running any test file. It executes the before hook to create the database and insert some items into it. The test files then run after that. Once the test is finished, Mocha runs the after hook in which we drop the database. This ensures that each time we run our tests, we do so with clean and new records in our database.

Create a new test file test/messages.test.js and add the below code:

import { expect, server, BASE_URL } from './setup'; describe('Messages', () => { it('get messages page', done => { server .get(`${BASE_URL}/messages`) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.messages).to.be.instanceOf(Array); res.body.messages.forEach(m => { expect(m).to.have.property('name'); expect(m).to.have.property('message'); }); done(); }); }); });

We assert that the result of the call to /messages is an array. For each message object, we assert that it has the name and message property.

The final step in this section is to update the CI files.

Add the following sections to the .travis.yml file:

services: - postgresql addons: postgresql: "10" apt: packages: - postgresql-10 - postgresql-client-10 before_install: - sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf - sudo /etc/init.d/postgresql restart

This instructs Travis to spin up a PostgreSQL 10 database before running our tests.

Add the command to create the database as the first entry in the before_script section:

# add this as the first line in the before_script section - psql -c 'create database testdb;' -U postgres

Create the CONNECTION_STRING environment variable on Travis, and use the below value:

CONNECTION_STRING="postgresql://postgres:postgres@localhost:5432/testdb"

Add the following sections to the .appveyor.yml file:

before_test: - SET PGUSER=postgres - SET PGPASSWORD=Password12! - PATH=C:\Program Files\PostgreSQL\10\bin\;%PATH% - createdb testdb services: - postgresql101

Add the connection string environment variable to appveyor. Use the below line:

CONNECTION_STRING=postgresql://postgres:Password12!@localhost:5432/testdb

Now commit your changes and push to GitHub. Your tests should pass on both Travis CI and AppVeyor.

Note: I hope everything works fine on your end, but in case you should be having trouble for some reason, you can always check my code in the repo!

Now, let’s see how we can add a message to our database. For this step, we’ll need a way to send POST requests to our URL. I’ll be using Postman to send POST requests.

Let’s go the TDD route and update our test to reflect what we expect to achieve.

Open test/message.test.js and add the below test case:

it('posts messages', done => { const data = { name: 'some name', message: 'new message' }; server .post(`${BASE_URL}/messages`) .send(data) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.messages).to.be.instanceOf(Array); res.body.messages.forEach(m => { expect(m).to.have.property('id'); expect(m).to.have.property('name', data.name); expect(m).to.have.property('message', data.message); }); done(); }); });

This test makes a POST request to the /v1/messages endpoint and we expect an array to be returned. We also check for the id, name, and message properties on the array.

Run your tests to see that this case fails. Let’s now fix it.

To send post requests, we use the post method of the server. We also send the name and message we want to insert. We expect the response to be an array, with a property id and the other info that makes up the query. The id is proof that a record has been inserted into the database.

Open src/models/model.js and add the insert method:

async insertWithReturn(columns, values) { const query = ` INSERT INTO ${this.table}(${columns}) VALUES (${values}) RETURNING id, ${columns} `; return this.pool.query(query); }

This is the method that allows us to insert messages into the database. After inserting the item, it returns the id, name and message.

Open src/controllers/messages.js and add the below controller:

export const addMessage = async (req, res) => { const { name, message } = req.body; const columns = 'name, message'; const values = `'${name}', '${message}'`; try { const data = await messagesModel.insertWithReturn(columns, values); res.status(200).json({ messages: data.rows }); } catch (err) { res.status(200).json({ messages: err.stack }); } };

We destructure the request body to get the name and message. Then we use the values to form an SQL query string which we then execute with the insertWithReturn method of our model.

Add the below POST endpoint to /src/routes/index.js and update your import line.

import { indexPage, messagesPage, addMessage } from '../controllers'; indexRouter.post('/messages', addMessage);

Run your tests to see if they pass.

Open Postman and send a POST request to the messages endpoint. If you’ve just run your test, remember to run yarn query to recreate the messages table.

yarn query POST request to messages endpoint. (Large preview) GET request showing newly added message. (Large preview)

Commit your changes and push to GitHub. Your tests should pass on both Travis and AppVeyor. Your test coverage will drop by a few points, but that’s okay.

Middleware

Our discussion of Express won’t be complete without talking about middleware. The Express documentation describes a middlewares as:

“[...] functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.”

A middleware can perform any number of functions such as authentication, modifying the request body, and so on. See the Express documentation on using middleware.

We’re going to write a simple middleware that modifies the request body. Our middleware will append the word SAYS: to the incoming message before it is saved in the database.

Before we start, let’s modify our test to reflect what we want to achieve.

Open up test/messages.test.js and modify the last expect line in the posts message test case:

it('posts messages', done => { ... expect(m).to.have.property('message', `SAYS: ${data.message}`); # update this line ... });

We’re asserting that the SAYS: string has been appended to the message. Run your tests to make sure this test case fails.

Now, let’s write the code to make the test pass.

Create a new middleware/ folder inside src/ folder. Create two files inside this folder:

  • middleware.js
  • index.js

Enter the below code in middleware.js:

export const modifyMessage = (req, res, next) => { req.body.message = `SAYS: ${req.body.message}`; next(); };

Here, we append the string SAYS: to the message in the request body. After doing that, we must call the next() function to pass execution to the next function in the request-response chain. Every middleware has to call the next function to pass execution to the next middleware in the request-response cycle.

Enter the below code in index.js:

# export everything from the middleware file export * from './middleware';

This exports the middleware we have in the /middleware.js file. For now, we only have the modifyMessage middleware.

Open src/routes/index.js and add the middleware to the post message request-response chain.

import { modifyMessage } from '../middleware'; indexRouter.post('/messages', modifyMessage, addMessage);

We can see that the modifyMessage function comes before the addMessage function. We invoke the addMessage function by calling next in the modifyMessage middleware. As an experiment, comment out the next() line in the modifyMessage middle and watch the request hang.

Open Postman and create a new message. You should see the appended string.

Message modified by middleware. (Large preview)

This is a good point to commit our changes.

Error Handling And Asynchronous Middleware

Errors are inevitable in any application. The task before the developer is how to deal with errors as gracefully as possible.

In Express:

Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously.

If we were only writing synchronous functions, we might not have to worry so much about error handling as Express already does an excellent job of handling those. According to the docs:

“Errors that occur in synchronous code inside route handlers and middleware require no extra work.”

But once we start writing asynchronous router handlers and middleware, then we have to do some error handling.

Our modifyMessage middleware is a synchronous function. If an error occurs in that function, Express will handle it just fine. Let’s see how we deal with errors in asynchronous middleware.

Let’s say, before creating a message, we want to get a picture from the Lorem Picsum API using this URL https://picsum.photos/id/0/info. This is an asynchronous operation that could either succeed or fail, and that presents a case for us to deal with.

Start by installing Axios.

# install axios yarn add axios

Open src/middleware/middleware.js and add the below function:

export const performAsyncAction = async (req, res, next) => { try { await axios.get('https://picsum.photos/id/0/info'); next(); } catch (err) { next(err); } };

In this async function, we await a call to an API (we don’t actually need the returned data) and afterward call the next function in the request chain. If the request fails, we catch the error and pass it on to next. Once Express sees this error, it skips all other middleware in the chain. If we didn’t call next(err), the request will hang. If we only called next() without err, the request will proceed as if nothing happened and the error will not be caught.

Import this function and add it to the middleware chain of the post messages route:

import { modifyMessage, performAsyncAction } from '../middleware'; indexRouter.post('/messages', modifyMessage, performAsyncAction, addMessage);

Open src/app.js and add the below code just before the export default app line.

app.use((err, req, res, next) => { res.status(400).json({ error: err.stack }); }); export default app;

This is our error handler. According to the Express error handling doc:

“[...] error-handling functions have four arguments instead of three: (err, req, res, next).”

Note that this error handler must come last, after every app.use() call. Once we encounter an error, we return the stack trace with a status code of 400. You could do whatever you like with the error. You might want to log it or send it somewhere.

This is a good place to commit your changes.

Deploy To Heroku
  1. To get started, go to https://www.heroku.com/ and either log in or register.
  2. Download and install the Heroku CLI from here.
  3. Open a terminal in the project folder to run the command.
# login to heroku on command line heroku login

This will open a browser window and ask you to log into your Heroku account.

Log in to grant your terminal access to your Heroku account, and create a new heroku app by running:

#app name is up to you heroku create app-name

This will create the app on Heroku and return two URLs.

# app production url and git url https://app-name.herokuapp.com/ | https://git.heroku.com/app-name.git

Copy the URL on the right and run the below command. Note that this step is optional as you may find that Heroku has already added the remote URL.

# add heroku remote url git remote add heroku https://git.heroku.com/my-shiny-new-app.git

Open a side terminal and run the command below. This shows you the app log in real-time as shown in the image.

# see process logs heroku logs --tail Heroku logs. (Large preview)

Run the following three commands to set the required environment variables:

heroku config:set TEST_ENV_VARIABLE="Environment variable is coming across." heroku config:set CONNECTION_STRING=your-db-connection-string-here. heroku config:set NPM_CONFIG_PRODUCTION=false

Remember in our scripts, we set:

"prestart": "babel ./src --out-dir build", "start": "node ./build/bin/www",

To start the app, it needs to be compiled down to ES5 using babel in the prestart step because babel only exists in our development dependencies. We have to set NPM_CONFIG_PRODUCTION to false in order to be able to install those as well.

To confirm everything is set correctly, run the command below. You could also visit the settings tab on the app page and click on Reveal Config Vars.

# check configuration variables heroku config

Now run git push heroku.

To open the app, run:

# open /v1 route heroku open /v1 # open /v1/messages route heroku open /v1/messages

If like me, you’re using the same PostgresSQL database for both development and production, you may find that each time you run your tests, the database is deleted. To recreate it, you could run either one of the following commands:

# run script locally yarn runQuery # run script with heroku heroku run yarn runQuery Continuous Deployment (CD) With Travis

Let’s now add Continuous Deployment (CD) to complete the CI/CD flow. We will be deploying from Travis after every successful test run.

The first step is to install Travis CI. (You can find the installation instructions over here.) After successfully installing the Travis CI, login by running the below command. (Note that this should be done in your project repository.)

# login to travis travis login --pro # use this if you’re using two factor authentication travis login --pro --github-token enter-github-token-here

If your project is hosted on travis-ci.org, remove the --pro flag. To get a GitHub token, visit the developer settings page of your account and generate one. This only applies if your account is secured with 2FA.

Open your .travis.yml and add a deploy section:

deploy: provider: heroku app: master: app-name

Here, we specify that we want to deploy to Heroku. The app sub-section specifies that we want to deploy the master branch of our repo to the app-name app on Heroku. It’s possible to deploy different branches to different apps. You can read more about the available options here.

Run the below command to encrypt your Heroku API key and add it to the deploy section:

# encrypt heroku API key and add to .travis.yml travis encrypt $(heroku auth:token) --add deploy.api_key --pro

This will add the below sub-section to the deploy section.

api_key: secure: very-long-encrypted-api-key-string

Now commit your changes and push to GitHub while monitoring your logs. You will see the build triggered as soon as the Travis test is done. In this way, if we have a failing test, the changes would never be deployed. Likewise, if the build failed, the whole test run would fail. This completes the CI/CD flow.

  • The corresponding branch in my repo is 11-cd.
Conclusion

If you’ve made it this far, I say, “Thumbs up!” In this tutorial, we successfully set up a new Express project. We went ahead to configure development dependencies as well as Continuous Integration (CI). We then wrote asynchronous functions to handle requests to our API endpoints — completed with tests. We then looked briefly at error handling. Finally, we deployed our project to Heroku and configured Continuous Deployment.

You now have a template for your next back-end project. We’ve only done enough to get you started, but you should keep learning to keep going. Be sure to check out the express docs as well. If you would rather use MongoDB instead of PostgreSQL, I have a template here that does exactly that. You can check it out for the setup. It has only a few points of difference.

Resources Smashing Editorial (ks, yk, il)
Catégories: Programmation

Smashing Podcast Episode 13 With Laura Kalbag: What Is Online Privacy?

mar, 04/07/2020 - 09:00
Smashing Podcast Episode 13 With Laura Kalbag: What Is Online Privacy? Smashing Podcast Episode 13 With Laura Kalbag: What Is Online Privacy? Drew McLellan 2020-04-07T07:00:00+00:00 2020-04-07T09:35:11+00:00

Laura KalbagIn this episode of the Smashing Podcast, we’re talking about online privacy. What should web developers be doing to make sure the privacy of our users is maintained? I spoke to Laura Kalbag to find out.

Show Notes Weekly Update Transcript

Drew McLellan: She’s a designer from the UK, but now based in Ireland, she’s co-founder of the Small Technology Foundation. You’ll often find her talking about rights-respecting design, accessibility and inclusivity, privacy, and web design and development, both on her personal website and with publications such as Smashing magazine. She’s the author of the book Accessibility for Everyone from A Book Apart. And with the Small Technology Foundation, she’s part of the team behind Better Blocker, a tracking blocker tool for Safari on iOS and Mac. So we know she’s an expert in inclusive design and online privacy, but did you know she took Paris Fashion Week by storm wearing a kilt made out of spaghetti. My Smashing friends, please welcome Laura Kalbag.

Laura Kalbag: Hello.

Drew: Hello Laura, how are you?

Laura: I am smashing.

Drew: I wanted to talk to you today about the topic of online privacy and the challenges around being an active participant online without seeding too much of your privacy and personal data to companies who may or may not be trustworthy. This is an area that you think about a lot, isn’t it?

Laura: Yeah. And I don’t just think about the role of us as consumers in that, but also as people who work on the web, our role in actually doing it and how much we’re actually making that a problem for the rest of society as well.

Drew: As a web developer growing up in the ‘90s as I did, for me maintaining an active presence online involved basically building and updating my own website. Essentially, it was distributed technology but it was under my control. And these days it seems like it’s more about posting on centralized commercially operated platforms such as Twitter and Facebook, the obvious ones. That’s a really big shift in how we publish stuff online. Is it a problem?

Laura: Yeah. And I think we have gone far away from those decentralized distributed ways of posting on our own websites. And the problem is that we are essentially posting everything on somebody else’s website. And not only does that mean that we’re subject to their rules, which in some cases is a good thing, you don’t necessarily want to be on a website that is full of spam, full of trolls, full of Nazi content, we don’t want to be experiencing that. But also we have no control over whether we get kicked off, whether they decide to censor us in any way. But also everything underlying on that platform. So whether that platform is knowing where we are at all times because it’s picking up on our location. Whether it is reading our private messages because if it’s not end-to-end encrypted, if we’re sending direct messages to each other, that could be accessed by the company.

Laura: Whether it’s actively, so whether people working there could actually just read your messages. Or passively, where they are just sucking up the stuff from inside your messages and using that to build profiles about you, which they can then use to target you with ads and stuff like that. Or even combine that information with other datasets and sell that on to other people as well.

Drew: It can be quite terrifying, can’t it? Have what you considered to be a private message with somebody on a platform like Facebook, using Facebook Messenger, and find the things you’ve mentioned in a conversation then used to target ads towards you. It’s not something you think you’ve shared but it is something you’ve shared with the platform.

Laura: And I have a classic example of this that happened to me a few years ago. So, I was on Facebook, and my mom had just died, and I was getting ads for funeral directors. And I thought is was really strange because none of my family had said anything on a social media platform at that point, none of my family had said anything on Facebook because we’d agreed that no one wants to find out that kind of thing about a friend or family member via Facebook so we’d not say about it. And then, so I asked my siblings, “Have any of you said anything on Facebook that might cause this strange?” Because I just usually just get ads for make-up, and dresses, and pregnancy tests, and all those fun things they like to target women of a certain age. And my sister got back to me, she said, “Well, yeah, my friend lives in Australia so I sent her a message on Messenger, Facebook Messenger, and told her that our mom had died.”

Laura: And of course Facebook knew that we’re sisters, it has that relationship connection that you can choose to add on there, it could probably guess we were sisters anyway by the locations we’ve been together, the fact that we share a surname. And decided that’s an appropriate ad to put in her feed.

Drew: It’s sobering, isn’t it? To think that technology is making these decisions for us that actually affects people, potentially in this example, in quite a sensitive or vulnerable time.

Laura: Yeah. We say it’s creepy, but a lot of the time people say it’s almost like the microphone on my phone or my laptop was listening to me because I was just having this conversation about this particular product and suddenly it’s appearing in my feed everywhere. And I think what’s actually scary is the fact that most of them don’t have access to your microphone, but it’s the fact that your other behaviors, your search, the fact that it knows who you’re talking to because of your proximity to each other and your location on your devices. It can connect all of those things that we might not connect ourselves together in order to say, maybe they’ll be interested in this product because they’ll probably think you’re talking about it already.

Drew: And of course, it’s not as simple as just rolling back the clock and going back to a time where if you wanted to be online, you had to create your own website because there’s technical barriers to that, there’s cost barriers. And you only need to look at the explosion of things like sharing video online, there’s not an easy way to share a video online in the same way you can just by putting it on YouTube, or uploading it to Facebook, or onto Twitter, there are technical challenges there.

Laura: It’s not fair to blame anyone for it because using the web today and using these platforms today is part of participating in society. You can’t help it if your school has a Facebook group for all the parents. You can’t help it if you have to use a website that, in order to get some vital information. It’s part of our infrastructure now, particularly nowadays when everyone is suddenly relying video calling and things like that so much more. These are our infrastructure, they are as used and as important as our roads, as our utilities, so we need to have them treated accordingly. And we can’t blame people for using them, especially if there aren’t any alternatives that are better.

Drew: When the suggestion is using these big platforms that it’s easy and it’s free, but is it free?

Laura: No, because you’re paying with your personal information. And I hear a lot of developers saying things like, “Oh well, I’m not interesting, I don’t really care, it’s not really a problem for me.” And we have to think about the fact that we’re often in quite a privileged group. What about people that are more vulnerable? We think about people who have parts of their identity that they don’t necessarily want to share publicly, they don’t want to be outed by platforms to their employers, to their government. People who are in domestic abuse situations, we think about people who are scared of their governments and don’t want to spied on. That’s a huge number of people across the world, we can’t just say, “Oh well, it’s fine for me, so it has to be fine for everybody else,” it’s just not fair.

Drew: It doesn’t have to be a very big issue you’re trying to conceal from the world to be worried about what a platform might share about you.

Laura: Yeah. And the whole thing about privacy is that it isn’t about having something to hide, it’s about choosing what you want to share. So you might not feel like you have anything in particular that you want to hide, but it doesn’t necessarily mean you put a camera in your bedroom and broadcast it 24 hours, there’s things we do and don’t want to share.

Drew: Because there are risks as well in sharing social content, things like pictures of family and friends. That we could be sacrificing other peoples privacy without them really being aware, is that a risk?

Laura: Yeah. And I think that that applies to a lot of different things as well. So it’s not just if you’re uploading things of people you know and then they’re being added to facial recognition databases, which is happening quite a lot of the time. These very dodgy databases, they’ll scrape social media sites to make their facial recognition databases. So Clearview is an example of a company that’s done that, they’ve scraped images off Facebook and used those. But also things like email, you might choose… I’m not going to use Gmail because I don’t want Google to have access to everything in my email, which is everything I’ve signed up for, every event I’m attending, all of my personal communication, so I decide not to use it. But if I’m communicating with someone who uses Gmail, well, they’ve made that decision on my behalf, that everything I email them will be shared with Google.

Drew: You say that, often from a privileged position, we think okay, we’re getting all this technology, all these platforms are being given to us for free, we’re not having to pay for it, all we got to do is… We’re giving up a little bit of privacy, but that’s okay, that’s an acceptable trade-off. But is it an acceptable trade-off?

Laura: No. It’s certainly not an acceptable trade-off. But I think it’s also because you don’t necessarily immediately see the harms that are caused by giving these things up. You might feel like you’re in a safe situation today, but you may not be tomorrow. I think a good example is Facebook, they’ve actually got a pattern for approving or disproving loans based on the financial status of your friends on Facebook. So thinking, oh well, if your friend owes lots of money, and a lot of your friends owes lots of money, you’re more likely to be in that same situation as them. So all these systems, all of these algorithms, they are making decisions and influencing our lives and we have no say on them. So it’s not necessarily about what we’re choosing to share and what we’re choosing not to share in terms of something we put in a status, or a photo, or a video, but it’s also about all of this information that is derived about us from our activity on these platforms.

Laura: Things about our locations or whether we have a tendency to be out late at night, the kinds of people that we tend to spend our time with, all of this information can be collected by these platforms too and then they’ll make decisions about us based on that information. And we not only don’t have access to what’s being derived about us, we have no way of seeing it, we have no way of changing it, we have no way of removing it, bar a few things that we could do if we’re in the EU based on GDPR, if you’re in California based on their regulation there that you can go in and ask companies what data they have on you and ask them to delete it. But then what data counts under that situation? Just the data they’ve collected about you? What about the data they’ve derived and created by combining your information with other people’s information and the categories they’ve put you in, things like that. We have no transparency on that information.

Drew: People might say that this is paranoia, this is tinfoil hat stuff. And really all that these companies are doing is collecting data to show us different ads. And okay, there’s the potential for these other things, but they’re not actually doing that. All they’re doing is just tailoring ads to us. Is that the case or is this data actually actively being used in more malicious ways than just showing ads?

Laura: No. We’ve seen in many, many occasions how this information is being used in ways other than just ads. And even if one company decides to just collect it based on ads, they then later might get sold to or acquired by an organization that decides to do something different with that data and that’s parts of the problem with collecting the data at all in the first place. And it’s also a big risk to things like hacking, if you’re creating a big centralized database with people’s information, their phone numbers, their email addresses, even just the most simple stuff, that’s really juicy data for hackers. And that’s why we see massive scale hacks that result in a lot of people’s personal information ending up being publicly available. It’s because a company decided it was a good idea to collect of that information in one place in the first place.

Drew: Are there ways then that we can use these platforms, interact with friends and family that are also on these platforms, Facebook is the obvious example where you might have friends and family all over the world and Facebook is the place where they communicate. Are there ways that you can participate in that and not be giving up privacy or is it just something that if you want to be on that platform, you just have to accept?

Laura: I think there’s different layers, depending on what we would call your threat model is. So depending how vulnerable you are, but also your friends and family, and what your options are. So yeah, the ultimate thing is to not use these platforms at all. But if you do, try to use them more than they use you. So if you have things that you’re communicating one-on-one, don’t use Messenger for that because there are plenty of alternatives for one-on-one direct communication that can be end-to-end encrypted or is private and you don’t have to worry about Facebook listening in on it. And there’s not really much you can do about things like sharing your location data and stuff like that, which is really valuable information. It’s all of your meta information that’s so valuable, it’s not even necessarily the content of what you’re saying, but who you’re with and where you are when you’re saying it. That’s the kind of stuff that’s useful that companies would use to put you in different categories and be able to sell things to you accordingly or group you accordingly.

Laura: So I think we can try to use them as little as possible. I think it’s important to seek alternatives, particularly if you’re a person who is more technically savvy in your group of friends and family, you can always encourage other people to join other things as well to have. So use Wire for messaging, that’s a nice little platform that’s available in lots of places and is private. Or Signal is another option that’s just like WhatsApp but it’s end-to-end encrypted as well. And if you can be that person, I think there’s two points that we have to really forget about. One, is the idea that everyone needs to be on a platform for it to be valuable. The benefit is that everyone’s on Facebook, that’s actually the downside as well, that everyone’s on Facebook. You don’t need everyone you know to suddenly be on the same platform as you. As long as you have those few people you want to communicate with regularly on a better platform, that’s a really good start.

Laura: And the other thing that we need to embrace, we’re not going to find an alternative to a particular platform that does everything that platform does as well. You’re not going to find an alternative to Facebook that does messaging, that has status updates, that has groups, that has events, that has live, that has all of this stuff. Because the reason Facebook can do that is because Facebook is massive, Facebook has these resources, Facebook has a business model that really makes a lot out of all that data and so it’s really beneficial to provide all those services to you. And so we have to change our expectations and maybe be like, “Well okay, what’s the one function I need? To be able to share a photo. Well, let’s find the thing that I can do that will help me just share that photo.” And not be expecting just another great big company to do the right thing for us.

Drew: Is this something that RSS can help us with? I tend to think RSS is the solution to most problems, but I was thinking here if you have a service for photo sharing, and something else for status updates, and something else for all these different things is RSS the solution that brings it all together to create a virtual… That encompasses all these services?

Laura: I’m with you on that for lots of things. I, myself, I’ve built into my own site, I have a section for photos, a section for status updates, as well as my blog and stuff. So that I can allow people to, if they don’t follow me on social media platforms, if I’m posting the same stuff to my site, they can use RSS to access it and they’re not putting themselves at risk. And that’s one of the ways that I see as just a fairly ordinary designer/developer that I can not force other people to use those platforms in order to join in with me. And RSS is really good for that. RSS can have tracking, I think people can do stuff with it, but it’s rare and it’s not the point of it. That’s what I think RSS is a really good standard for.

Drew: As a web developer, I’m aware when I’m building sites that I’m frequently being required to add JavaScript from Google for things like analytics or ads, and from Facebook for like and share actions, and all that sort of thing, and from various other places, Twitter, and you name it. Are those something that we need to worry about in terms of developers or as users of the web? That there’s this code executing that it’s origin is on google.com or facebook.com?

Laura: Yes. Absolutely. I think Google is a good example here of things like web fonts and libraries and stuff like that. So people are encouraged to use them because they’re told well, it’s going to very performant, it’s on Google servers, Google will grab it from the closest part of the world, you’ll have a brilliant site just by using, say a font off Google rather than embedding it, self-hosting it on your own site. There’s a reason why Google offers up all of those fonts for free and it’s not out of the goodness of their Googley little hearts, it is because they get something out of it. And what they get is, they get access to your visitors on your website when you include their script on your website. So I think it’s not just something we should be worried about as developers, I think that it’s our responsibility to know what our site is doing and know what a third party script is doing or could do, because they could change it and you don’t necessarily have control over that as well. Know what their privacy policies are and things like that before we use them.

Laura: And ideally, don’t use them at all. If we can self-host things, self-host things, a lot of the time it’s easier. If we don’t need to provide a login with Google or Facebook, don’t do it. I think we can be the gatekeepers in this situation. We as the people who have the knowledge and the skills in this area, we can be the ones that can go back to our bosses or our managers and say, “Look, we can provide this login with Facebook or we could build our own login, it will be private, it would be safer. Yeah, it might take a little bit more work but actually we’ll be able to instill more trust in what we’re building because we don’t have that association with Facebook.” Because what we’re seeing now, over time, is that even mainstream media is starting to catch up with the downsides of Facebook, and Google, and these other organizations.

Laura: And so we end up being guilty by association even if we’re just trying to make the user experience easier by adding a login where someone doesn’t have to create a new username and password. And so I think we really do need to take that responsibility and a lot of it is about valuing people’s rights and respecting their rights and their privacy over our own convenience. Because of course it’s going to be much quicker just to add that script to the page, just to add another package in without investigating what it actually does. We’re giving up a lot when we do that and I think that we need to take responsibility not to.

Drew: As web developers are there other things that we should be looking out for when it comes to protecting the privacy of our own customers in the things that we build?

Laura: We shouldn’t be collecting data at all. And I think most of the time, you can avoid it. Analytics is one of my biggest bugbears because I think that a lot of people get all these analytics scripts, all these scripts that can see what people are doing on your website and give you insights and things like that, but I don’t think we use them particularly well. I think we use them to confirm our own assumptions and all we’re being taught about is what is already on our site. It’s not telling us anything that research and actually talking to people who use our websites… We could really benefit more from that than just looking at some numbers go up and down, and guessing what the effect of that is or why it’s happening. So I think that we need to be more cautious around anything that we’re putting on our sites and anything that we’re collecting. And I think nowadays we’re also looking at regulatory and legal risks as well when we’re starting to collect people’s data.

Laura: Because when we look at things like the GDPR, we’re very restricted in what we are allowed to collect and the reasons why we’re allowed to collect it. And that’s why we’re getting all of these consent notifications and things like that coming up now. Because companies have to have your explicit consent for collecting any data that is not associated with vital function for the website. So if you’re using something like a login, you don’t need to get permission to store someone’s email and password for a login because that is implied by logging in, you need that. But things like analytics and stuff like that, you actually need to get explicit consent in order to be able to spy on the people visiting the website. So this is why we see all of these consent boxes, this is why we should actually be including them on our websites if we’re using analytics and other tools that are collecting data that aren’t vital to the functioning of the page.

Drew: I think about some of even just the side projects and things that I’ve launched, that just almost as a matter of routine I’ve put Google analytics on there. I think, “Oh, I need to track how many people are visiting.” And then I either never look at it or I only look at it to gain an understanding of the same things that I could’ve just got from server logs like we used to do in the old days, just by crunching over their web access logs.

Laura: Exactly. And yet Google is sitting there going, “Thank you very much.” Because you’ve instilled another input for them on the website. And I think once you start thinking about it, once you adjust your brain to taking this other way of looking at it, it’s much easier to start seeing the vulnerabilities. But we do have to train ourselves to think in that way, to think about how can we harm people with what we’re building, who could lose out from this, and try to build things that are a bit more considerate of people.

Drew: There’s an example, actually, that I can think of where Google analytics itself was used to breach somebody’s privacy. And that was the author of Belle de Jour, The Secret Diary of a Call Girl, who was a London call girl who kept a blog for years and it was all completely anonymous. And she diarized her daily life. And it was incredibly successful, and it became a book, and a TV series, and what have you. She was intending to be completely anonymous, but she was eventually found out. Her identity was revealed because she used the same Google analytics tracking user id on her personal blog where she was her professional self and on the call girl blog as well. And that’s how she was identified, just-

Laura: So she did it to herself in that way as well.

Drew: She did it to herself. Yeah. She leaked personal data there that she didn’t mean to leak. She didn’t even know it was personal data, I suspect. There are so many implications that you just don’t think of. And so I think it pays to start thinking of it.

Laura: Yeah. And not doing things because you feel that that’s what we always did, and that’s what we always do, or that’s what this other organization that I admire, they do it, so I should, I think. And a lot of the time it is about being a bit more restrictive and maybe not jumping on the bandwagon of I’m going to use this service like everybody else is. And stopping, reading their privacy policy, which is not something I recommend doing for fun, because it’s really tedious, and I have to do a lot of it when I’m looking into trackers for Better. But you can see a lot of red flags if you read privacy policies. You see the kinds of language that means that they’re trying to make it free and easy for them to do whatever they want with your information. And there’s a reason why I say to designers and developers, if you’re making your own projects, don’t just copy the privacy policy from somebody else. Because you might be opening yourself up to more issues and you might actually be making yourself look suspicious.

Laura: It’s much better to be transparent and clear about what you’re doing, everything doesn’t need to be written in legal ease in order for you to be clear about what you’re doing with people’s information.

Drew: So, in almost anything, people say that the solution to it is to use the JAMstack. Is the JAMstack a solution, is it a good answer, is it going to help us out of accidentally breaching the privacy of our customers?

Laura: There’s a lot of stuff I like about the JAMstack stuff, but I would say I like the “JMstack”, because it’s the APIs bit that worries me. Because if we’re taking control over our own sites, we’re building static sites, and we’re generating it all on our machines, and we’re not using servers, and that’s great that we’ve taken away a lot potential issues there. But then if we’re adding back in all of the third party functionality using APIs, we may as well be adding script tags to our pages all over again. We may as well have it on somebody else’s platform. Because we’re losing that control again. Because every time we’re adding something from a third party, we’re losing control over a little bit of our site. So I think that a lot of static site generators and things like that have a lot of value, but we still need to be cautious.

Laura: And I think one of the reasons why we love the jam stack stuff because again, it’s allowed us to knock up a site really quickly, deploy it really quickly, have a development environment set up really quickly, and we’re valuing again, our developer experience over that of the people that are using the websites.

Drew: So I guess the key there is to just be hyperaware of what every API you’re using is doing. What data you could be sending to them, what their individual privacy policies are.

Laura: Yeah. And I think we have to be cautious about being loyal to companies. We might have people that we are friends with and think are great and things like that, that are working for these companies. We might that they are producing some good work, they’re doing good blogs, they’re introducing some interesting new technologies into the world. But at the end of the day, businesses are businesses. And they all have business models. And we have to know what are their business models. How are they making their money? Who is behind the money? Because a lot of venture capital backed organizations end up having to deal in personal data, and profiling, and things like that, because it’s an easy way to make money. And it is hard to build a sustainable business on technology, particularly if you’re not selling a physical product, it’s really hard to make a business sustainable. And if an organization has taken a huge amount of money and they’re paying a huge amount of employees, they’ve got to make some money back somehow.

Laura: And that’s what we’re seeing now is, so many businesses doing what Shoshana Zuboff refers to as surveillance capitalism, tracking people, profiling them, and monetizing that information because it’s the easiest way to make money on the web. And I think that the rest of us have to try to resist it because it can be very tempting to jump in and do what everyone else is doing and make big money, and make a big name. But I think that we’re realizing too slowly the impact that that has on the rest of our society. The fact that Cambridge Analytica only came about because Facebook was collecting massive amounts of people’s information and Cambridge Analytica was just using that information in order to target people with, essentially, propaganda in order to make referendums and elections of their way. And that’s terrifying, that’s a really scary effect that’s come out of what you might think is an innocuous little banner ad.

Drew: Professionally, many people are transitioning into building client sites or helping their clients to build their own sites on platforms like Squarespace and that sort of thing, online site builders where sites are then completely hosted on that service. Is that an area that they should also be worried about in terms of privacy?

Laura: Yeah. Because you’re very much subject to the privacy policies of those platforms. And while a lot of them are paid platforms, so just because it’s a platform doesn’t necessarily mean that they are tracking you. But the inverse is also true, just because you’re paying for it, doesn’t mean they’re not tracking you. I’d use Spotify as an example of this. People pay Spotify a lot of money for their accounts. And Spotify does that brilliant thing where it shows off how much it’s tracking you by telling people all of this incredible information about them on a yearly basis, and giving them playlists for their moods, and things like that. And then you realize, oh, actually, Spotify knows what my mood is because I’m listening to a playlist that’s made for this mood that I’m in. And Spotify is with me when I’m exercising. And Spotify knows when I’m working. And Spotify knows when I’m trying to sleep. And whatever other playlists you’ve set up for it, whatever other activities you’ve done.

Laura: So I think we just have to look at everything that a business is doing in order to work out whether it’s a threat to us and really treat everything as though it could possibly cause harm to us, and use it carefully.

Drew: You’ve got a fantastic personal website where you collate all the things that you’re working on and things that you share socially. I see that your site is built using Site.js. What’s that?

Laura: Yes. So it’s something that we’ve been building. So what we do at the Small Technology Foundation, or what we did when we were called Ind.ie, which was the UK version of the Small Technology Foundation, is that we’re tying to work on how do we help in this situation. How do we help in a world where technology is not respecting people’s rights? And we’re a couple of designers and developers, so what is our skills? And the way we see it is we have to do a few different things. We have to first of all, prevent some of the worst harms if we can. And one of the ways we do that is having a tracker blocker, so it’s something that blocks trackers on the web, with their browser. And another thing we do is, we try to help inform things like regulation, and we campaign for better regulation and well informed regulation that is not encouraging authoritarian governments and is trying to restrict businesses from collecting people’s personal information.

Laura: And the other thing we can do is, we can try to build alternatives. Because one of the biggest problems with technology and with the web today is that there’s not actually much choice when you want to build something. A lot of things are built in the same way. And we’ve been looking at different ways of doing this for quite a few years now. And the idea behind Site.js is to make it really easy to build and deploy a personal website that is secure, has the all the HTTPS stuff going on and everything, really, really, easily. So it’s something that really benefits the developer experience, but doesn’t threaten the visitor’s experience at the same time. So it’s something that is also going to keep being rights respecting, that you have full ownership and control over as the developer of your own personal website as well. And so that’s what Site.js does.

Laura: So we’re just working on ways for people to build personal websites with the idea that in the future, hopefully those websites will also be able to communicate easily with each other. So you could use them to communicate with each other and it’s all in your own space as well.

Drew: You’ve put a lot of your expertise in this area to use with Better Blocker. You must see some fairly wild things going on there as you’re updating it and…

Laura: Yeah. You can always tell when I’m working on Better because that’s when my tweets get particularly angry and cross, because it makes me so irritated when I see what’s going on. And it also really annoys me because I spend a lot of time looking at websites, and working out what the scripts are doing, and what happens when something is blocked. One of the things that really annoys me is how developers don’t have fallbacks in their code. And so the amount of times that if you block something, for example, I block an analytics script, and if you block an analytics script, all the links stop working on the webpage, then you’re probably not using the web properly if you need JavaScript to use a link. And so I wish that developers bear that in mind, especially when they think about maybe removing these scripts from their sites. But the stuff I see is they…

Laura: I’ve seen, like The Sun tabloid newspaper, everybody hates it, it’s awful. They have about 30 different analytics scripts on every page load. And to some degree I wonder whether performance would be such a hot topic in the industry if we weren’t all sticking so much junk on our webpages all the time. Because, actually, you look at a website that doesn’t have a bunch of third party tracking scripts on, tends to load quite quickly. Because you’ve got to do a huge amount to make a webpage heavy if you haven’t got all of that stuff as well.

Drew: So is it a good idea for people who build for the web to be running things like tracker blockers and ad blockers or might it change our experience of the web and cause problems from a developer point of view?

Laura: I think in the same way that we test things across different browsers and we might have a browser that we use for our own consumer style, I hate the word consumer, use, just our own personal use, like our shopping and our social stuff, and things like that. And we wouldn’t only test webpages in that browser, we test webpages in as many browsers can get our hands on because that’s what makes us good developers. And I think the same should be for if you’re using a tracker blocker or an ad blocker in your day-to-day, then yeah, you should try it without as well. Like I keep Google Chrome on my computer for browser testing, but you can be sure that I will not be using that browser for any of my personal stuff, ever, it’s horrible. So yeah, you’ve got to be aware of what’s going in the world around you as part of your responsibility as a developer.

Drew: It’s almost just like another browser combination, isn’t it? To be aware of the configurations that the audience your site or your product might have and then testing with those configurations to find any problems.

Laura: Yeah. And also developing more robust ways of writing your code, so that your code can work without certain scripts and things like that. So not everything is hinging off one particular script unless it is absolutely necessary. Things completely fall apart when people are using third party CDNs, for example. I think that’s a really interesting thing that so many people decided to use a third party CDN, but you have very little control over it’s uptime and stuff like that. And if you block the third party CDN, what happens? Suddenly you have no images, no content, no videos, or do you have no functionality because all of your functional JavaScript is coming from a third party CND?

Drew: As a web developer or designer, if I’d not really thought about privacy concerns about the sites I’m producing up until this point, if I wanted to make a start, what should be the first thing that I do to look at the potential things I’m exposing my customers to?

Laura: I’d review one of your existing pages or one of your existing sites. And you can take it on a component by component basis even. I think any small step is better than no step. And it’s the same way you’d approach learning anything new. It’s the same way I think about accessibility as well. Is you start by, okay, what is one thing I can take away? What is one thing I can change that will make a difference? And then you start building up that way of thinking, that way of looking at how you’re doing your work. And eventually that will build up into being much more well informed about things.

Drew: So I’ve been learning a lot about online privacy. What have you been learning about lately?

Laura: One of the things I’ve been learning about is Hugo, which is a static site generator that is written using Go. And I use it for my personal site already, but right now for Site.js, I’ve been writing a starter blog theme so that people could just set up a site really easily and don’t necessarily have to know a lot about Hugo. Because Hugo is interesting, it’s very fast, but the templating is quite tricky and the documentation is not the most accessible. And so I’m trying to work my way through that to understand it better, which I think I finally got over the initial hurdle. Where I understand what I’m doing now and I can make it better. But it’s hard learning these stuff, isn’t it?

Drew: It really is.

Laura: It reminds you how inadequate you are sometimes.

Drew: If you, dear listener, would like to hear more from Laura, you can find her on the web at laurakalbag.com and Small Technology Foundation at small-tech.org. Thanks for joining us today, Laura. Do you any parting words?

Laura: I’d say, I think we should always just be examining what we’re doing and our responsibility in the work that we do. And what can we do that can make things better for people? And what we can do to make things slightly less bad for people as well.

Smashing Editorial (il)
Catégories: Programmation

Create Your Free Developer Blog Using Hugo And Firebase

lun, 04/06/2020 - 13:30
Create Your Free Developer Blog Using Hugo And Firebase Create Your Free Developer Blog Using Hugo And Firebase Zara Cooper 2020-04-06T11:30:00+00:00 2020-04-06T12:35:23+00:00

In this tutorial, I’ll demonstrate how to create your own blog using Hugo and deploy it on Firebase for free. Hugo is an open-source static site generator and Firebase is a Google platform that offers resources and services used to augment web and mobile development. If you’re a developer who does not have a blog yet but is interested in hosting one, this article will help you create one. To follow these steps, you need to know how to use Git and your terminal.

Having your own technical blog can have tons of benefits to your career as a developer. For one, blogging about technical topics makes you learn things you might not have otherwise picked up at your primary developer job. As you research your pieces or try new things, you end up learning a whole host of things like how to work with new technologies and solve edge case problems. In addition to that, you get to practice soft skills like communication and dealing with criticism and feedback when you engage with your reader’s comments.

Additionally, you become more self-assured in your software development skills because you get to write so much code when building sample projects for your blog to illustrate concepts. A technical blog augments your brand as a developer since it gives you a platform to showcase your skills and expertise. This opens you up to all kinds of opportunities like jobs, speaking and conference engagements, book deals, side businesses, relationships with other developers, and so on.

Recommended Reading on SmashingMag:

Chris Sevilleja, for example, started writing tutorials in 2014 on his blog scotch.io that turned into a business that later joined Digital Ocean. Another significant benefit of having a technical blog is that it makes you a better writer which can be an asset in your job when writing software design and technical spec documents. Moreover, it makes you an exceptional teacher and mentor. For example, I often read research.swtch.com, a blog by Russ Cox who blogs about the Go language and also works on the Google Go team that builds it. From it, I’ve learned a ton about how the language works that I might not have picked up from my main job.

Another great blog I also enjoy reading and learning a lot from is welearncode.com by Ali Spittel who once wrote that a really great part of blogging is:

“Helping other people learn how to code and making it easier for the people coming after me.”

A fairly easy and painless way to get your blog up and running is to use a third-party platform like Medium where you only have to create an account to get a blog. Although these platforms may suit most blogging needs at the start, they do have some drawbacks in the long run.

Some platforms offer bad user experiences like constantly sending distracting notifications for trivial things, asking for app installs, and so on. If your reader has a bad experience on a platform where your blog is hosted they are less likely to engage with your content. Besides that, tools you may need to enhance your reader’s interaction with and time on your blog may not be supported. Things like RSS feeds, syntax highlighting for code snippets among other things may not be supported on the platform. In a worst-case scenario, the platform where your blog is hosted may close and you may lose all the work you’ve done.

Hosting your own blog and redirecting your users to it increases the chances that they will be more engaged with the posts you put out. You won’t have to compete for your reader’s attention with other writers on a platform since you’ll be the only one on it. Readers are likely to read more of your posts or sign up for your newsletter since they’re more focused on what you’re communicating. Another plus that comes with hosting your own blog is the ability to customize it in a myriad of ways to your own tastes, which is usually not possible with third-party platforms.

Setting Up Hugo

If you’re working on macOS or Linux, the easiest way to install Hugo is to use Homebrew. All you’ll need to run on your terminal is:

brew install hugo

If you’re running on windows, Hugo can be installed using either the scoop installer or the chocolatey package manager. For scoop:

scoop install hugo

For chocolatey:

choco install hugo -confirm

If none of these options apply to you, check out these options for installation.

Setting Up Firebase Tools

To install firebase tools, you need to have Node.js installed to get access to npm. To install Firebase tools, run:

npm install -g firebase-tools

Create a Firebase account for free at this link. You’ll need a Google account for this. Next, login using the Firebase tools. You’ll be redirected to a browser tab where you can log in using your Google account.

firebase login Create Your Blog

Pick a directory where you’d like your blog’s source code to reside. Change location to that directory on your terminal. Pick a name for your blog. For the purposes of this tutorial, let’s name the blog sm-blog.

hugo new site sm-blog

It’s advisable to back up your site’s source code in case anything goes wrong. I’m going to use Github for this but you could use any version control service — if you choose to do the same. I’ll initialize a repository.

cd sm-blog git init

Before we can run the site locally and actually view it on the browser, we need to add a theme otherwise all you’ll see is a blank page.

Picking And Installing A Theme For Your Blog

One thing I love about Hugo is the community behind it and all the developers who submit themes for the community to use. There is a vast array of themes to choose from, everything from small business websites, portfolios to blogs. To pick a blog theme, head on over to the blog section of themes.gohugo.io. I picked a theme called Cactus Plus because of its simplicity and minimalism. To install this theme, I’ll need to add it as a submodule of my repository. Many themes instruct its users to use submodules for installs but if this is not the case, just follow the instructions given by the theme maker provided in the description. I’ll add the theme to the /themes folder.

git submodule -b master add https://github.com/nodejh/hugo-theme-cactus-plus.git theme/hugo-theme-cactus-plus

At the root of the blog folder, there exists a generated file, config.toml. This is where you specify settings for your site. We’ll need to change the theme there. The theme name corresponds to the chosen theme’s folder name in the /themes folder. These are the contents of the config.toml file now. You could also change the title of the blog.

baseURL = "http://example.org/" languageCode = "en-us" title = "SM Blog" theme="hugo-theme-cactus-plus"

Now we can run the blog. It will look exactly like the theme with the exception of the name change. Once you run the server, head on over to http://localhost:1313 on your browser.

hugo server -D Personalizing Your Blog

One benefit of deploying your own blog is getting to personalize it to your liking in all kinds of ways. The primary way to do this with Hugo is to change the theme you selected. Many themes provide customization options through the config.toml. The theme creator usually provides a list of options and what they all mean in the description on the theme page. If they don’t, check out the /exampleSite folder of the theme and copy the contents of config.toml within that folder to your config.toml file. For example:

cp themes/hugo-theme-cactus-plus/exampleSite/config.toml .

Since all themes are different, changes I make here may not apply to your theme but hopefully, you may be able to get an idea of what to do with your blog.

  1. I’ll change the avatar image and the favicon of the blog. All static files including images should be added to the /static folder. I created an /images folder within static and added the images there.
  2. I’ll add Google Analytics so I can track the traffic to my blog.
  3. I’ll enable Disqus so my readers can leave comments on my posts.
  4. I’ll enable RSS.
  5. I’ll put in my social links to Twitter and Github.
  6. I’ll enable the Twitter card.
  7. I’ll enable summaries under the post titles on the home page.

So my config.toml will look this:

### Site settings baseurl = "your_firebase_address" languageCode = "en" title = "SM Blog" theme = "hugo-theme-cactus-plus" googleAnalytics = "your_google_analytics_id" [params] # My information author = "Cat Lense" description = "blog about cats" bio = "cat photographer" twitter = "cats" copyright = "Cat Photographer" # Tools enableRSS = true enableDisqus = true disqusShortname = "your_disqus_short_name" enableSummary = true enableGoogleAnalytics = true enableTwitterCard = true [social] twitter = "https://twitter.com/cats" github = "https://github.com/cats" Creating Your First Post

Hugo posts are written in markdown. So you’ll need to be familiar with it. When creating a post, you’re actually creating a markdown file that Hugo will then render into HTML. Take the title of your post, make it lower case, substitute the spaces with hyphens. That will be the name of your post. Hugo takes the file name, replaces the hyphens with spaces, transforms it to start case, then sets it as the title. I’ll name my file my-first-post.md. To create your first post, run:

hugo new posts/my-first-post.md

The post is created in the /content folder. These are the contents of the file.

--- title: "My First Post" date: 2020-03-18T15:59:53+03:00 draft: true ---

A post contains front matter which is the metadata that describes your post. If you’d like to keep your posts as drafts while you write them, leave draft: true. Once you’re done writing, change draft: false so that the posts can be displayed on the home page. I’ll add a summary line to the front matter to summarize the post on the home page.

Adding Resources To Your Post

To add resources to your posts like images, videos, audio files, etc. create a folder within the /content/posts folder with the same name as your post excluding the extension.

For example, I’d create this folder:

mkdir content/posts/my-first-post

Then I’d add all my post resources to that folder and link to the resources just by file name without having to specify a long URL. For example, I’d add an image like this:

![A cute cat](cute-cat.png) Hosting Your Blog’s Source Code

Once you’re done writing your first post, it’s important to back it up before you deploy it. Before that, make sure you have a .gitignore file and add the /public folder to it. The public folder should be ignored because it can be generated again.

Create a repository on Github to host your blog’s source code. Then set the remote repository locally.

git remote add origin [remote repository URL]

Finally, stage and commit all your changes then push them to the remote repository.

git add * git commit -m "Add my first post" git push origin master Deploying Your Blog To Firebase

Before you can deploy your blog to Firebase, you’ll need to create a project on Firebase. Head on over to the Firebase Console. Click on Add Project.

Firebase Console home page where the “Create a Project” button resides. (Large preview)

Input the name of your project.

First page of “Create a project” flow on Firebase Console. (Large preview)

Enable Google Analytics if you want to use it in your blog.

Second page of “Create a project” flow on Firebase Console. (Large preview) Third page of “Create a project” flow on Firebase Console. (Large preview)

Once you’re done creating the project, go back to your blog’s root and initialize a Firebase project in the blog.

firebase init

You’ll be prompted to enter some information when this command runs.

Prompts Answer Which Firebase CLI features do you want to set up for this folder? Hosting: Configure and deploy Firebase Hosting sites Project Setup Options Use an existing project What do you want to use as your public directory? public Configure as a single-page app (rewrite all urls to /index.html)? N First prompt of the firebase init command requesting a feature selection. (Large preview) Second prompt of the firebase init command requesting a project selection. (Large preview) Third and fourth prompts of the firebase init command requesting a deployment folder and inquiring whether to configure the project as a single-page app. (Large preview)

Next, we’ll build the blog. A /public folder will be created and it will contain your generated blog.

hugo

After this, all we have to do is deploy the blog.

firebase deploy

Now the blog is deployed. Check it out at the hosting URL provided in the output.

Output from running the firebase deploy command. (Large preview) Next Steps

The only drawback of hosting on Firebase is the URL it uses for your hosted project. It can be unsightly and difficult to remember. So I’d advise that you buy a domain and set it up for your blog.

Third-party platforms are not all bad. They have tons of readers who may be interested in your writing but haven’t come across your blog yet. You could cross-post to those sites to put your work in front of a large audience but don’t forget to link back to your own blog. Add the link to your article on your blog to whichever platform you are posting to as a canonical URL so that it is not viewed as duplicate content by a search engine and hurts the SEO of your site. Sites like Medium, dev.to, and Hashnode support canonical URLs.

Conclusion

Writing on your own technical blog can have immense benefits to your career as a software developer and help you cultivate your skills and expertise. It’s my hope that this tutorial has started you on that journey or at least encouraged you to make your own blog.

Smashing Editorial (ra, il)
Catégories: Programmation

Releasing The Ethical Design Handbook When We Needed It Most

ven, 04/03/2020 - 12:00
Releasing The Ethical Design Handbook When We Needed It Most Releasing The Ethical Design Handbook When We Needed It Most Ari Stiles 2020-04-03T10:00:00+00:00 2020-04-03T12:35:00+00:00

Ethics is a timely subject for all of us who work on digital products, so it was no surprise The Ethical Design Handbook was well received. There is a real need for practical solutions beyond just complying with the law. The book offers ways to evaluate current practices, create opportunities for change when needed, and embed ethical design into your workflow.

Something Good In The Mail

As printed copies started to make their way around the world, we got to see some happy responses and thoughtful reviews:

Just got my new @smashingmag book in the mail today: The Ethical Design Handbook.

Super excited to dig in a little bit at a time. 📚 pic.twitter.com/XbDZwuwmN3

— Mayene 🏝️🍑 #ACNH Creator ID: MA-7125-3087-2361 (@mayenedesign) March 27, 2020 “After reading this book it is suddenly very clear how saturated the digital realm is with manipulative design. And that it is staged with intent. “The Ethical Design Handbook” teaches both the persuader and the persuaded what design for the most vulnerable looks like and how to avoid surveillance capitalism – the root cause of unethical design.”

— Mie Oehlenschlager, Now It’s Time To Act

The printed version of The Ethical Design Handbook arrived! Juhu and looking forward reading it and learning new things! @smashingmag @trinefalbe ✌️ pic.twitter.com/PbCFDmb8Ed

— Joshua Schaer (@JoshuaSchaer) March 10, 2020 “To assist in this decision-making the book also provides some really good practical tools and templates provided for assessing ethical considerations. I hope these will be put to good use by many readers. Throughout, there is an especially strong emphasis on the risks of collecting and managing personal data, and the importance of actually accumulating as little of it as possible. The walkthrough of different types of website cookies is also a great example of a useful artefact to enable relevant team discussions.”

— Per Axbom, Managing Consequences of Design

This isn’t the first book for Trine Falbe, Martin Michael Frederiksen and Kim Andersen—they are also the authors of White Hat UX—but The Ethical Design Handbook brought its own unique challenges from the start. The authors had difficulty finding examples of good ethics. DuckDuckGo, Goodwings, and LINGScars are just a few of the ethical sites and services eventually showcased in the Handbook.

Another challenge came just a few days after the release of the book, as quarantine and lockdown orders spread around the world. The spread of COVID-19 dominated the news, and as events were either canceled, rescheduled, or moved online, we had to rethink traditional book release plans.

“We felt it made most sense to stop actively marketing the book at that point. It just didn’t feel right to celebrate and to ask people to support us, when they clearly had so much to worry about.”

— Trine Falbe Spreading The Word In Ethical Ways

The book launch party planned for UX Copenhagen had to be scrapped when the event went online. Falbe still presented “Ethical Design Beyond the ‘Feel Good’” at the conference, raffled off a couple of books, and took questions from the audience.

Trine Falbe presenting at UX Copenhagen—showing how online ticketing services use urgency, scarcity, and loss aversion to pressure shoppers into buying event tickets. (Large preview)

The Ethical Design Handbook made a few guest appearances at the conference, too:

@snetramelleh just read my question.
Part of the answer was "buy @trinefalbe
Book.
First book buy of the conference! (Via kindle)#uxconfcph pic.twitter.com/RCDjIdAo4p

— (((lucaswxyz))) (@lucaswxyz) March 30, 2020

I was lucky enough to read an early copy of @trinefalbe's book 'The Ethical Design Handbook' - Although I wish we didn't have to make a business case for being kind, we do, and Trine lays this out in a really clear way. #uxcopenhagen

— Bex Rae-Evans (@RebeccaWho) March 30, 2020

Most people in the world are in an estate of crisis and emergency. We will remember the ones that show compassion. Behind every decision, are people. It starts and ends with us! @trinefalbe
Powerful Trine - thank you...#EthicalDesign #UXCPHConf #UXCopenhagen pic.twitter.com/FDw5HjHJc3

— Jose Coronado (@jcoronado1) March 30, 2020 Looking Forward

The use of online services, delivery apps, and teleconferencing is surging right now as we all find new ways to keep working, take care of each other, and stay connected. If the core mission of design is problem-solving, maybe we DO need designers now more than ever.

Other disciplines focus on problem-solving too—engineers, doctors, teachers—and the best of them all have a code of ethics that informs professional behavior and decisions. Most of the time, these codes are more stringent than the law.

There are ethical codes for business, too. But dark patterns, poor privacy protections, and a lack of transparency are proof that many of our digital services are not built on ethical foundations. Companies that do build with ethics in mind don’t have to make big changes when new legislation like GDPR and CCPA becomes law.

Should designers insist on ethical projects and workflow? Can they? The Ethical Design Handbook gives us a place to start: a business case for doing the right thing.

The news around tech companies during the pandemic has made choices even more difficult for users. Tech companies with deep pockets and convenient services have pounced on opportunities to improve their image, but it’s not all good news. Zoom, for example, is one of the more accessible platforms for online meetings, and they’ve made their platform free for schools. Zoom is also making headlines for sending user data to Facebook and plenty of other ethical shortcomings. Many companies will grow during the pandemic, but the ones who stick to ethical practices might be able to keep those new customers.

“If I was running a company that actually protects people’s privacy (like join.me for online meetings) I would make sure to surface that in my communication. Another important element is transparency. People are in a state of crisis, and the last thing we need is to feel tricked. If we find a product or service that treats us well, doesn’t hide costs, doesn’t violate our privacy, and does their best to be honest about it, we will stick with them.

After all of this is over, we'll remember the companies and people that did good.”

— Trine Falbe Tell Us Something Good

It’s a safe guess that Smashing readers are giving tech advice to a lot of family and friends right now. What are your favorite ethically-made digital products? What services and apps are you recommending to others? Let us know in the comments!

Other Resources Smashing Editorial (ra, il)
Catégories: Programmation

Django Highlights: Templating Saves Lines (Part 2)

jeu, 04/02/2020 - 14:00
Django Highlights: Templating Saves Lines (Part 2) Django Highlights: Templating Saves Lines (Part 2) Philip Kiely 2020-04-02T12:00:00+00:00 2020-04-02T12:35:28+00:00

Some no-frills approaches to building websites require a developer to write every line of HTML by hand. On the other extreme, commercial no-code site builders create all of the HTML for the user automatically, often at the expense of readability in the resultant code. Templating is around the middle of that spectrum, but closer to hand-written HTML than, say, generating page structure in a single-page application using React or a similar library. This sweet spot on the continuum provides many of the benefits of from-scratch manual HTML (semantic/readable code, full control over page structure, fast page loads) and adds separation of concerns and concision, all at the expense of spending some time writing modified HTML by hand. This article demonstrates using Django templating to write complex pages.

HTML Spectrum. (Large preview)

Today’s topic applies beyond the Django framework. Flask (another web framework) and Pelican (a static site generator) are just two of many other Python projects that use the same approach to templating. Jinja2 is the templating engine that all three frameworks use, although you can use a different one by altering the project settings (strictly speaking, Jinja2 is a superset of Django templating). It is a freestanding library that you can incorporate into your own projects even without a framework, so the techniques from this article are broadly useful.

Server-Side Rendering

A template is just an HTML file where the HTML has been extended with additional symbols. Remember what HTML stands for: HyperText Markup Language. Jinja2, our templating language, simply adds to the language with additional meaningful markup symbols. These additional structures are interpreted when the server renders the template to serve a plain HTML page to the user (that is to say, the additional symbols from the templating language don’t make it into the final output).

Server-side rendering is the process of constructing a webpage in response to a request. Django uses server-side rendering to serve HTML pages to the client. At the end of its execution, a view function combines the HTTP request, one or more templates, and optionally data accessed during the function’s execution to construct a single HTML page that it sends as a response to the client. Data goes from the database, through the view, and into the template to make its way to the user. Don’t worry if this abstract explanation doesn’t fully make sense, we’ll turn to a concrete example for the rest of this article.

Setting Up

For our example, we’ll take a fairly complex webpage, Start Bootstrap’s admin template, and rewrite the HTML as a Jinja2 template. Note that the MIT-licensed library uses a different templating system (based on JavaScript and Pug) to generate the page you see, but their approach differs substantially from Jinja2-style templating, so this example is more of a reverse-engineering than a translation of their excellent open-source project. To see the webpage we’ll be constructing, you can take a look at Start Bootstrap’s live preview.

I have prepared a sample application for this article. To get the Django project running on your own computer, start your Python 3 virtual environment and then run the following commands:

pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver

Then, open your web browser and navigate to http://127.0.0.1:8000. You should see the same page as the preview, matching the image below.

Dashboard Main Page. (Large preview)

Because this tutorial is focused on frontend, the underlying Django app is very simple. This may seem like a lot of configuration for presenting a single webpage, and to be fair it is. However, this much set-up could also support a much more robust application.

Now, we’re ready to walk through the process of turning this 668 line HTML file into a properly architected Django site.

Templating And Inheritance

The first step in refactoring hundreds of lines of HTML into clean code is splitting out elements into their own templates, which Django will compose into a single webpage during the render step.

Take a look in pages/templates. You should see five files:

  • base.html, the base template that every webpage will extend. It contains the <head> with the title, CSS imports, etc.
  • navbar.html, the HTML for the top navigation bar, a component to be included where necessary.
  • footer.html, the code for the page footer, another component to be included where needed.
  • sidebar.html, the HTMl for the sidebar, a third component to be included when required.
  • index.html, the code unique to the main page. This template extends the base template and includes the three components.

Django assembles these five files like Voltron to render the index page. The keywords that allow this are {% block %}, {% include %}, and {% extend %}. In base.html:

{% block content %} {% endblock %}

These two lines leave space for other templates that extend base.html to insert their own HTML. Note that content is a variable name, you can have multiple blocks with different names in a template, giving flexibility to child templates. We see how to extend this in index.html:

{% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}

Using the extends keyword with the base template name gives the index page its structure, saving us from copying in the heading (note that the file name is a relative path in double-quoted string form). The index page includes all three components that are common to most pages on the site. We bring in those components with include tags as below:

{% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}

Overall, this structure provides three key benefits over writing pages individually:

  • DRY (Don’t Repeat Yourself) Code
    By factoring out common code into specific files, we can change the code in only one place and reflect those changes across all pages.
  • Increased Readability
    Rather than scrolling through one giant file, you can isolate the specific component you’re interested in.
  • Separation of Concerns
    The code for, say, the sidebar now has to be in one place, there can’t be any rogue script tags floating at the bottom of the code or other intermingling between what should be separate components. Factoring out individual pieces forces this good coding practice.

While we could save even more lines of code by putting the specific components in the base.html template, keeping them separate provides two advantages. The first is that we are able to embed them exactly where they belong in a single block (this is relevant only to the footer.html which goes inside the main div of the content block). The other advantage is that if we were to create a page, say a 404 error page, and we did not want the sidebar or footer, we could leave those out.

These capabilities are par for the course for templating. Now, we turn to powerful tags that we can use in our index.html to provide dynamic features and save hundreds of lines of code.

Two Fundamental Tags

This is very far from an exhaustive list of available tags. The Django documentation on templating provides such an enumeration. For now, we’re focusing on the use cases for two of the most common elements of the templating language. In my own work, I basically only use the for and if tag on a regular basis, although the dozen or more other tags provided to have their own use cases, which I encourage you to review in the template reference.

Before we get to the tags, I want to make a note on syntax. The tag {% foo %} means that “foo” is a function or other capability of the templating system itself, while the tag {{ bar }} means that “bar” is a variable passed into the specific template.

For Loops

In the remaining index.html, the largest section of code by several hundred lines is the table. Instead of this hardcoded table, we can generate the table dynamically from the database. Recall python manage.py loaddata employee_fixture.json from the setup step. That command used a JSON file, called a Django Fixture, to load all 57 employee records into the application’s database. We use the view in views.py to pass this data to the template:

from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})

The third positional argument to render is a dictionary of data that is made available to the template. We use this data and the for tag to construct the table. Even in the original template that I adapted this webpage from, the table of employees was hard-coded. Our new approach cuts hundreds of lines of repetitive hard-coded table rows. index.html now contains:

{% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}

The bigger advantage is that this greatly simplifies the process of updating the table. Rather than having a developer manually edit the HTML to reflect a salary increase or new hire, then push that change into production, any administrator can use the admin panel to make real-time updates (http://127.0.0.1/admin, use the credentials you created with python manage.py createsuperuser to access). This is a benefit of using Django with this rendering engine instead of using it on its own in a static site generator or other templating approach.

If Else

The if tag is an incredibly powerful tag that allows you to evaluate expressions within the template and adjust the HTML accordingly. Lines like {% if 1 == 2 %} are perfectly valid, if a little useless, as they evaluate to the same result every time. Where the if tag shines is when interacting with data passed into the template by the view. Consider the following example from sidebar.html:

<div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>

Note that the entire user object is passed into the template by default, without us specifying anything in the view to make that happen. This allows us to access the user’s authentication status (or lack thereof), username, and other features, including following foreign key relationships to access data stored in a user profile or other connected model, all from the HTML file.

You might be concerned that this level of access could pose security risks. However, remember that these templates are for a server-side rendering framework. After constructing the page, the tags have consumed themselves and are replaced with pure HTML. Thus, if an if statement introduces data to a page under some conditions, but the data is not used in a given instance, then that data will not be sent to the client at all, as the if statement is evaluated server-side. This means that a properly constructed template is a very secure method of adding sensitive data to pages without that data leaving the server unless necessary. That said, the use of Django templating does not remove the need to communicate sensitive information in a secure, encrypted manner, it simply means that security checks like user.is_authenticated can safely happen in the HTML as it is processed server-side.

This feature has a number of other use cases. For example, in a general product homepage, you might want to hide the “sign up” and “sign in” buttons and replace them with a “sign out” button for logged-in users. Another common use is to show and hide success or error messages for operations like form submission. Note that generally you would not hide the entire page if the user is not logged in. A better way to change the entire webpage based on the user’s authentication status is to handle it in the appropriate function in views.py.

Filtering

Part of the view’s job is to format data appropriately for the page. To accomplish this, we have a powerful extension to tags: filters. There are many filters available in Django to perform actions like justifying text, formatting dates, and adding numbers. Basically, you can think of a filter as a function that is applied to the variable in a tag. For example, we want our salary numbers to read “$1,200,000” instead of “1200000.” We’ll use a filter to get the job done in index.html:

<td>${{ employee.salary|intcomma }}</td>

The pipe character | is the filter that applies the intcomma command to the employee.salary variable. The “$” character does not come from the template, for an element like that which appears every time, it’s easier to just stick it outside the tag.

Note that intcomma requires us to include {% load humanize %} at the top of our index.html and 'django.contrib.humanize', in our INSTALLED_APPS in settings.py. This is done for you in the provided sample application.

Conclusion

Server-side rendering with the Jinja2 engine provides key tools for creating clean, adaptable, responsive front-end code. Separating pages into files allows for DRY components with flexible composition. Tags provide fundamental capabilities for displaying data passed from the database by view functions. Done right, this approach can increase the speed, SEO capabilities, security, and usability of the site, and is a core aspect of programming in Django and similar frameworks.

If you haven’t done so already, check out the sample application and try adding your own tags and filters using the complete list.

Django Highlights is a series introducing important concepts of web development in Django. Each article is written as a stand-alone guide to a facet of Django development intended to help front-end developers and designers reach a deeper understanding of “the other half” of the code base. These articles are mostly constructed to help you gain an understanding of theory and convention, but contain some code samples, which are written in Django 3.0.

Smashing Editorial (dm, yk, il)
Catégories: Programmation

Building A Web App With Headless CMS And React

mer, 04/01/2020 - 13:30
Building A Web App With Headless CMS And React Building A Web App With Headless CMS And React Blessing Krofegha 2020-04-01T11:30:00+00:00 2020-04-01T12:36:30+00:00

In this tutorial, you’ll learn what Headless CMS is, and the pros and cons of Headless CMS. In the end, youll have built a shopping cart using GraphCMS (a (backend-only content management system). After that, you can go ahead and build any web app of your choice using a headless CMS and React.

To follow along, you need to have Node and npm/yarn installed on your machine. If you do not have that done already, follow these quick guides to install yarn or npm on your machine. You also need to have a basic understanding of React, Node.js and GraphQL queries. (You can always brush up on React and GraphQL skills, of course!)

As digital products continue to evolve, so does the content we consume. A scalable, cross-platform content management system is crucial to ensuring a product’s growth velocity. Traditional CMS gives the comfort of having the content, the editing interface, templates and custom codes, in a single environment. But with the changes in this mobile era, that’s no longer enough. We need a new breed of CMS — one that can make content available through any channel at which point a Headless CMS is required. A headless CMS gives you the benefits of managing the content and delivering it to any channel. The API makes contents available through any channel and on any device using most favorite tools and programming languages plus it also provides a higher level of security and much better scalability.

What Does This Look Like In Practice?

What happens when you take away the frontend of a CMS? The biggest distinction is that a website can’t be built with a headless CMS on its own. With a traditional CMS, everything happens in the same place.

A headless CMS doesn’t have the features that let you build your site — it doesn’t have site themes or templates. To use a headless CMS, you have to build a site or app, or other experience first, then use the CMS’s API to plug your content into it.

Why Should You Care About Headless?

A headless CMS comes with an API friendly approach, which makes it possible to publish content through an API (either RESTful or GraphQL). It allows you to use the same API to deliver content across various channels such as Android or IOS apps, smartwatches, AR/VR, etc. A headless CMS gives developers the ability to harness creativity quickly. With a traditional CMS, changes can be time-consuming, for example, to tweak a part of your site, you need to re-implement the entire CMS. With a headless CMS, you can make changes to your frontend without having any impact on the back-end infrastructure, hence saving yourself time and resources, which makes it much better.

Traditional vs Headless CMS: The Pros And Cons

It can be complicated to choose between a headless and a traditional CMS. The fact is, they both have potential advantages and drawbacks.

Traditional CMS Pros
  • It allows for easy customization. A lot of them have drag and drop, this makes it easy for a person without programming experience to work seamlessly with them.
  • It’s easier to set up your content on a traditional CMS as everything you need (content management, design, etc) are already available.
Traditional CMS Cons
  • The coupled front-end and back-end results in more time and money for maintenance and customization.
  • Traditional CMS e.g Wordpress relies heavily on plugins and themes which may contain malicious codes or bugs and slow the speed of the website or blog. Here’s a list of 18,305 vulnerable WordPress plugins, themes. Here are security measures for Drupal developers. Check here for more facts.
Headless CMS Pros
  • Since the frontend and backend are separated from each other, it makes it possible for you to pick which front-end technology suits your needs. This also gives the developer flexibility during the development stage.
  • Platforms (blogs, websites, etc) built with headless CMS can be deployed to work on various displays such as web, mobile, AR/VR, and so on.
Headless CMS Cons
  • They give you the hassle of managing back-end infrastructures, setting up the presentation component of your site, app.
  • They can be more costly to implement — the cost involved in building a user-friendly platform with analytics is high when compared to using traditional CMS.
Best Use Cases For Headless CMS

Headless CMS can have the following use cases:

  • Static Site Generators (e.g. Gridsome, Gatsby)

Many Jamstack sites created with static site generators like Gridsome, Hugo or Gatsby make use of the headless CMS to manage content, they cannot access a database, Hence content can be stored in a headless CMS and fetched through an API during build time and deployed as static files.

  • Mobile Apps (iOS, Android)

The advantage of a headless CMS for mobile engineers is that the API enables them to deliver content to an IOS/Android app from the same backend that manages content for their web site, which keeps things in sync.

  • Web Applications

This approach involves serving content through an API which is then consumed by a web application but offers a centralized place for managing content. An example is an e-commerce application built using HTML, CSS, and JavaScript with content and product data that are maintained in the CMS and served via an external API.

Types Of Headless CMS

There is a list of headless CMSs you might what to check out.

Please note that this article is not written to promote any services or products.

  • Contentful
    An API-driven headless CMS designed to create, manage and distribute content to any platform. Unlike a traditional CMS, they offer the ability to create your content model so that you can decide what type of content you want to manage.
  • GraphCMS
    A headless CMS for users who want to build a GraphQL content infrastructure for their digital products. This CMS is fully built as API focused from the ground up, allowing creators to define the structures, permissions, and relations for the API parameters. In this article, we’d be using GraphCMS because of its GraphQL API approach.
  • ButterCMS
    A CMS that gives complete freedom to build a website or a branded blog with full SEO and supports any tech stack. This tool saves you money and the time for site development time. Butter CMS is a maintenance-free headless CMS tool and can integrate with any language or framework. The powerful interface helps you define and customize every element of your website without any hassle.
  • Directus
    An open-source tool that wraps custom SQL databases with a dynamic API and provides an intuitive admin app for managing its content. Self-host for free, or use the on-demand Cloud service to manage all your omnichannel digital experiences.
  • Sanity
    Another API driven platform for managing structured content. With Sanity, you can manage your text, images, and other media with APIs. You can also use the open-source single page application Sanity Studio to quickly set up an editing environment that you can customize.
  • Agility
    A JAMStack focused Headless CMS with Page Management built-in. Faster to build, manage, and deploy. Agility CMS is a Content-First Headless CMS, allowing you to choose any programming language while also getting the flexibility, speed, and power that comes from lightweight APIs. From there, add features like Page Management, Ecommerce, Online Ticketing, and Search. Agility CMS becomes a complete Digital Experience Platform–saving time, removing limitations and allowing for seamless experiences across all digital channels.
  • Netlify CMS
    A free and open-source, git-based CMS created by Netlify. It allows you to define your content model, integrates third-party authentication and extends the capabilities of its backend (a single-page app built on React).

Note: All of the examples mentioned above have free and paid versions, except Directus and Netlify CMS which are free. For a list of more headless CMS, check here.

In this article, we’re using GraphCMS — a GraphqQL API-oriented headless content management system that takes care of our back-end architecture.

Using GraphCMS

Content is both dynamic and multi-channeled, however current content management systems (CMS) lack the flexibility to meet the demands of modern-day digital content distribution. GraphCMS is the first HeadlessCMS built around GraphQL and offers a solution to this problem with its mission to facilitate painless content flow between content creators, developers, and consumers.

GraphCMS accept almost any kind of data you can imagine ranging from images, maps, etc. It even makes roles and permissions easy. While other headless CMS solutions exist, GraphCMS aims to provide a hassle-free experience for developers; through leveraging an API specification called GraphQL. It eliminates the need for multiple SDKs to interact with content delivery and provides simple multi-channel content accessibility. It makes creating rich content apps very easy.

GraphCMS And GraphQL

GraphCMS sorely relies on GraphQL, its backbone API specification. GraphQL is API query language and runtime. It was developed by Facebook in 2012 and released open-sourced in 2015. Since then, the likes of Pinterest, Github, Twitter, Intuit, Coursera have all adopted GraphQL to power their mobile apps, websites, and APIs. GraphQL is similar to REST in its core purpose of providing a specification for building and utilizing APIs. However, unofficially dubbed “REST 2.0”, GraphQL has optimized different key functionality offered by REST.

The main uniqueness of GraphQL includes protocol-agnostic usage, controlled data fetching, editable fields, and types and in-depth error handling. The results include removal of code redundancy, prevention of over and under fetching data, and significant reduction of network requests.

As a concrete example, let’s take the relationship of a query to a newsfeed. A newsfeed post has an author, a title and comments. If we use a REST-based CMS, we would have to make 3 different server requests for these 3 different endpoints, whereas, in a GraphQL based CMS, we would only have to make 1 request for all 3. Consequently, the results offer relatively quicker queries and less network flooding — in a practical use case, it would not just be one entity making multiple requests, but thousands and millions.

GraphQL reduces the complexity of building APIs by abstracting all requests to a single endpoint. Unlike traditional REST APIs, it is declarative; whatever is requested is returned.

GraphCMS has a generous free tier of 1 million API operations requests per month and 500 GB assets traffic. Also, GraphCMS provides a Graphiql admin interface that provides you full access to your data and you could just download it all and then execute a create many mutations against your new backend to migrate everything over.

In this article, we’ll be using the free tier of 1 million API operations per month and 500 GB asset traffic. You can make use of the same tier for testing, for projects that need more than this, do well to check out their pricing page.

Building Our Project

To see the power of Headless CMS using GraphCMS we would be building a simple shopping cart.

Getting Started

To get started with GraphCMS follow the steps.

  • Create an account on GraphCMS. You can use the free tier.
(Large preview)
  • At successful signup, you’ll be taken to your dashboard. Click on create a new project.
Click on Create new project. (Large preview)
  • Ensure you click on create a project from scratch.
Select From Scratch. (Large preview)
  • Set project details for the project fill in what is in the image below and click create.
Set Project Details. (Large preview)
  • In our dashboard, we would create our models and content.
Create model. (Large preview)
  • Select the schema in the sidebar of the dashboard to create a schema.

GraphCMS has an awesome drag and drop UI, that make it easy to seamlessly create schema in minutes.

Drag and Drop fields. (Large preview)
  • Let’s go ahead and create our system fields in our schema.

    • name: “”
      • type: The field type is a String, Single line Text.
      • Is required
      • description: It’s the name of the product.
    • price: “”
      • type: The field type is int.
      • Is required
      • description: It will contain the price of our product.
    • description: “”
      • type: The field type is a String, Multi-line Text.
      • Is required
      • description: This field will contain the description of our product.
    • image: “”
      • type: The field type is the file, which is an Asset Picker.
      • Is required
      • description: This image field will contain the image of our product.
Creating our name field. (Large preview)

Note: Click on the ‘Advance’ tab to select the required option in our fields.

  • If all went well, you should have our schema looking the image below:
Final Schema fields. (Large preview)
  • Currently, we have no content. Click on ‘Content’ in the sidebar that should take you the Content section, and click on ‘Create New’.
At this point our we have no content/post. (Large preview)
  • Let’s add a few contents so we can display them later in our app using React.
Here’s how to add content. (Large preview)
  • Add a few more content if you desire. Here’s our result.
Our final content. (Large preview)
  • Next, copy the API endpoint URL (Click on the Dashboard) — this is the single endpoint for communication between our React front end and GraphCMS back end.
(Large preview)

Next, let’s make our API endpoint accessible.

  • Navigate to Settings Under Public API Permission and click on the drop-down and select OPEN and click the update button.
(Large preview) Setting Up React

The easiest way to set up React is to use Create-React-App. (This is an officially supported way to create single-page React applications, and offers a modern build setup with no configuration.) We’ll make use of it to bootstrap the application we’ll be building.

From your terminal, run the command below:

npx create-react-app smashing-stores && cd smashing-stores

Once the installation is successful, start the React server by running npm start.

React Starter Page. (Large preview) Creating Our Layout

In creating the layout for our project, we will have five different components.

Navbar To hold our navigation and cart icon Allproducts To display a list of all products Product The markup for a single product Footer The footer of our app Cart To hold the items in our cart

For a quick setup, we will be using Bootstrap to create our components. To include Bootstrap, we would use bootstrap CDN, open up your index.html in the public folder, add the link to the head section:

https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css

Now we can make use of bootstrap classes in our application.

Next, create a /components folder and create the following files inside it:

  • Navbar.js
  • Allproducts.js
  • Product.js
  • Footer.js
  • Cart.js
Creating Our Navbar

Open up the Navbar.js and add the following code:

import React from 'react'; const Navbar = () => { return ( <nav className="navbar navbar-light bg-light"> <a href="/" className="navbar-brand">Smashing Stores</a> <button className="btn btn-outline-success my-2 my-sm-0" type="submit">Cart</button> </nav> ); }; export default Navbar;

We declared a functional component Navbar, we return our nav tag with a bootstrap class of navbar navbar-light bg-light. What these classes do is to apply a Navbar with a light background. Inside our nav element, we included an anchor tag with a link to just forward-slash(Homepage) and a class of navbar-brand.

The styled button in the Navbar component has a class named navbar navbar-light bg-light. What this class does it to ensure that our button has a light blue background color and a shadow when hovered.

Creating Our Footer.js

Next, let’s create our Footer. Open up the Footer.js file and add the following code to it:

import React from 'react'; import '../App.css'; const Footer = () => { return ( <footer className="page-footer font-small bg-blue pt-4"> <div className="container text-center text-md-left"> <div className="row"> <div className="col-md-6 mt-md-0 mt-3"> <h5 className="text-uppercase font-weight-bold">Contact Us</h5> <p>You can contact us on hi@smashingstores.com</p> </div> <div className="col-md-6 mb-md-0 mb-3"> <h5 className="text-uppercase font-weight-bold">Smashing Stores</h5> <p>Built with 💕 by <a href="https://twitter.com/beveloper">beveloper</a></p> </div> </div> </div> <div className="footer-copyright text-center py-3">© 2020 Copyright <span> Smashing Stores</span> </div> </footer> ); }; export default Footer;

We added contact-us email using h5 and paragraph element. Lastly, on this footer section, we added copyright with the name “Smashing Stores”.

Our footer needs some styling so we’d add the following styles to the App.css file:

footer { position: absolute; bottom: -55px; width: 100%; background-color: #333; color:#fff; }

Before we create our product component, we need to query GraphCMS to send us our product details to display. Let’s do that now.

Connecting To The GraphCMS Backend With GraphQL

To connect our application to the backend, we need to install a couple of GraphQL packages. One of the libraries we can use is apollo-boost which gives a client the avenue for connecting to the GraphQL backend using a URI (Uniform Resource Identifier).

The URI is the endpoint provided by GraphCMS and is available on the endpoint section of the dashboard.

Run the following command in your terminal to install the necessary packages:

npm install apollo-boost graphql graphql-tag react-apollo

Once you’re done with the installation update the index.js file in the /src directory to the following code:

import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import { ApolloProvider } from "react-apollo"; import ApolloClient from "apollo-boost"; import * as serviceWorker from './serviceWorker'; const client = new ApolloClient({ uri: "<YOUR_GRAPHCMS_ENDPOINT>" }); ReactDOM.render( <ApolloProvider client={client}> <App /> </ApolloProvider>, document.getElementById('root') ); serviceWorker.unregister();

Here, we wrapped our entire application with the ApolloProvider which takes a single prop: the client. The ApolloProvider loads the Graph CMS schema and gives us access to all properties of the data model inside our application which is possible because our App component is a child of the ApolloProvider component.

Displaying Our Products

If you got this far, pat yourself on the back. 👍 We’ve been able to load our schema from GraphCMS into our application.

The next step is to fetch and display our products. Create an /all-product folder under the /component folder and then create an index.js file and add the following to it:

import gql from "graphql-tag"; const PRODUCTS_QUERY = gql` query { productses { id name price description createdAt image { id url } } } `; export default PRODUCTS_QUERY;

What are “productses”? Our model name is products, but GraphQL pluralizes models, hence the name.

Next, we created a variable called PRODUCTS_QUERY that stores the query from our GraphQl back end. The gql function is used to parse (analyze an object, as it were in our schema) the plain string that contains the GraphQL code (if you’re unfamiliar with the backtick-syntax, you can read up on JavaScript’s tagged template literals).

GraphCMS provides a handy GraphQL explorer named (graphiql) specifically for testing our query.

Testing our endpoint using Graphiql Explorer in our GraphCMS Dashboard. (Large preview)

Now that our query works as it should. Let’s go ahead and create our product’s components.

Creating The Allproducts Component

Open up the Allproducts.js file and add the following code to it:

import React, { Component } from 'react'; import { Query } from 'react-apollo'; import PRODUCTS_QUERY from './all-products/index'; import Product from './Product'; import Cart from './Cart'; import Navbar from './Navbar'; class Allproducts extends Component { constructor(props) { super(props); this.state = { cartitems: [] }; } addItem = (item) => { this.setState({ cartitems : this.state.cartitems.concat([item]) }); } render() { return ( <Query query={PRODUCTS_QUERY}> {({ loading, error, data }) => { if (loading) return <div>Fetching products.....</div> if (error) return <div>Error fetching products</div> const items = data.productses; return ( <div> <Navbar/> <div className="container mt-4"> <div className="row"> {items.map(item => <Product key={item.id} product={item} addItem={this.addItem} />)} </div> </div> </div> ) }} </Query> ); } }; export default AllProducts;

Here, we wrapped our products with the <Query/> component and passed the PRODUCTS_QUERY as props. Apollo injected several props into the component’s render prop function. These props themselves provide information about the state of the network request:

loading This occurs during ongoing requests. error This occurs when the requests fail. data This is data received from the server.

Finally, we loop through all the received items and pass them as a prop to our Product component. Before we see what it looks like, let’s create our Product component.

Creating Product Component

Open up Product.js and add the following code to it:

import React from 'react'; const Product = (props) => { return ( <div className="col-sm-4"> <div className="card" style={{width: "18rem"}}> <img src={props.product.image.url} className="card-img-top" alt="shirt"/> <div className="card-body"> <h5 className="card-title">{props.product.name}</h5> <p className="card-title">$ {props.product.price}</p> <p className="card-title">{props.product.description}</p> <button className="btn btn-primary" onClick={() => props.addItem(props.product)}>Buy now</button> </div> </div> </div> ); } export default Product;

Since our Product.js is a functional component that receives product details via props and displays them, we call the addItem function on the onClick event listener to add the current product to the cart when it clicked.

Importing Our Components Into App.js

With our components setup, it’s time we import our components into our App.js base component.

Open it up and add the following to it:

import React from 'react'; import './App.css'; import Footer from './components/Footer'; import Products from './components/Allproducts'; function App() { return ( <div className="App"> <Products /> <Footer/> </div> ); } export default App;
  • From lines 3-4, we imported both Footer and Products component in the App component.

Next, type npm start in your terminal then navigate to https://localhost:3000 in your browser, and you will see the following:

Final Outcome of our Web App. (Large preview)

We’re close to the end of our project, but our products need a feature that adds items to the cart.

Creating Our Cart Component

To include our cart functionality, we’d need to add some methods to our components.

Let’s update our Allproducts.js file to this:

import React, { Component } from 'react'; import { Query } from 'react-apollo'; import PRODUCTS_QUERY from './all-products/index'; import Product from './Product'; import Cart from './Cart'; import Navbar from './Navbar'; class Allproducts extends Component { constructor(props) { super(props); this.state = { cartitems: [], show: false }; } addItem = (item) => { this.setState({ cartitems : this.state.cartitems.concat([item]) }); } showModal = () => { this.setState({ show: true }); }; hideModal = () => { this.setState({ show: false }); }; render() { return ( <Query query={PRODUCTS_QUERY}> {({ loading, error, data }) => { if (loading) return <div>Fetching</div> if (error) return <div>Error</div> const items = data.productses const itemssent = this.state.cartitems; return ( <div> <Navbar cart={itemssent} show={this.showModal} /> <Cart show={this.state.show} items={itemssent} handleClose={this.hideModal}> </Cart> <div className="container mt-4"> <div className="row"> {items.map(item => <Product key={item.id} product={item} addItem={this.addItem} />)} </div> </div> </div> ) }} </Query> ) }; }; export default Allproducts;
  • showModal
    This method sets the show state to true so that the modal can be visible to the user.
  • hideModal
    This method sets the show state to false to hide the modal.
  • We created a variable named itemssent that holds the state of all cart items we get from the backend.
Navbar
  • cart
    It passes the items in the cart data to our Navbar.
  • show
    It triggers our modal method.
Cart
  • show
    It opens up the cart modal.
  • Items
    It receives and stores the data sent from the Navbar so it can be displayed when needed.
  • handleClose
    It closes the modal.
Updating Navbar

Let’s update our Navbar.js file with the following code:

import React from 'react'; const Navbar = (props) => { return ( <nav className="navbar navbar-light bg-light"> <h3>Smashing Stores</h3> <button className="btn btn-outline-success my-2 my-sm-0" onClick={() => props.show()}>Cart {(props.cart.length)}</button> </nav> ); }; export default Navbar;
  • We added an on click event that takes a function, which triggers that cart modal.
  • Lastly, we check for the number of items in our cart by using the .length JavaScript method.

Next, create a Cart.js file and add the following code to it:

import React from 'react'; const Cart = ({ handleClose, show, items }) => { return ( <div className={show ? "modal display-block" : "modal display-none"}> <section className="main-modal"> {items.map(item => <div className="card" style={{width: "18rem"}}> <img src={item.image.url} className="card-img-top" alt="shirt"/> <div className="card-body"> <h5 className="card-title">{item.name}</h5> <h6 className="card-title">$ {item.price}</h6> </div> </div> )} Total items: {items.length} <button className="btn btn-warning ml-2" onClick={handleClose}>close</button> </section> </div> ); }; export default Cart;

In our parent div, we used a ternary operator that toggles between visibility and hidden state. Next, in other for us to display the items in our cart modal we map through our items.

Lastly, in this section to check out for the total number of items in our cart we used the .length JavaScript method.

Open up your app.css and add the following code to it:

.modal { position: fixed; top: 0; left: 0; width:100%; height: 100%; background: rgba(0, 0, 0, 0.6); } .main-modal { position:fixed; background: white; width: 80%; height: auto; top:50%; left:50%; padding: 10px; transform: translate(-50%,-50%); } .display-block { display: block; } .display-none { display: none; }

Finally open the shopping cart, add items to it and view it via the ‘Cart’ button:

Conclusion

The concept learned in this article can help you create almost anytime of web apps without paying so much attention to your back-end infrastructure. You can take it further by creating a full-fledged e-commerce store and adding payment etc. I’ll love to see what you were able to make in the comments section.

The supporting repo for this article is available on Github.

References
  1. GraphCMS Documentation
  2. Event App with GraphCMS
Smashing Editorial (ks, yk, il)
Catégories: Programmation

What Should You Do When A Web Design Trend Becomes Too Popular?

mar, 03/31/2020 - 13:30
What Should You Do When A Web Design Trend Becomes Too Popular? What Should You Do When A Web Design Trend Becomes Too Popular? Suzanne Scacca 2020-03-31T11:30:00+00:00 2020-03-31T12:34:45+00:00

I read an interesting article on Forbes recently about language saturation. Here’s the problem:

Consumers don’t always understand the technicalities of what businesses do or the solutions they’ve created for them. So, copywriters use jargon that translates something like “Internet-connected devices with computing capabilities” into “smartphones”, “smart watches” and “smart speakers”.

Some of these buzzwords spread like wildfire and it soon becomes impossible to find a brand or website that doesn’t use them. When that happens, the words — and the associated product or service — become meaningless in the minds of consumers because everyone is saying the same thing.

The same thing happens when design trends become too popular. This is something Vitaly Friedman talked about last year with regards to cookie consent notices and banner blindness.

But what choice do you have? Are you supposed to hop on the design bandwagon anyway so your website doesn’t get left behind? Today, we’re going to look at what your options are.

What Should You Do with Too-Popular Design Trends?

To be clear, I’m not suggesting that you ignore any and all rising design trends.

There are certain trends that we absolutely need to adopt across the board. Like minimalism and mobile-first design. When there’s substantial, quantifiable proof that a design technique is needed, please don’t ignore it.

What I’m talking about are design trends that aren’t aimed at strengthening the web. Instead, they’re solely about driving up engagement on websites.

Brutalism. Facebook Messenger pop-ups. Home page hero sliders. The second that popular websites begin to adopt these trends and once writers and designers start including them in design trend roundups, it’s only a matter of months before consumers are inundated with them. And this is when banner blindness kicks in.

So, what are your options when you learn about a new design trend that promises big results?

Option 1: Ignore It and Stick with What Works

There are a few reasons you should consider going with this option:

You work on short-term website projects.

For those of you who build websites, hand them over to clients and then wish them luck as you move onto the next, it’s probably not a good idea to play around with fad-like design trends.

You know how quickly design trends change, so why put your client in a position where they have a website with an outdated design? One of three things is going to happen:

  1. They’ll leave the outdated feature as is and have no idea that it’s costing them conversions.
  2. They’ll ask you for help in removing the feature not too long after launch and won’t be happy about needing a rework so soon.
  3. They’ll ask another designer for help because they’re upset you put them in this less than ideal position.

Unless your client has a very good reason why they need to exploit a passing design trend, try to dissuade them from it. If they understand the fleeting nature of some of these trends, as well as how banner blindness develops from oversaturation, they should be onboard with you sticking to what works.

You’re designing (or redesigning) a site for a very well-established company.

When building a website for a company that has a long-standing reputation with its audience as well as a tried-and-true formula for success, adopting a passing trend could be risky.

Take Zillow, for example.

Zillow homepage on mobile The homepage for Zillow on mobile (Image source: Zillow) (Large preview)

This is the mobile homepage as it stands today. It’s simple, sleek and intuitive by nature.

Can you imagine what would happen if the designer decided to add a video background to the hero banner? Or to interrupt the property browsing experience with a pop-up advertising a free ebook download?

You have to really think about what disruptions to the expected design would do to the flow of things. So, when building something for a brand that’s known for its consistency and convenience, it’s best to ignore passing trends.

This doesn’t mean that a website like this shouldn’t be redesigned. Like I said before, lasting design “trends” can’t be ignored as they enable us to move websites in the right direction (like responsive design). For example, this was Zillow in 2017:

Zillow mobile homepage in 2017 The mobile homepage for the Zillow website in 2017 (Image source: Zillow) (Large preview)

See how far we’ve come in terms of making websites mobile responsive and mobile-first in just a few years? These are the kinds of popular changes that don’t require debating.

The company’s goal is to build relationships; not to increase sales.

I realize that every website needs conversions in order to survive. However, many business models can’t sustain with just one-off sales. It costs too much money to constantly market to new customers, which is why some businesses focus on building long-term relationships with their customer base.

And that’s why you need to steer clear of conversion-boosting design trends on these kinds of websites.

Take, for instance, Gary Vaynerchuk’s website:

Gary Vaynerchuk mobile site The mobile website for Gary Vaynerchuk is free of passing design trends and elements. (Source: Gary Vaynerchuk) (Large preview)

Remember when every website seemed to have a pop-up containing two buttons — one of which would be super-positive like “Yes, I want to change my life!” and the other which was meant to shame the visitor with something like “No, I like living in squalor.”

How do you think Vaynerchuk’s always-growing loyal following would feel if the site displayed one of those pop-ups? Not only would they be annoyed by the disruption keeping them from the content, but they’d probably be upset that he’d use such a shameless ploy to bully them into signing up.

If the brand you’re building a website for is on a similar mission — to build long-lasting and meaningful relationships — you don’t want to sully that with bad design decisions.

Option 2: Adopt the Trend But Keep an Eye on Market Saturation

Patrick Ward, the author of the Forbes article mentioned above, explained that many writers in the fintech space have had to pivot towards a simpler style of writing:

“At first, new startups used jargon and buzzwords to highlight their brand new tech and give themselves a competitive edge.”

I think this is a good lesson for designers as well. It’s not always a bad thing to hop on a design trend’s bandwagon — especially if it’s proven to work and it’s still in the very early stages of public awareness.

So, while there are clear cases where it makes sense to avoid design fads, I think there are times when it makes sense to take advantage of them. The only thing is, you can’t just implement the design and then leave it be.

For instance, this is the 15 Finches website on desktop:

15 Finches website animationA walk-through of the animation on the 15 Finches website on desktop. (Source: 15 Finches) (Large preview)

Now let’s compare this same animated experience to what users get on their mobile devices:

15 Finches mobile websiteA walk-through of the 15 Finches website on mobile with layering errors and no animation. (Source: 15 Finches)(Large preview)

There are a number of design choices made on this mobile site that should’ve been long phased out.

  1. The vertical typography in the background should go. It might add texture to the desktop site, but it’s just a confusing distraction on mobile.
  2. The animation on the desktop site doesn’t translate to mobile. To present visitors with a consistent experience, the designer should commit to mobile-first design.
  3. There are also layering errors all over the mobile site, with text often covering other bits of text as well as missing call-to-action buttons.

As I said, there are some sites where it’s okay to adopt short-term design trends. Just keep an eye on them.

For example, the Hubspot site design is always changing, but any design trends it adopts never seem to overstay their welcome. Hubspot tends to cut out just before they become too much. And that’s a key thing to remember.

Hubspot mobile site with chatbot widget Hubspot’s mobile site continues to use a chatbot widget to guide prospective customers in the right direction. (Image ource: Hubspot) (Large preview)

As you can see, the mobile site still uses a chatbot widget. For a business that sells sales and marketing software, it’s an important element to retain even if other sites have since ditched theirs.

That said, I’m positive that Hubspot keeps close tabs on its user data so it probably has confirmation that the element continues to work well. This is just one of the things you should be mindful of when monitoring a trend.

If you want to utilize popular design trends, you need to be in it for the long haul with your clients. That way, the second you start to notice:

  • Oversaturation in the market,
  • The trend has gone completely stale,
  • Or your users aren’t responding positively to it.

You can immediately move the website to safer ground.

Option 3: Go in a Similar But Different Direction

When a design technique or element immediately and universally becomes popular, there’s more value to it than just its ability to increase conversions or create a prettier design.

Take a look at why it’s caught on the way it has. If you understand what’s driving the popularity of the fad, you can leverage the strongest parts of it, make it your own and have something with real staying power.

Do you remember the New York Times’ Snow Fall article in 2012? This was shortly after parallax scrolling started to pick up speed in web design. And despite some websites utilizing the trend, it was the way the NYT creatively integrated it along with interactive and animated images that really blew people away — so much so that it won a number of journalism awards for it.

Notice that the NYT didn’t try to redesign its website with parallax scrolling or interactivity. It took the basic principles gaining in popularity and applied it to one groundbreaking story. By considering how the trend could be best used for maximum impact, the NYT turned a short-term fad into something that would make its story memorable.

If you understand what’s driving the popularity of the fad, you can leverage the strongest parts of it, make it your own and have something with real staying power.

Let’s take a look at a more recent example of a site using this approach.

You’re all familiar with the trend of split-screen design, right? It worked really well on desktop, both in its static form as well as when one half of the screen would remain put while the other moved. But on mobile? It wasn’t so great.

While we’ve seen a lot of split screen designs get phased out, EngineThemes has made the trend its own:

EngineThemes mobile site with split screen designEngineThemes has put a playful twist on the once-trendy split screen design. (Source: EngineThemes) (Large preview)

Upon entering the site, it’s a look we’re familiar with as consumers. But it doesn’t take long to realize that this is going to be a different experience.

For starters, the bobbing bird and red double-headed arrow are something you don’t see much of, if at all, on other sites. I can’t imagine many visitors scroll past this banner without engaging with it.

Secondly, there are no words in this banner on mobile. (There are on the desktop website.)

One of the reasons why this design trend doesn’t work anymore is because it can’t be used on mobile sites — there just isn’t enough space to split the screen and fit enough words in there. Or is there?

EngineThemes hidden message to mobile visitors EngineThemes has hidden a message in its animated, split screen graphic. (Image source: EngineThemes) (Large preview)

Eagle-eyed visitors will notice that there’s a message carefully hidden in the bird graphic when the arrow is moved to the right. Granted, the text should be bigger, but mobile visitors can zoom in if they’re struggling to read it.

It’s a string of code that reads:

"EngineThemes provides effective business solutions with simple and powerful WordPress app themes."

But do you see what I mean? When a design trend suddenly becomes popular — for a short or long while, too — it doesn’t necessarily mean you need to use the same exact version of it like everyone else. This is why oversaturation quickly turns once great-looking websites stale.

By taking what’s so innovative about a design trend and making it your own, though, you can give the trend real staying power while making your site a standout in the process.

Wrapping Up

When we overdo it by leveraging the same design trends as everyone else, we put our websites at risk of becoming redundant or, worse, invisible. So, how do we establish a cutting edge if we can’t make use of design “jargon”?

The truth is, there’s no one clear-cut answer. You need to be able to read the room, so to speak, and figure out which approach is best for you. You could leave the passing trend alone, you could adopt it temporarily or you could make it your own.

Further Reading on SmashingMag: Smashing Editorial (ra, il)
Catégories: Programmation

Stay Positive, Stay Creative (April 2020 Wallpapers Edition)

mar, 03/31/2020 - 11:30
Stay Positive, Stay Creative (April 2020 Wallpapers Edition) Stay Positive, Stay Creative (April 2020 Wallpapers Edition) Cosima Mielke 2020-03-31T09:30:00+00:00 2020-03-31T09:53:22+00:00

In times like these where our everyday life is pausing and we’re trying to find strategies to cope with this situation we all find ourselves in at the moment, little routines can help give us a sense of security and familiarity — no matter if it’s having a cup of coffee in the midday sun on your balcony, calling an old friend in the evenings, or trying out a new recipe every day.

One of our routines here at Smashing that has been going on for more than nine years already and that we’re continuing now, too, of course, is to provide you with new wallpapers every month. So if you need a little bit of colorful inspiration or something to cheer you up this April, we’ve got you covered.

Designed with love by artists and designers from across the globe, the wallpapers in this collection come in versions with and without a calendar for April 2020. As a little bonus goodie, we also compiled some wallpaper favorites from the past at the end of this post — after all, some things are just too good to be forgotten. A big thank you to everyone who shared their artworks with us this month! Enjoy and take care!

  • All images can be clicked on and lead to the preview of the wallpaper,
  • We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.
Submit your wallpaper

Did you know that you could get featured in one of our upcoming wallpapers posts, too? We are always looking for creative talent, so if you have an idea for a wallpaper design, please don’t hesitate to submit it. Join in! →

Spring Awakens

“Despite the threat that has befallen us all, we all look forward to the awakening of a life that spreads its wings after every dormant winter and opens its petals to greet us. Long live spring, long live life.” — Designed by LibraFire from Serbia.

Spring Awakens April Flowers

“While April showers usually bring May flowers, we thought we all deserved flowers a little early this year. During a stressful time in the world, spending time thinking about others is an antidote to some of the uncertainty. We thought this message, Lift Others Up, reflected the energy the world needs.” — Designed by Mad Fish Digital from Portland, Oregon.

April Flowers An Era Of Metals With Sense Of Touch

“In the future we can expect that machines will have emotions and they will start loving nature and flowers.” — Designed by Themesvillage from London.

An Era Of Metals With Sense Of Touch April Fox

Designed by MasterBundles from the United States.

April Fox Stay Home and Smash

“Inspired by the current situation of Corona virus affecting the world.” — Designed by WrapPixel from India.

Stay Home and Smash Celebrating the Genius

“‘Iron rusts from disuse; water loses its purity from stagnation… even so does inaction sap the vigor of the mind.’ These are the words of no other than the ‘Universal Genius’. Leonardo da Vinci’s unprecedented talents, exemplary imagination, and an unquenchable wonder shaped not solely the Renaissance era but the future of humankind. On April 15, we mark the birthday of one of the world’s greatest painters, most prolific inventors, and the father of paleontology and architecture.” — Designed by PopArt Studio from Serbia.

Celebrating the Genius You’re Smashing

Designed by Ricardo Gimenes from Sweden.

You’re Smashing National Submarine Day

Designed by Nicolas van der Straten Ponthoz from Belgium.

National Submarine Day Take Our Daughters And Sons To Work Day

“The day revolves around parents taking their children to work to expose them to future job possibilities and the value of education. It’s been an annual event since 1992 and helps expose children to the possibilities of careers at a young age.” — Designed by Ever Increasing Circles from the United Kingdom.

Take Our Daughters And Sons To Work Day Everything Will Be Alright

“This month we don’t need more words. Just these.” — Designed by Joana Vicente from Portugal.

Everything Will Be Alright Oldies But Goodies

A lot of wallpaper goodies have seen the light of day in the nine years that we’ve been running our monthly wallpapers challenge. Here’s a selection of favorites from past April editions. Maybe you’ll rediscover one of your almost-forgotten favorites, too? (Please note that these wallpapers don’t come with a calendar.)

A Time For Reflection

“‘We’re all equal before a wave.’ (Laird Hamilton)” — Designed by Shawna Armstrong from the United States.

A Time for Reflection

Dreaming

“The moment when you just walk and your imagination fills up your mind with thoughts.” — Designed by Gal Shir from Israel.

Dreaming

Inspiring Blossom

“‘Sweet spring is your time is my time is our time for springtime is lovetime and viva sweet love’, wrote E. E. Cummings. And we have a question for you. Is there anything more refreshing, reviving, and recharging than nature in blossom? Let it inspire us all to rise up, hold our heads high, and show the world what we are made of.” — Designed by PopArt Studio from Serbia.

Inspiring Blossom

Spring Fever

“I created that mouse character for a series of illustrations about a poem my mom often told me when I was a child. In that poem the mouse goes on an adventure. Here it is after the adventure, ready for new ones.” — Designed by Anja Sturm from Germany.

Spring Fever

Yellow Submarine

“The Beatles — ‘Yellow Submarine’: This song is fun and at the same time there is a lot of interesting text that changes your thinking. Like everything that makes The Beatles.” — Designed by WebToffee from India.

Yellow Submarine

Clover Field

Designed by Nathalie Ouederni from France.

Clover Field

Wonderful Life

“My favorite song is ‘Wonderful Life’ from Black from my childhood. This picture that was taken in a very beautiful dock in Belgrade evokes a calm feeling from that song, a peacefulness of soul and mind. Each of us has a gift, but what is truly wonderful is to embrace a flair toward life in small things because, no need to run and hide, it’s a wonderful, Wonderful Life. Cheers!” — Designed by Marija Zaric from Belgrade, Serbia.

Wonderful Life

Happy Easter

Designed by Tazi Design from Australia.

Happy Easter

Fairytale

“A tribute to Hans Christian Andersen. Happy Birthday!” — Designed by Roxi Nastase from Romania.

Fairytale

Be Happy Bee

Designed by Kiraly Tamas from Romania.

Be Happy Bee

Spring Infographics

“Spring comes for everyone, for big and for small. How spring is arranged? I suggest us to understand this question.” — Designed by Ilya Denisenko from Russia.

Spring Infographics

Without The Rain There Would Be No Rainbows

“I love April showers and the spring blooms they bring!” — Designed by Denise Johnson from Chicago.

Without The Rain There Would Be No Rainbows.

Sakura

“Spring is finally here with its sweet Sakura’s flowers, which remind me of my trip to Japan.” Designed by Laurence Vagner from France.

Smashing Wallpaper - April 2011

Good Day

“Some pretty flowers and spring time always make for a good day.” — Designed by Amalia Van Bloom from the United States.

good day

April Cosmos

“I was inspired by a non-fiction book The Living Cosmos written by University of Arizona professor of astronomy Chris Impey. It’s a research of scientists trying to address the questions we ask about nature. Is there life in the universe beyond the Earth?” — Designed by Paul Ranosa from the Philippines.

April Cosmos

Spring

“I love spring and handmade typography.” — Designed by Raluca Dragos from Romania.

Spring

Vector Saraswathi

“Saraswathi, Goddess of Creativity (Indian mythology).” Designed by Atma Creative Team from India.

Smashing Wallpaper - April 2011

Egg Hunt In Wonderland

“April is Easter time and I wanted to remind us that there’s a child inside all of us. My illustration is based on the story that fills our imagination since childhood, Alice in Wonderland, and joined to one of the most traditional customs in America at this time of year, the egg hunt. That’s how we get an ‘egg hunt in wonderland’.” — Designed by Patrícia Garcia from Portugal.

Egg Hunt In Wonderland

Skateboarding Bunny

Designed by Lew Su-ann from Brunei Darussalam.

Skateboarding Bunny

Join In Next Month!

Please note that we respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience throughout their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.

Thank you to all designers for their participation. Join in next month!

A postcat. Sign up for our Smashing Newsletter. Smashing Newsletter

Upgrade your inbox and get our editors’ picks 2× a month — delivered right into your inbox. Earlier issues.

Your (smashing) email Subscribe → Useful tips for web designers. Sent 2× a month.
You can unsubscribe any time — obviously.
Catégories: Programmation

Visual Design Language: The Building Blocks Of Design

lun, 03/30/2020 - 15:00
Visual Design Language: The Building Blocks Of Design Visual Design Language: The Building Blocks Of Design Gleb Kuznetsov 2020-03-30T13:00:00+00:00 2020-03-30T13:36:45+00:00 “Design is not just what it looks like and feels like. Design is how it works.”

— Steve Jobs

Like written words are to language, fonts, colors, shapes and icons are to visual design. An effective visual design language not only acts as a communication framework for all stakeholders on a product development team, but unites a brand and its customers to ensure that a company’s brand identity matches a customer’s brand perception.

We use language as a tool for communication with other people. Writers use words to communicate with their readers, while designers use visual language to communicate with their users. Fonts, colors, shapes, visual elements such as icons — those are elements of design language. Effective design language streamlines communication.

While working at Fantasy in 2016, my team was tasked with designing the interface for Huawei’s mobile OS (EMUI 5 interface). I personally was responsible for the visual design language for this OS. Surprisingly, the company didn’t have its own language at initiation; instead, they relied on a customized version of Android that was plagued by inconsistency and lacked a coherent vision. This was largely due to the existence of multiple teams and multiple functional roles with different skillsets and perspectives all grasping at straws to invent a way to communicate. UX designers, interaction designers, visual designers and graphic designers had all worked on the OS in the past, all using their own best efforts to communicate.

Without a uniform system of communication, not only was the user experience jumbled and confusing, it was extremely difficult to integrate changes into a final design. It was a true Tower of Babel.

Writers use words to communicate with their readers, while designers use visual language to communicate with their users.

“ What Does Design Language Provide?

By unifying the project teams under one shared language, a project can move forward with clarity, cohesion and speed.

Consistency

Digital design has few physical constraints compared to industrial disciplines. This gives designers a lot of power to experiment and propose a variety of solutions to any given challenge. However, this can easily lead to disjointed user experiences.

To achieve consistency in design, it’s vital to define reusable and cross-platform components and styling options. Consistent design makes it much easier to ship products on a multitude of platforms and devices, which is especially crucial for companies like Huawei.

Brand Recall

When they interact with a product that has a strong visual language, users tend to remember it better. Unfortunately, a majority of products available on the market have generic designs. It is too easy to confuse one product with another when they share the same visual styles.

Creating a strong visual identity is a goal that design teams should state when working on visual design. This is the personality of a digital product! The colors, typefaces, photos, illustrations, animations are all part of a brand, and they should be designed in a way that helps people remember the product. When an authentic design language is followed consistently, it creates recognizability for the brand.

Clarity

We put a strong focus on clarity — we wanted to make our GUI clean, not cluttered. By following a minimalist approach, we minimized the number of elements that users have on every screen and created a highly-focused experience.

Design concept of EMUI 5 interface Minimalist design helps to focus user attention on important elements of your design. EMUI 5.0 Concept by Fantasy (Design concept of EMUI 5 interface) (Large preview) A Way To Innovate

With so much competition in the phone market, companies invest significant resources to make people try their products. Companies invest in innovation and try to break new ground to attract users and peak their interest. Visual design is often the fastest and cheapest way for a product to innovate.

How Do We Create A Design Language?

For me and my teams, the process of creating a design language, we follow the same rubric we would create any complete consumer product: research-ideate-design-validate- implement. This is how we ensure that the language will work for our target audience.

Research

Often, the VDL is the most important, cornerstone product we create. And like every product you design, research should always be the first. When we started this Huawei project, it was important to understand the opportunities for our design. Jeshua Nanthakumar, a lead UX designer on this project, and his UX research team analyzed all mobile OS available on the market and identified the full range of challenges typically faced by users.

The UI Audit

As I’ve mentioned above, achieving consistency was one of the goals of creating a shared design language. It’s essential to standardize the visual design. That’s why even before starting work on a visual language, we decided to conduct a UI audit. Our goal was to understand the anatomy of the Android OS.

We broke down the whole mobile OS into atomic elements—colors, shapes, shadows, lines, transitions. By decomposing the design, our team was able to see how individual pieces work together and form a greater whole. At the end of UI audit, we had all the elements that make up the digital product (buttons, navigation bars, icons, etc.) grouped into distinct categories.

Understand How Users Perceive The Brand

When working on visual language, it’s essential to have a clear understanding of who you’re designing for and how they perceive your brand. Ideally, brand identity (the way the brand wants to be perceived by users) should match with the brand image (the way users actually perceive the brand). Designers have a direct impact on brand identity. Aesthetic styles, language & tone, iconography, and illustrations — all these are elements of brand identity.

Our goal was to create an innovative design language that feels customized for its audience. To understand how your users perceive the Huawei brand, our team invested in user research. We knew that design language should successfully meet the needs of both Eastern and Western design sensibilities, so we categorized large groups of users and created summaries based on the available information about our target groups. Every summary about our audience had the following information blocks — demographics, what they care about, and their expectations. Here is an example of the summary of the group of North American customers:

  • Huawei’s core audience lives both Urban and Suburban environments;
  • They are driven by business, social status, and personal organization;
  • Age range 30-64;
  • Average income: USD $75.000 per annum
  • They care about:
    • Being organized and ordered
    • Efficiency and productivity to enable them to enjoy their own time
  • Their expectations
    • Contributing to something bigger than themselves
    • Maximizing life and living for happiness

With the idea that design should match the audience’s lifestyle and be extremely refined, we evaluated every design decision in accordance with the needs of our target segments. This understanding will give you a reason for your visual direction.

Analyze Major Competitors

To identify strategic design opportunities, our team conducted the competitors’ analysis. We’ve identified four major competitors who had strong design languages and focussed on identifying their strengths and weaknesses. For example, when we evaluated Apple iOS, we’ve mentioned the following strengths of the language — scalable across devices, great focus on standardization, unique identity — and the following weakness — inconsistency with iconography, overuse of blur effects.

Icons of the four major Huawei competitors. Four major competitors of Huawei at the time of our analysis. Every brand represented a large part of the market and had its own robust visual language. (Large preview)

This analysis helped us to identify four major directions that brands followed when they create products:

  1. Empathetic to me (design tailored for the needs of the target audience; design that demonstrates real empathy with the human and truly reflects the audience)
  2. Novel design (design that uses innovative visual styles and interaction patterns)
  3. Commonplace design (design that utilizes conservative style elements)
  4. Standardized for all (heavy standardized design)

We put every brand on the plot with those four directions.

Quadrant diagram of Huawei visual language Identifying opportunities for Huawei visual language (Large preview)

This process helped us to identify the opportunities for Huawei language:

  • Scalable Design Language
    The language should scale across devices and across third-party developer apps as well.
  • Unique Design DNA
    The language should be unique and distinct from the major competitors.
  • Be Bold Yet Timeless
    The language should be long-lasting.
Define Requirements For Visual Hierarchy

When UX researchers analyzed typical user complaints, they found that the location of key interactive elements was one of the most common problems that many mobile users mentioned. In 2016 mobile screens become larger and larger, but the location of key functional elements in Android remained the same — the top area of the screen. As a result, users had to stretch their fingers or change their grip in order to interact with the elements.

Diagram of reachable zones on mobile devices Thumb Zone: how easy it is for our thumbs to tap areas on a phone’s screen. (Image credit: Luke W) (Large preview)

Today a bottom-area navigation is an industry-standard, but back in 2016, the situation was a bit different. We’ve reached the Huawei engineering team with this insight and asked about the technical feasibility of moving controls to the bottom area of the screen — this area is more comfortable for user interaction. The engineering team confirmed that it was possible to move the elements, and we helped define the new default location for functional elements.

Design concept of EMUI 5 interface Functional controls are located at the bottom of the screen — in the easy-to-reach area. (Design concept of EMUI 5 interface by Fantasy) (Large preview) Ideation: Defining A Design Vision Creating A Philosophy Of Design

Imagine that you need to design a language that will be integrated into products that will be used by people all over the world. The natural language we use in interpersonal communications cannot be separated from a culture because it has a close relation to the attitude or behavior of speakers of the languages. The digital language is absolutely the same — it should look natural for customers in the Americas, Europe, Asia, Africa, and Oceania.

The success of any visual design highly relates to how people perceive it. Many factors are influencing human perception, and the significant part goes to psychology. To create a sophisticated design, you need to consider the meaning of shapes and the impact which they have on users’ minds.

Creating a philosophy of design is extremely challenging, and you cannot do it alone. That’s why I worked with Abigail Brody, a former Apple creative director who joined Huawei in September 2015 as Chief UX design and VP of Huawei Devices. At Apple, Abigail was responsible for iOS design. She was the one who described the methodology of visual language to me.

Together we spend a lot of time trying to find the direction for visual design, and we’ve decided to use the philosophy of organic design as a foundation for our design language. Organic design is centered around using nature as the biggest inspiration.

Frank Lloyd Wright chair Organic Design was pioneered by Frank Lloyd Wright who believed in creating harmony between people and nature. (Image credit: museiitaliani) (Large preview)

According to this philosophy, design should help to achieve harmony between people and nature. When we worked on our visual language, we focused on incorporating natural forms (smooth curves and organic forms) in our visual design. As a result, all visual elements, such as buttons, icons, and shapes, had an organic design aesthetic.

Design concept of EMUI 5 interface Round shapes are one of the things that make organic objects different from non-organic. (Large preview) Using Motion Design To Create A Distinct Visual Identity

There is no doubt about the importance of the role that motion plays in mobile design. For many product motion serves a purely-functional role—it provides feedback for user action and connects different states of the mobile app together. The well-crafted motion also makes things more attractive, and as we know, attractive things work better (the aesthetic-usability effect says that people are more tolerant of minor usability issues when they find an interface visually appealing).

Our team put high stakes on the motion. Our ultimate goal was to use motion to breathe life into our products — make the interface feel alive and dynamic. We wrote a motion design manifesto with solid design principles. Every animated effect and transition that we wanted to introduce in our design was measured in accordance with the functional and emotional benefits it delivers to end-users.

We know that early impressions of a product design are especially important. And for that very reason our key focus was on creating magical moments — surprise and delight users while they interact with the OS.

This video demonstrates the visual effects we used in EMUI. Design And Testing: Build, Test, Iterate Baking Meaning Into Every Design Element/Design Decision

Just like we have rules for using words in sentences in a natural language, we should have rules for using visual elements in visual language. Strong semantics is what makes visual communication efficient.

When a team works on a visual language, it should take two rules into account:

  • There are no random visual elements in a visual language. Every element serves a purpose.
  • There should be no isolated units in visual language. Every unit in a visual language should be a part of a greater whole.
Design concept of EMUI 5 interface The animated effect behind the user avatar is used to convey a sense of active call. The animation is both meaningful and pleasurable. (Design concept of EMUI 5 interface) (Large preview) Experimentation And Design Review

It’s impossible to create a great design from the first attempt. Design is an iterative process, and whenever our team created a new visual solution, they evaluated it by comparing it with previous solutions. The comparison was visual—the screens were laid side by side on a board, so everyone could see the parts that require additional polishing. Team members gather together on informal design reviews where they discuss the pros and cons of individual solutions.

Team reviewing designs on computer screen Design review in progress at Fantasy Interactive (Large preview) Pattern Libraries, Style Guides And Design Principles

Pattern libraries (reusable building blocks such as UI bars), style guides, and design principles (principles that allow developers to propagate design language in their own apps) are essential elements of design language. They are the foundation of the design system — a shared resource that teams use when they create interfaces. The fact that we’ve conducted a UI audit during the research phase helped us to categorize the visual design elements. We’ve established a toolbox for everyone who worked on the project. So, when a new member joins a team, all they need is the toolbox, and they are set to maintain consistency.

There are no random visual elements in a visual language. Every element serves a purpose.

“ Test Early, Test Often

The Huawei EMUI project was an extremely important project for the Huawei Corporation. It was essential to ensure that the language we’ve defined work for the users. And the only way to get this understanding is to test our design as soon as possible.

We’ve followed a simple but effective technique — build, measure, learn. By following this approach, the design team didn’t postpone the testing design until the release. We’ve incorporated visual language into functional prototypes and tested them both inside our group (dogfooding) and outside (with real users). The feedback collected during the testing allowed us to understand what worked/doesn’t work for users.

Product team meeting at Fantasy Interactive Sharing the results of testing with product teams at Fantasy Interactive (Large preview) Implementation

If you have had a chance to use the Huawei EMUI 5 interface, you are probably thinking to yourself, “Um, that doesn’t look exactly like Gleb said!” And that’s true.

Huawei OS screenshot Production version of the Huawei EMUI 5 interface. (Image credit: androidauthority) (Large preview)

It is a sad reality that almost no design team is responsible for the implementation of this solution. Unfortunately, a lot of solutions we proposed to the engineering team weren’t implemented properly, or at all. As a result, the design language we’ve created and the design language the end-user saw in Huawei products end up as two different animals. But this is purely my opinion. In 2018, Huawei surpassed Apple in smartphone sales. The UI was a critical element to user confidence.

Based on my experience, the challenge of implementation is common for large-scale corporations. When designers who created the language aren’t invited into the process of implementing this language into the product, the final results will always be compromised. What usually happens is the engineering team follows a path of least resistance — they adjust the design solutions to the technical constraints they face when they start.

Every company needs a top-manager who cares about design and is ready to fight for it. It’s a well-known fact that when the original minimize animation in macOS that was proposed by the Apple motion design team, the engineering team said that it was impossible to implement that. At that time, Steve Jobs insisted that this animation is a must-have for MacOS. As a result, this animation became not only the most memorable transition for first-time users but also one of the things that contribute to good UX in MacOS.

A screenshot of Mac OS The instantly memorable window animation of the Mac OS (Large preview) A Robust Visual Design Language Is The Heart Of Good UX

Visual language can have a dramatic impact on user experience. It’s able not only to reduce friction by making UI more predictable but also to create delight. By pairing great form with excellent function, we will have an excellent user experience.

Visual language is a by-product of product design, and it requires a similar design process. It’s iterative and requires validation at every step along the way. When you build a visual language, you establish a new ecosystem for designers, and this ecosystem creates harmony between different teams involved in product development.

Smashing Editorial (cc, ra, il)
Catégories: Programmation

Visual Design Language: The Building Blocks Of Design

lun, 03/30/2020 - 15:00
Visual Design Language: The Building Blocks Of Design Visual Design Language: The Building Blocks Of Design Gleb Kuznetsov 2020-03-30T13:00:00+00:00 2020-03-30T13:36:45+00:00 “Design is not just what it looks like and feels like. Design is how it works.”

— Steve Jobs

Like written words are to language, fonts, colors, shapes and icons are to visual design. An effective visual design language not only acts as a communication framework for all stakeholders on a product development team, but unites a brand and its customers to ensure that a company’s brand identity matches a customer’s brand perception.

We use language as a tool for communication with other people. Writers use words to communicate with their readers, while designers use visual language to communicate with their users. Fonts, colors, shapes, visual elements such as icons — those are elements of design language. Effective design language streamlines communication.

While working at Fantasy in 2016, my team was tasked with designing the interface for Huawei’s mobile OS (EMUI 5 interface). I personally was responsible for the visual design language for this OS. Surprisingly, the company didn’t have its own language at initiation; instead, they relied on a customized version of Android that was plagued by inconsistency and lacked a coherent vision. This was largely due to the existence of multiple teams and multiple functional roles with different skillsets and perspectives all grasping at straws to invent a way to communicate. UX designers, interaction designers, visual designers and graphic designers had all worked on the OS in the past, all using their own best efforts to communicate.

Without a uniform system of communication, not only was the user experience jumbled and confusing, it was extremely difficult to integrate changes into a final design. It was a true Tower of Babel.

Writers use words to communicate with their readers, while designers use visual language to communicate with their users.

“ What Does Design Language Provide?

By unifying the project teams under one shared language, a project can move forward with clarity, cohesion and speed.

Consistency

Digital design has few physical constraints compared to industrial disciplines. This gives designers a lot of power to experiment and propose a variety of solutions to any given challenge. However, this can easily lead to disjointed user experiences.

To achieve consistency in design, it’s vital to define reusable and cross-platform components and styling options. Consistent design makes it much easier to ship products on a multitude of platforms and devices, which is especially crucial for companies like Huawei.

Brand Recall

When they interact with a product that has a strong visual language, users tend to remember it better. Unfortunately, a majority of products available on the market have generic designs. It is too easy to confuse one product with another when they share the same visual styles.

Creating a strong visual identity is a goal that design teams should state when working on visual design. This is the personality of a digital product! The colors, typefaces, photos, illustrations, animations are all part of a brand, and they should be designed in a way that helps people remember the product. When an authentic design language is followed consistently, it creates recognizability for the brand.

Clarity

We put a strong focus on clarity — we wanted to make our GUI clean, not cluttered. By following a minimalist approach, we minimized the number of elements that users have on every screen and created a highly-focused experience.

Design concept of EMUI 5 interface Minimalist design helps to focus user attention on important elements of your design. EMUI 5.0 Concept by Fantasy (Design concept of EMUI 5 interface) (Large preview) A Way To Innovate

With so much competition in the phone market, companies invest significant resources to make people try their products. Companies invest in innovation and try to break new ground to attract users and peak their interest. Visual design is often the fastest and cheapest way for a product to innovate.

How Do We Create A Design Language?

For me and my teams, the process of creating a design language, we follow the same rubric we would create any complete consumer product: research-ideate-design-validate- implement. This is how we ensure that the language will work for our target audience.

Research

Often, the VDL is the most important, cornerstone product we create. And like every product you design, research should always be the first. When we started this Huawei project, it was important to understand the opportunities for our design. Jeshua Nanthakumar, a lead UX designer on this project, and his UX research team analyzed all mobile OS available on the market and identified the full range of challenges typically faced by users.

The UI Audit

As I’ve mentioned above, achieving consistency was one of the goals of creating a shared design language. It’s essential to standardize the visual design. That’s why even before starting work on a visual language, we decided to conduct a UI audit. Our goal was to understand the anatomy of the Android OS.

We broke down the whole mobile OS into atomic elements—colors, shapes, shadows, lines, transitions. By decomposing the design, our team was able to see how individual pieces work together and form a greater whole. At the end of UI audit, we had all the elements that make up the digital product (buttons, navigation bars, icons, etc.) grouped into distinct categories.

Understand How Users Perceive The Brand

When working on visual language, it’s essential to have a clear understanding of who you’re designing for and how they perceive your brand. Ideally, brand identity (the way the brand wants to be perceived by users) should match with the brand image (the way users actually perceive the brand). Designers have a direct impact on brand identity. Aesthetic styles, language & tone, iconography, and illustrations — all these are elements of brand identity.

Our goal was to create an innovative design language that feels customized for its audience. To understand how your users perceive the Huawei brand, our team invested in user research. We knew that design language should successfully meet the needs of both Eastern and Western design sensibilities, so we categorized large groups of users and created summaries based on the available information about our target groups. Every summary about our audience had the following information blocks — demographics, what they care about, and their expectations. Here is an example of the summary of the group of North American customers:

  • Huawei’s core audience lives both Urban and Suburban environments;
  • They are driven by business, social status, and personal organization;
  • Age range 30-64;
  • Average income: USD $75.000 per annum
  • They care about:
    • Being organized and ordered
    • Efficiency and productivity to enable them to enjoy their own time
  • Their expectations
    • Contributing to something bigger than themselves
    • Maximizing life and living for happiness

With the idea that design should match the audience’s lifestyle and be extremely refined, we evaluated every design decision in accordance with the needs of our target segments. This understanding will give you a reason for your visual direction.

Analyze Major Competitors

To identify strategic design opportunities, our team conducted the competitors’ analysis. We’ve identified four major competitors who had strong design languages and focussed on identifying their strengths and weaknesses. For example, when we evaluated Apple iOS, we’ve mentioned the following strengths of the language — scalable across devices, great focus on standardization, unique identity — and the following weakness — inconsistency with iconography, overuse of blur effects.

Icons of the four major Huawei competitors. Four major competitors of Huawei at the time of our analysis. Every brand represented a large part of the market and had its own robust visual language. (Large preview)

This analysis helped us to identify four major directions that brands followed when they create products:

  1. Empathetic to me (design tailored for the needs of the target audience; design that demonstrates real empathy with the human and truly reflects the audience)
  2. Novel design (design that uses innovative visual styles and interaction patterns)
  3. Commonplace design (design that utilizes conservative style elements)
  4. Standardized for all (heavy standardized design)

We put every brand on the plot with those four directions.

Quadrant diagram of Huawei visual language Identifying opportunities for Huawei visual language (Large preview)

This process helped us to identify the opportunities for Huawei language:

  • Scalable Design Language
    The language should scale across devices and across third-party developer apps as well.
  • Unique Design DNA
    The language should be unique and distinct from the major competitors.
  • Be Bold Yet Timeless
    The language should be long-lasting.
Define Requirements For Visual Hierarchy

When UX researchers analyzed typical user complaints, they found that the location of key interactive elements was one of the most common problems that many mobile users mentioned. In 2016 mobile screens become larger and larger, but the location of key functional elements in Android remained the same — the top area of the screen. As a result, users had to stretch their fingers or change their grip in order to interact with the elements.

Diagram of reachable zones on mobile devices Thumb Zone: how easy it is for our thumbs to tap areas on a phone’s screen. (Image credit: Luke W) (Large preview)

Today a bottom-area navigation is an industry-standard, but back in 2016, the situation was a bit different. We’ve reached the Huawei engineering team with this insight and asked about the technical feasibility of moving controls to the bottom area of the screen — this area is more comfortable for user interaction. The engineering team confirmed that it was possible to move the elements, and we helped define the new default location for functional elements.

Design concept of EMUI 5 interface Functional controls are located at the bottom of the screen — in the easy-to-reach area. (Design concept of EMUI 5 interface by Fantasy) (Large preview) Ideation: Defining A Design Vision Creating A Philosophy Of Design

Imagine that you need to design a language that will be integrated into products that will be used by people all over the world. The natural language we use in interpersonal communications cannot be separated from a culture because it has a close relation to the attitude or behavior of speakers of the languages. The digital language is absolutely the same — it should look natural for customers in the Americas, Europe, Asia, Africa, and Oceania.

The success of any visual design highly relates to how people perceive it. Many factors are influencing human perception, and the significant part goes to psychology. To create a sophisticated design, you need to consider the meaning of shapes and the impact which they have on users’ minds.

Creating a philosophy of design is extremely challenging, and you cannot do it alone. That’s why I worked with Abigail Brody, a former Apple creative director who joined Huawei in September 2015 as Chief UX design and VP of Huawei Devices. At Apple, Abigail was responsible for iOS design. She was the one who described the methodology of visual language to me.

Together we spend a lot of time trying to find the direction for visual design, and we’ve decided to use the philosophy of organic design as a foundation for our design language. Organic design is centered around using nature as the biggest inspiration.

Frank Lloyd Wright chair Organic Design was pioneered by Frank Lloyd Wright who believed in creating harmony between people and nature. (Image credit: museiitaliani) (Large preview)

According to this philosophy, design should help to achieve harmony between people and nature. When we worked on our visual language, we focused on incorporating natural forms (smooth curves and organic forms) in our visual design. As a result, all visual elements, such as buttons, icons, and shapes, had an organic design aesthetic.

Design concept of EMUI 5 interface Round shapes are one of the things that make organic objects different from non-organic. (Large preview) Using Motion Design To Create A Distinct Visual Identity

There is no doubt about the importance of the role that motion plays in mobile design. For many product motion serves a purely-functional role—it provides feedback for user action and connects different states of the mobile app together. The well-crafted motion also makes things more attractive, and as we know, attractive things work better (the aesthetic-usability effect says that people are more tolerant of minor usability issues when they find an interface visually appealing).

Our team put high stakes on the motion. Our ultimate goal was to use motion to breathe life into our products — make the interface feel alive and dynamic. We wrote a motion design manifesto with solid design principles. Every animated effect and transition that we wanted to introduce in our design was measured in accordance with the functional and emotional benefits it delivers to end-users.

We know that early impressions of a product design are especially important. And for that very reason our key focus was on creating magical moments — surprise and delight users while they interact with the OS.

This video demonstrates the visual effects we used in EMUI. Design And Testing: Build, Test, Iterate Baking Meaning Into Every Design Element/Design Decision

Just like we have rules for using words in sentences in a natural language, we should have rules for using visual elements in visual language. Strong semantics is what makes visual communication efficient.

When a team works on a visual language, it should take two rules into account:

  • There are no random visual elements in a visual language. Every element serves a purpose.
  • There should be no isolated units in visual language. Every unit in a visual language should be a part of a greater whole.
Design concept of EMUI 5 interface The animated effect behind the user avatar is used to convey a sense of active call. The animation is both meaningful and pleasurable. (Design concept of EMUI 5 interface) (Large preview) Experimentation And Design Review

It’s impossible to create a great design from the first attempt. Design is an iterative process, and whenever our team created a new visual solution, they evaluated it by comparing it with previous solutions. The comparison was visual—the screens were laid side by side on a board, so everyone could see the parts that require additional polishing. Team members gather together on informal design reviews where they discuss the pros and cons of individual solutions.

Team reviewing designs on computer screen Design review in progress at Fantasy Interactive (Large preview) Pattern Libraries, Style Guides And Design Principles

Pattern libraries (reusable building blocks such as UI bars), style guides, and design principles (principles that allow developers to propagate design language in their own apps) are essential elements of design language. They are the foundation of the design system — a shared resource that teams use when they create interfaces. The fact that we’ve conducted a UI audit during the research phase helped us to categorize the visual design elements. We’ve established a toolbox for everyone who worked on the project. So, when a new member joins a team, all they need is the toolbox, and they are set to maintain consistency.

There are no random visual elements in a visual language. Every element serves a purpose.

“ Test Early, Test Often

The Huawei EMUI project was an extremely important project for the Huawei Corporation. It was essential to ensure that the language we’ve defined work for the users. And the only way to get this understanding is to test our design as soon as possible.

We’ve followed a simple but effective technique — build, measure, learn. By following this approach, the design team didn’t postpone the testing design until the release. We’ve incorporated visual language into functional prototypes and tested them both inside our group (dogfooding) and outside (with real users). The feedback collected during the testing allowed us to understand what worked/doesn’t work for users.

Product team meeting at Fantasy Interactive Sharing the results of testing with product teams at Fantasy Interactive (Large preview) Implementation

If you have had a chance to use the Huawei EMUI 5 interface, you are probably thinking to yourself, “Um, that doesn’t look exactly like Gleb said!” And that’s true.

Huawei OS screenshot Production version of the Huawei EMUI 5 interface. (Image credit: androidauthority) (Large preview)

It is a sad reality that almost no design team is responsible for the implementation of this solution. Unfortunately, a lot of solutions we proposed to the engineering team weren’t implemented properly, or at all. As a result, the design language we’ve created and the design language the end-user saw in Huawei products end up as two different animals. But this is purely my opinion. In 2018, Huawei surpassed Apple in smartphone sales. The UI was a critical element to user confidence.

Based on my experience, the challenge of implementation is common for large-scale corporations. When designers who created the language aren’t invited into the process of implementing this language into the product, the final results will always be compromised. What usually happens is the engineering team follows a path of least resistance — they adjust the design solutions to the technical constraints they face when they start.

Every company needs a top-manager who cares about design and is ready to fight for it. It’s a well-known fact that when the original minimize animation in macOS that was proposed by the Apple motion design team, the engineering team said that it was impossible to implement that. At that time, Steve Jobs insisted that this animation is a must-have for MacOS. As a result, this animation became not only the most memorable transition for first-time users but also one of the things that contribute to good UX in MacOS.

A screenshot of Mac OS The instantly memorable window animation of the Mac OS (Large preview) A Robust Visual Design Language Is The Heart Of Good UX

Visual language can have a dramatic impact on user experience. It’s able not only to reduce friction by making UI more predictable but also to create delight. By pairing great form with excellent function, we will have an excellent user experience.

Visual language is a by-product of product design, and it requires a similar design process. It’s iterative and requires validation at every step along the way. When you build a visual language, you establish a new ecosystem for designers, and this ecosystem creates harmony between different teams involved in product development.

Smashing Editorial (cc, ra, il)
Catégories: Programmation

Smart Interface Design Patterns Checklists PDF

lun, 03/30/2020 - 11:30
Smart Interface Design Patterns Checklists PDF Smart Interface Design Patterns Checklists PDF Rachel Andrew 2020-03-30T09:30:00+00:00 2020-03-30T09:45:31+00:00

Sharing the things we have learned is at the heart of everything we do at Smashing. That goes for the team as well as our authors, and Vitaly has been working on a set of checklists to accompany his workshop, [Smart Interface Design Patterns](https://smashingconf.com/online-workshops/workshops/vitaly-friedman-ux). The resulting PDF is 152 pages packed with useful information to help you create better interfaces. And, we’re offering it to you free of charge.

These checklists are based on the work Vitaly has been doing for many years, exploring and examining examples of desktop and mobile interfaces. Learning what works and what doesn’t in usability tests and user interviews.

The cover of the PDF deck on “Smart Interface Design Patterns” The cover of the PDF deck on “Smart Interface Design Patterns”, curated by Vitaly Friedman. You can get the entire deck (150 pages) by subscribing to our lovely email newsletter.

In the PDF is a collection of over 150 questions to ask yourself when designing and building almost anything — accordions, drop-downs, carousels, timelines, tables, sliders, advanced configurators, maps, seating selection, and onboarding. They can act as a jumping-off point for discussion, as designers and developers sit together to plan a component, or work through a particular design problem.

A screenshot of the Hamburger Design Checklist with 13 questions to discuss when designing and building a good navigation An example: Hamburger Design Checklist, with questions to discuss when designing and building a good navigation.

They can help to bring to mind all the fine details that go into interface design. How large should a hamburger icon be to avoid rage clicks? Should sections in an accordion collapse automatically when moving from one to another? Can users tap on the same spot to undo actions when zooming or filtering?

These aren’t golden rules, but rather starting points to help you consider all angles when working alone, or in a team. These checklists have been created after years of work on real projects with real users. Your projects can benefit from all of that existing knowledge, rather than needing to discover these issues for yourself or wait for your visitors to tell you about the problems they are having.

Three different design patterns without hamburger navigation on three mobile devices The PDF deck features some examples of design patterns as well. A quick peek at some navigation design patterns without hamburger navigation. Large preview) Subscribe To Newletter and Get The PDF

To download, we ask for one thing: your real email address. In return, you’ll get the checklist and also our Smashing bi-monthly email newsletter and occasional emails when we have a new book or event that might be of interest. We don’t spam, nor do we pass on your email address to anyone outside of Smashing.

  1. Subscribe to our lovely email newsletter.
    Please use your actual email — it’s no fun to land in spam.
  2. Verify your email.
    Please check your inbox and click on a button in the confirmation email.
  3. Download the checklist PDF.
    Voilà! We hope you’ll find the PDF useful for your work.
With Smashing Newsletter, it always feels like home. A cat with slippers reading the newsletter edition.Smashing Newsletter

Every second Tuesday, we send a newsletter on front-end and UX. Subscribe and get “Smart Interface Design Checklists” in your inbox.

Your (smashing) email Subscribe → Front-end, design and UX. Sent 2× a month.
You can always unsubscribe with just one click.

After subscribing, you’ll get a link to the PDF via email. If you are already subscribed, look out for the link in the upcoming newsletter issue coming this Tuesday, March 31. And please, ask your friends and colleagues to subscribe rather than simply forwarding the link on.

There is a huge amount of work that has gone into this PDF. We hope you’ll find it useful in your work. Thank you for your trust, and we hope to release more useful tools for you soon!

Smashing Editorial (vf, il)
Catégories: Programmation

Pages