123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- <!doctype html><!-- This is a valid HTML5 document. -->
- <!-- Screen readers, SEO, extensions and so on. -->
- <html lang=fr>
- <!-- Has to be within the first 1024 bytes, hence before the <title>
- See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
- <meta charset=utf-8>
- <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
- <!-- The viewport meta is quite crowded and we are responsible for that.
- See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
- <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
- <!-- Required to make a valid HTML5 document. -->
- <title>“God is in the details.” (archive) — David Larlet</title>
- <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
- <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
- <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
- <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
- <link rel="manifest" href="/manifest.json">
- <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
- <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
- <meta name="apple-mobile-web-app-title" content="David Larlet">
- <meta name="application-name" content="David Larlet">
- <meta name="msapplication-TileColor" content="#da532c">
- <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
- <meta name="theme-color" content="#f0f0ea">
- <!-- That good ol' feed, subscribe :p. -->
- <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
-
- <meta name="robots" content="noindex, nofollow">
- <meta content="origin-when-cross-origin" name="referrer">
- <!-- Canonical URL for SEO purposes -->
- <link rel="canonical" href="https://medium.com/@buzzusborne/god-is-in-the-details-bc3a9a9a5d88">
-
- <style>
- /* http://meyerweb.com/eric/tools/css/reset/ */
- html, body, div, span,
- h1, h2, h3, h4, h5, h6, p, blockquote, pre,
- a, abbr, address, big, cite, code,
- del, dfn, em, img, ins,
- small, strike, strong, tt, var,
- dl, dt, dd, ol, ul, li,
- fieldset, form, label, legend,
- table, caption, tbody, tfoot, thead, tr, th, td,
- article, aside, canvas, details, embed,
- figure, figcaption, footer, header, hgroup,
- menu, nav, output, ruby, section, summary,
- time, mark, audio, video {
- margin: 0;
- padding: 0;
- border: 0;
- font-size: 100%;
- font: inherit;
- vertical-align: baseline;
- }
- /* HTML5 display-role reset for older browsers */
- article, aside, details, figcaption, figure,
- footer, header, hgroup, menu, nav, section { display: block; }
- body { line-height: 1; }
- blockquote, q { quotes: none; }
- blockquote:before, blockquote:after,
- q:before, q:after {
- content: '';
- content: none;
- }
- table {
- border-collapse: collapse;
- border-spacing: 0;
- }
-
- /* http://practicaltypography.com/equity.html */
- /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
- /* https://www.filamentgroup.com/lab/js-web-fonts.html */
- @font-face {
- font-family: 'EquityTextB';
- src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
- url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
- font-weight: 300;
- font-style: normal;
- font-display: swap;
- }
- @font-face {
- font-family: 'EquityTextB';
- src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
- url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
- font-weight: 300;
- font-style: italic;
- font-display: swap;
- }
- @font-face {
- font-family: 'EquityTextB';
- src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
- url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
- font-weight: 700;
- font-style: normal;
- font-display: swap;
- }
-
- @font-face {
- font-family: 'ConcourseT3';
- src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
- url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
- font-weight: 300;
- font-style: normal;
- font-display: swap;
- }
-
-
- /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
- body {
- /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
- font-family: "EquityTextB", Palatino, serif;
- background-color: #f0f0ea;
- color: #07486c;
- font-kerning: normal;
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: subpixel-antialiased;
- text-rendering: optimizeLegibility;
- font-variant-ligatures: common-ligatures contextual;
- font-feature-settings: "kern", "liga", "clig", "calt";
- }
- pre, code, kbd, samp, var, tt {
- font-family: 'TriplicateT4c', monospace;
- }
- em {
- font-style: italic;
- color: #323a45;
- }
- strong {
- font-weight: bold;
- color: black;
- }
- nav {
- background-color: #323a45;
- color: #f0f0ea;
- display: flex;
- justify-content: space-around;
- padding: 1rem .5rem;
- }
- nav:last-child {
- border-bottom: 1vh solid #2d7474;
- }
- nav a {
- color: #f0f0ea;
- }
- nav abbr {
- border-bottom: 1px dotted white;
- }
-
- h1 {
- border-top: 1vh solid #2d7474;
- border-bottom: .2vh dotted #2d7474;
- background-color: #e3e1e1;
- color: #323a45;
- text-align: center;
- padding: 5rem 0 4rem 0;
- width: 100%;
- font-family: 'ConcourseT3';
- display: flex;
- flex-direction: column;
- }
- h1.single {
- padding-bottom: 10rem;
- }
- h1 span {
- position: absolute;
- top: 1vh;
- left: 20%;
- line-height: 0;
- }
- h1 span a {
- line-height: 1.7;
- padding: 1rem 1.2rem .6rem 1.2rem;
- border-radius: 0 0 6% 6%;
- background: #2d7474;
- font-size: 1.3rem;
- color: white;
- text-decoration: none;
- }
- h2 {
- margin: 4rem 0 1rem;
- border-top: .2vh solid #2d7474;
- padding-top: 1vh;
- }
- h3 {
- text-align: center;
- margin: 3rem 0 .75em;
- }
- hr {
- height: .4rem;
- width: .4rem;
- border-radius: .4rem;
- background: #07486c;
- margin: 2.5rem auto;
- }
- time {
- display: bloc;
- margin-left: 0 !important;
- }
- ul, ol {
- margin: 2rem;
- }
- ul {
- list-style-type: square;
- }
- a {
- text-decoration-skip-ink: auto;
- text-decoration-thickness: 0.05em;
- text-underline-offset: 0.09em;
- }
- article {
- max-width: 50rem;
- display: flex;
- flex-direction: column;
- margin: 2rem auto;
- }
- article.single {
- border-top: .2vh dotted #2d7474;
- margin: -6rem auto 1rem auto;
- background: #f0f0ea;
- padding: 2rem;
- }
- article p:last-child {
- margin-bottom: 1rem;
- }
- p {
- padding: 0 .5rem;
- margin-left: 3rem;
- }
- p + p,
- figure + p {
- margin-top: 2rem;
- }
-
- blockquote {
- background-color: #e3e1e1;
- border-left: .5vw solid #2d7474;
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 1rem;
- margin: 1.5rem;
- }
- blockquote cite {
- font-style: italic;
- }
- blockquote p {
- margin-left: 0;
- }
-
- figure {
- border-top: .2vh solid #2d7474;
- background-color: #e3e1e1;
- text-align: center;
- padding: 1.5rem 0;
- margin: 1rem 0 0;
- font-size: 1.5rem;
- width: 100%;
- }
- figure img {
- max-width: 250px;
- max-height: 250px;
- border: .5vw solid #323a45;
- padding: 1px;
- }
- figcaption {
- padding: 1rem;
- line-height: 1.4;
- }
- aside {
- display: flex;
- flex-direction: column;
- background-color: #e3e1e1;
- padding: 1rem 0;
- border-bottom: .2vh solid #07486c;
- }
- aside p {
- max-width: 50rem;
- margin: 0 auto;
- }
-
- /* https://fvsch.com/code/css-locks/ */
- p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
- font-size: 1rem;
- line-height: calc( 1.5em + 0.2 * 1rem );
- }
- h1 {
- font-size: 1.9rem;
- line-height: calc( 1.2em + 0.2 * 1rem );
- }
- h2 {
- font-size: 1.6rem;
- line-height: calc( 1.3em + 0.2 * 1rem );
- }
- h3 {
- font-size: 1.35rem;
- line-height: calc( 1.4em + 0.2 * 1rem );
- }
- @media (min-width: 20em) {
- /* The (100vw - 20rem) / (50 - 20) part
- resolves to 0-1rem, depending on the
- viewport width (between 20em and 50em). */
- p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
- font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
- line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
- margin-left: 0;
- }
- h1 {
- font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
- line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
- }
- h2 {
- font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
- line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
- }
- h3 {
- font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
- line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
- }
- }
- @media (min-width: 50em) {
- /* The right part of the addition *must* be a
- rem value. In this example we *could* change
- the whole declaration to font-size:2.5rem,
- but if our baseline value was not expressed
- in rem we would have to use calc. */
- p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
- font-size: calc( 1rem + .6 * 1rem );
- line-height: 1.5em;
- }
- p, li, pre, details {
- margin-left: 3rem;
- }
- h1 {
- font-size: calc( 1.9rem + 1.5 * 1rem );
- line-height: 1.2em;
- }
- h2 {
- font-size: calc( 1.5rem + 1.5 * 1rem );
- line-height: 1.3em;
- }
- h3 {
- font-size: calc( 1.35rem + 1.5 * 1rem );
- line-height: 1.4em;
- }
- figure img {
- max-width: 500px;
- max-height: 500px;
- }
- }
-
- figure.unsquared {
- margin-bottom: 1.5rem;
- }
- figure.unsquared img {
- height: inherit;
- }
-
-
-
- @media print {
- body { font-size: 100%; }
- a:after { content: " (" attr(href) ")"; }
- a, a:link, a:visited, a:after {
- text-decoration: underline;
- text-shadow: none !important;
- background-image: none !important;
- background: white;
- color: black;
- }
- abbr[title] { border-bottom: 0; }
- abbr[title]:after { content: " (" attr(title) ")"; }
- img { page-break-inside: avoid; }
- @page { margin: 2cm .5cm; }
- h1, h2, h3 { page-break-after: avoid; }
- p3 { orphans: 3; widows: 3; }
- img {
- max-width: 250px !important;
- max-height: 250px !important;
- }
- nav, aside { display: none; }
- }
-
- ul.with_columns {
- column-count: 1;
- }
- @media (min-width: 20em) {
- ul.with_columns {
- column-count: 2;
- }
- }
- @media (min-width: 50em) {
- ul.with_columns {
- column-count: 3;
- }
- }
- ul.with_two_columns {
- column-count: 1;
- }
- @media (min-width: 20em) {
- ul.with_two_columns {
- column-count: 1;
- }
- }
- @media (min-width: 50em) {
- ul.with_two_columns {
- column-count: 2;
- }
- }
-
- .gallery {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-around;
- }
- .gallery figure img {
- margin-left: 1rem;
- margin-right: 1rem;
- }
- .gallery figure figcaption {
- font-family: 'ConcourseT3'
- }
-
- footer {
- font-family: 'ConcourseT3';
- display: flex;
- flex-direction: column;
- border-top: 3px solid white;
- padding: 4rem 0;
- background-color: #07486c;
- color: white;
- }
- footer > * {
- max-width: 50rem;
- margin: 0 auto;
- }
- footer a {
- color: #f1c40f;
- }
- footer .avatar {
- width: 200px;
- height: 200px;
- border-radius: 50%;
- float: left;
- -webkit-shape-outside: circle();
- shape-outside: circle();
- margin-right: 2rem;
- padding: 2px 5px 5px 2px;
- background: white;
- border-left: 1px solid #f1c40f;
- border-top: 1px solid #f1c40f;
- border-right: 5px solid #f1c40f;
- border-bottom: 5px solid #f1c40f;
- }
- </style>
-
- <h1>
- <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
- “God is in the details.” (archive)
- <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
- </h1>
- <section>
- <article>
- <h3><a href="https://medium.com/@buzzusborne/god-is-in-the-details-bc3a9a9a5d88">Source originale du contenu</a></h3>
- <p name="77c9" id="77c9" class="graf--p">It applied to <a target="_blank" href="http://en.wikipedia.org/wiki/Ludwig_Mies_van_der_Rohe" data-href="http://en.wikipedia.org/wiki/Ludwig_Mies_van_der_Rohe" class="markup--anchor markup--p-anchor" rel="nofollow">Ludwig Mies van der Rohe</a> when he was designing buildings in the mid 1900’s, and it remains true in product design today. Though I don’t profess to know much about architecture, another likely commonality with product design is that it’s those same details that are the easiest to forget. But it’s those little things, the tiny minutia of detail, that ultimately make beautiful products, and beautiful houses.</p>
-
- <p name="e21d" id="e21d" class="graf--p">Unfortunately, when I refer to the “details” in product design, I’m not talking about obvious design things; like colours, drop-shadows or placement. Instead I’m referring to something harder to define; experience and subconscious patterns that help the user feel more at-ease with an interaction. That detail might come in the form of a change in cursor, a “down” style for a button, or a helpful animation.</p>
-
- <p name="b064" id="b064" class="graf--p graf--last">Whatever form that detail takes, I’ll bet that it wasn’t designed in Photoshop, or included in even the most detailed spec document. It’s the details that fall outside of titles like UX, or UI. It’s interaction detail that can only be found after using a product <em class="markup--em markup--p-em">for real</em>, then dedicating solid design and engineering time to building.</p>
-
- <p></div></div></section><section name="1cbf"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><p name="2476" id="2476" class="graf--p graf--first">The details are difficult to include when you’re building a product; they’re expensive both in terms of time and technical overhead — which is why they’re rare. I spend my time in pursuit of these details, and as the designer and developer of <a target="_blank" href="https://prevue.it/" data-href="https://prevue.it/" class="markup--anchor markup--p-anchor" rel="nofollow">Prevue</a>, I have two luxuries which thankfully afford me the ability to obsess over them:</p><p name="c641" id="c641" class="graf--p"><strong class="markup--strong markup--p-strong">The first</strong> is that I have the capacity to <a target="_blank" href="http://blog.prevue.it/posts/use-improve-repeat" data-href="http://blog.prevue.it/posts/use-improve-repeat" class="markup--anchor markup--p-anchor" rel="nofollow">use, improve and repeat</a>. I’m not just talking about about the technical ability to implement the details — I’m also talking about having the <em class="markup--em markup--p-em">time</em> to do so. Sometimes an interaction will take me 50% longer to build, simply because I’ve spent hours obsessing about the animated states that occur over a 0.65 second duration. That’s not a luxury that many products can afford, or are willing to build into scope. Understandably so.</p><p name="2343" id="2343" class="graf--p"><strong class="markup--strong markup--p-strong">The second</strong> is that I use my product, for real, every single day. If there’s an annoying interaction, unnecessarily lengthy animation or a dumb user-flow — the chances are pretty high that I’m going to spot it. That’s the difference between functional testing:</p><blockquote name="a3ca" id="a3ca" class="graf--pullquote pullquote graf--startsWithDoubleQuote">“Does X do Y when you press Z?”</blockquote><p name="a4b4" id="a4b4" data-align="center" class="graf--p">Versus true-to-life user-testing:</p><blockquote name="2a67" id="2a67" class="graf--pullquote pullquote graf--startsWithDoubleQuote">“Does the product intuitively help me achieve a task,<br>quickly, when I’m up against a deadline?”</blockquote><p name="68e7" id="68e7" class="graf--p">But let’s be honest; using a product over-and-over, re-building functionality, and obsessing about the little things takes a <em class="markup--em markup--p-em">lot </em>of<em class="markup--em markup--p-em"> </em>time — perhaps a luxury afforded to side-projects like Prevue, or products with too much money. They’re usually too hard to justify, and they’re definitely the first thing to be sacrificed when push comes to shove. That’s probably why Ludwig Mies van der Rohe only designed a handful of buildings that weren’t ugly skyscrapers — or why Prevue doesn’t ship features very often.</p><p name="225d" id="225d" class="graf--p graf--last">Having spent the last 7 years polishing my own side-project, I’ve learned where to look for “quick wins” when it comes to building detail-oriented design into larger, fast-moving commercial products. So instead of professing to knowing the perfect solution for forcing “detail-mining” into your release schedule, I thought I’d share a few places where you can start looking for improvement in your own projects, and why those details can make all the difference.</p></div></div></section><section name="63d1"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="40be" id="40be" data-align="center" class="graf--h3 graf--first">Visually Confirm Interactions</h3><p name="c5dc" id="c5dc" class="graf--p">I’m going to start with something that applies to most products, yet is so commonly overlooked — button states. Even on a fast internet connection, there’s likely going to be a delay after pressing a button before the next action takes place; like a new page load, image upload, or some kind of event. Yet so few products give any visual confirmation that something is happening in the background.</p><p name="9a00" id="9a00" class="graf--p">Leaving the user hanging there, with no confirmation that their click actually did anything, is likely causing an unnecessary break in their journey. Whilst your servers are processing the action, your user is wondering whether their click actually registered. They’re <em class="markup--em markup--p-em">thinking</em> about your UI. That’s the very opposite of what you want.</p><p name="5a78" id="5a78" class="graf--p">The solution is to consider adding a button style for when the user has clicked, then another style or animation for when the submission has been made. At the very least, this shows that the user did, indeed, <em class="markup--em markup--p-em">click</em>.</p><figure name="83be" id="83be" class="graf--figure"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 200px;"><div class="aspect-ratio-fill" style="padding-bottom: 28.599999999999998%;"></div><img class="graf-image" data-image-id="1*UFlVP_L5ztX-T3sriUjvIw.gif" data-width="700" data-height="200" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*UFlVP_L5ztX-T3sriUjvIw.gif"></div><figcaption class="imageCaption">Every button in <a target="_blank" href="https://prevue.it/" data-href="https://prevue.it/" class="markup--anchor markup--figure-anchor" rel="nofollow">Prevue</a> has a ‘down’ state, and animation to confirm that your click was understood</figcaption></figure><p name="299b" id="299b" class="graf--p">Better still, if the action is likely going to take a little while — consider actually <em class="markup--em markup--p-em">telling</em> the user what’s happening. If you can’t explain something adequately through design, then there’s no shame in literally spelling it out.</p><figure name="2c8b" id="2c8b" class="graf--figure"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 132px;"><div class="aspect-ratio-fill" style="padding-bottom: 18.9%;"></div><img class="graf-image" data-image-id="1*zn3A_E4OKkCs294tL1qy2A.gif" data-width="700" data-height="132" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*zn3A_E4OKkCs294tL1qy2A.gif"></div></figure><p name="4b81" id="4b81" class="graf--p graf--last">Of course, attention to detail can run deeper than basic styling. A good example is when it comes to uploading images (an action that takes considerable time). In the event where user interaction is predicted to last into the 2+ second range, you might be better off faking success than making your user wait.</p></div></div></section><section name="876a"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="cbc8" id="cbc8" data-align="center" class="graf--h3 graf--first">Use Subtle Animation</h3><p name="eddd" id="eddd" class="graf--p">I could talk for days about the importance of animation, and the role it plays in helping users understand an interface — fortunately there are already plenty of <a target="_blank" href="http://stevenfabre.com/work/making-a-difference-with-animation" data-href="http://stevenfabre.com/work/making-a-difference-with-animation" class="markup--anchor markup--p-anchor" rel="nofollow">better resources</a> out there. Instead, I’ll just touch on the importance of subtle, almost <em class="markup--em markup--p-em">invisible</em> animation.</p><p name="aa0e" id="aa0e" class="graf--p">Take the following as an example; dragging an image to a folder doesn’t <em class="markup--em markup--p-em">require </em>feedback — it just works… but the user doesn’t know that. So a small animation that infers success is all it takes to alleviate uncertainty.</p><figure name="7468" id="7468" class="graf--figure"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 350px;"><div class="aspect-ratio-fill" style="padding-bottom: 50%;"></div><img class="graf-image" data-image-id="1*yEeEh-RfVR2lWbo4id9fxg.gif" data-width="700" data-height="350" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*yEeEh-RfVR2lWbo4id9fxg.gif"></div><figcaption class="imageCaption">Notice how the “X images” number takes slightly longer to update? That’s the actual time it takes for the server to respond. In this case, the “nom” animation helps the user continue about their business</figcaption></figure><p name="a1ca" id="a1ca" class="graf--p">Animation can also help to indicate context, and transition between views. Instead of abruptly moving between states, risking losing the focus of your user, animation can help indicate where things <em class="markup--em markup--p-em">came from.</em></p><figure name="0543" id="0543" class="graf--figure graf--last"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 331px;"><div class="aspect-ratio-fill" style="padding-bottom: 47.3%;"></div><img class="graf-image" data-image-id="1*GWM2hrch2ANwKyXxqoKWeQ.gif" data-width="700" data-height="331" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*GWM2hrch2ANwKyXxqoKWeQ.gif"></div></figure></div></div></section><section name="d124"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="620f" id="620f" data-align="center" class="graf--h3 graf--first">Remember, Things Load</h3><p name="0db8" id="0db8" class="graf--p">I recall reviewing the notes from a user testing session whilst working at Skype — where we had given people a drag-and-drop UI that saved ‘<em class="markup--em markup--p-em">on drop’</em>. It was so well-built, that the action of saving was almost instantaneous, and didn’t even require a loading state.</p><p name="4278" id="4278" class="graf--p">It was <em class="markup--em markup--p-em">so</em> fast, in fact, that users had a total disbelief that their action was successful — ultimately causing more confusion and anxiety than necessary. The solution? Pretending that the product was “thinking”, by adding a loading spinner on event of a drop. Even though it wasn’t.</p><p name="6944" id="6944" class="graf--p">That was a good use-case for a loading spinner. But most of the time, I see designers adding spinners, simply because they <em class="markup--em markup--p-em">can</em>. Most of the time, the user doesn’t need to be told that something is loading at all, and adding a spinning graphic is likely to command more attention than necessary.</p><p name="5c38" id="5c38" class="graf--p">Take the following example — the image, which is dynamically generated (slow) then loaded via AJAX, isn’t the point of the page… the text is. In this case, animation replaces the need for spinners or delays.</p><figure name="b8de" id="b8de" class="graf--figure graf--last"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 326px;"><div class="aspect-ratio-fill" style="padding-bottom: 46.6%;"></div><img class="graf-image" data-image-id="1*Q03nt9FrPYewyLbRbRhFNQ.gif" data-width="700" data-height="326" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*Q03nt9FrPYewyLbRbRhFNQ.gif"></div><figcaption class="imageCaption">Loading a dynamically generated image is costly. So instead of commanding the users’ attention with a spinning graphic, there’s a simple blank slate</figcaption></figure></div></div></section><section name="22f9"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="5123" id="5123" data-align="center" class="graf--h3 graf--first">Optimise for Context</h3><p name="ffa7" id="ffa7" class="graf--p">With any product that contains data, images or reporting — it’s likely that no screen is ever going to look the same. Yet when designing, we optimise for the best-case scenario, and often forget about when there’s no data, lots of data, or somewhere in-between. A good start is to ditch lorem ipsum, stock-quality images or perfectly rounded numbers in designs — and optimise for context instead. What does <em class="markup--em markup--p-em">real </em>data look like?</p><p name="22fc" id="22fc" class="graf--p">By considering the various states of a UI, you can begin to get creative about how to design accordingly. For example, a group of images in Prevue will change configuration depending on how many there are — to make sure that no matter what, the users images always looks nice.</p><figure name="5eaa" id="5eaa" class="graf--figure"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 366px;"><div class="aspect-ratio-fill" style="padding-bottom: 52.300000000000004%;"></div><img class="graf-image" data-image-id="1*e_1CqkbgCHHH3kz64Xh16g.jpeg" data-width="700" data-height="366" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*e_1CqkbgCHHH3kz64Xh16g.jpeg"></div></figure><p name="f0a2" id="f0a2" class="graf--p">Being context-aware isn’t just about looking good, either. Situational context is about identifying when and where extra attention should be paid to seemingly straight-forward, commonplace UI.</p><figure name="7c8a" id="7c8a" class="graf--figure postField--insetLeftImage"><div class="aspectRatioPlaceholder is-locked" style="max-width: 350px; max-height: 168px;"><div class="aspect-ratio-fill" style="padding-bottom: 47.9%;"></div><img class="graf-image" data-image-id="1*iD3cU2jlK6Au31UxL2qKXQ.gif" data-width="357" data-height="171" data-action="zoom" data-action-value="1*iD3cU2jlK6Au31UxL2qKXQ.gif" src="https://d262ilb51hltx0.cloudfront.net/max/800/1*iD3cU2jlK6Au31UxL2qKXQ.gif"></div><figcaption class="imageCaption">A modified version of Stripe’s <a target="_blank" href="https://stripe.com/blog/jquery-payment" data-href="https://stripe.com/blog/jquery-payment" class="markup--anchor markup--figure-anchor" rel="nofollow">Payment plugin</a> using learnings from <a target="_blank" href="http://bradfrost.com/blog/post/single-field-credit-card-input-pattern/" data-href="http://bradfrost.com/blog/post/single-field-credit-card-input-pattern/" class="markup--anchor markup--figure-anchor" rel="nofollow">Brad Frost’s article</a></figcaption></figure><p name="2346" id="2346" class="graf--p">Take credit card forms for example — an area where extra care and attention can help users subconsciously understand what’s required of them, and prevent potential errors.</p><p name="fa21" id="fa21" class="graf--p">They’re also a perfect example of the value of real-life testing — there’s so much anxiety involved in entering secure, financial details that you simply can’t appreciate it until you try for yourself. When building the credit card form for Prevue (<em class="markup--em markup--p-em">above)</em>, I tested several live versions in an attempt to perfect the experience. Every time, my card was actually charged $10 — which was a<strong class="markup--strong markup--p-strong"> </strong>great incentive to get it right.</p><p name="3f24" id="3f24" class="graf--p">Context is key in a situation like this, and even the tiniest details can help users understand what they’re doing. For example:</p><ul class="postList"><li name="554a" id="554a" class="graf--li">Format the numbers in the same way as on the physical card</li><li name="94af" id="94af" class="graf--li">Preventing non-numerical characters, or more numbers than necessary</li><li name="db45" id="db45" class="graf--li">Assuming MM/<strong class="markup--strong markup--li-strong">YYYY</strong> if MM/<strong class="markup--strong markup--li-strong">YY</strong> is entered</li></ul><p name="2b88" id="2b88" class="graf--p graf--last">By considering what content might be displayed, the circumstances in which a task might be undertaken, or the feeling of the user at the time — you’ll be able to balance what <em class="markup--em markup--p-em">looks </em>best with what <em class="markup--em markup--p-em">works</em> best.</p></div></div></section><section name="3c12"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="041a" id="041a" data-align="center" class="graf--h3 graf--first">Respect Native Functionality</h3><p name="49b5" id="49b5" class="graf--p">Your product should respect the functionality of the platform in which it lives — which means it definitely shouldn’t alter native functionality, like ‘hijacking’ your scrollbar, and should ideally complement existing user experience patterns.</p><p name="1e7c" id="1e7c" class="graf--p">For example, some people are used to using keyboard commands to perform common actions. So if your product allows the user to perform a potentially disruptive action (like moving content around, or deleting lots of text) — then you should strongly consider allowing Ctrl+Z functionality to ‘Undo’. The same applies for saving (Ctrl+S), pressing ESC to dismiss a modal window, or “clicking away” to close a dropdown or open menu.</p><p name="fd8a" id="fd8a" class="graf--p">By preventing your user from performing an interaction they’re familiar with — you’re creating an unnecessary <em class="markup--em markup--p-em">pause</em>; a moment of uncertainty for them.</p><p name="2dbe" id="2dbe" class="graf--p">There should also be no <strong class="markup--strong markup--p-strong">wrong way</strong> for a user to perform an action. For example, in both Prevue and <a target="_blank" href="https://www.campaignmonitor.com/email-templates/" data-href="https://www.campaignmonitor.com/email-templates/" class="markup--anchor markup--p-anchor" rel="nofollow">Email Builder</a>, users can upload an image by pressing the “upload” button — but if dragging a handful of images directly into the browser is what someone is used to; both products are built to allow for that too.</p><p name="2eba" id="2eba" class="graf--p graf--last">Building two or three different ways to perform the <em class="markup--em markup--p-em">exact same</em> action seems like unnecessary complexity, especially if you don’t even tell users that functionality exists. But when users are able to use your product how <em class="markup--em markup--p-em">they</em> want; you end up creating a seamless and fluid experience that people feel comfortable using. It’s why iPad’s were designed to emulate the familiar actions of leafing through a magazine’s pages.</p></div></div></section><section name="5b5a"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><h3 name="aafd" id="aafd" data-align="center" class="graf--h3 graf--first">Set the Tone</h3><p name="022d" id="022d" class="graf--p graf--empty"><br></p><p name="55d2" id="55d2" class="graf--p">The final, and arguably easiest detail to implement, is <em class="markup--em markup--p-em">tone of voice</em>. In the midsts of designing tough UI and writing functional documentation — it’s easy to forget that you’re building a product for real people. Forgetting to add a human touch to your copywriting can result in error messages reading as though they’re composed by robots — reminding users that they’re dealing with a faceless machine, right at the moment they need the most guidance. <a target="_blank" href="https://twitter.com/davegreiner/" data-href="https://twitter.com/davegreiner/" class="markup--anchor markup--p-anchor" rel="nofollow">Dave Greiner</a> gave me some good advice about copywriting:</p><blockquote name="a80d" id="a80d" class="graf--blockquote">Read your copy aloud, and imagine you’re talking to your user face-to-face</blockquote><p name="0a15" id="0a15" class="graf--p">It’s great advice for two reasons; firstly because you quickly spot when your message becomes unnecessarily lengthy, impersonal, or even rude. And secondly, because reading your message aloud will inform you when being overtly personal isn’t appropriate for the context either.</p><p name="34c1" id="34c1" class="graf--p">Take the following as an example of the latter — where I got the tone and context completely wrong for an error message:</p><figure name="23d3" id="23d3" class="graf--figure"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 239px;"><div class="aspect-ratio-fill" style="padding-bottom: 34.1%;"></div><img class="graf-image" data-image-id="1*W2hilxGUVLGW6w-MHlMgNQ.png" data-width="700" data-height="239" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*W2hilxGUVLGW6w-MHlMgNQ.png"></div><figcaption class="imageCaption">Not helpful.</figcaption></figure><p name="ea75" id="ea75" class="graf--p">In an attempt to be disarming and <em class="markup--em markup--p-em">human</em>, I wrote the above message to be displayed on the rare occasion when uploads failed due to server error. What I didn’t consider was <strong class="markup--strong markup--p-strong">context</strong>. At a point when the user had waited patiently for their upload to process, the app responded with an unhelpful and unapologetic response. If I was a user on my way to a client presentation, or up against a deadline, this would be less than ideal. This has fortunately been fixed, but not before I received a justifiably angry email from a customer.</p><p name="49ee" id="49ee" class="graf--p">Of course there are also occasions when you <em class="markup--em markup--p-em">can</em> have fun, and where a bit of personality can add value to an otherwise boring user experience. Like on the <a target="_blank" href="https://signup.prevue.it/" data-href="https://signup.prevue.it/" class="markup--anchor markup--p-anchor" rel="nofollow">Prevue signup</a>, where submitting the form without entering any details will return this message:</p><figure name="b084" id="b084" class="graf--figure graf--last"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 237px;"><div class="aspect-ratio-fill" style="padding-bottom: 33.900000000000006%;"></div><img class="graf-image" data-image-id="1*rUpHwI14OIYuNt9dqUv2NQ.png" data-width="700" data-height="237" src="https://d262ilb51hltx0.cloudfront.net/max/1067/1*rUpHwI14OIYuNt9dqUv2NQ.png"></div><figcaption class="imageCaption">For me, this is preferable to putting an error state on every input</figcaption></figure></div></div></section><section name="c9bc"><div class="section-divider layoutSingleColumn"><hr class="section-divider"></div><div class="section-content"><div class="section-inner layoutSingleColumn"><p name="ac9d" id="ac9d" class="graf--p graf--first">The details are the last 1% of a product. They’re hard to define, they’re impossible to scope, and they’re absolutely no substitute to thorough research, great design and clever engineering. They can, however, be the difference between an <em class="markup--em markup--p-em">average </em>experience and a <em class="markup--em markup--p-em">great </em>one.</p><p name="2292" id="2292" class="graf--p">The details will help your product feel natural, fun, intuitive, and even make your users feel smart. It’s in the small things, that easy-to-forget 1%, where you’ll find the key to making people fall in love your product.</p><p name="20e3" id="20e3" class="graf--p">In the details —<em class="markup--em markup--p-em"> that’s</em> where you’ll find God.</p></p>
- </article>
- </section>
-
-
- <nav id="jumpto">
- <p>
- <a href="/david/blog/">Accueil du blog</a> |
- <a href="https://medium.com/@buzzusborne/god-is-in-the-details-bc3a9a9a5d88">Source originale</a> |
- <a href="/david/stream/2019/">Accueil du flux</a>
- </p>
- </nav>
-
- <footer>
- <div>
- <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
- <p>
- Bonjour/Hi!
- Je suis <a href="/david/" title="Profil public">David Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
- Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
- </p>
- <p>
- Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
- </p>
-
- <p>
- Voici quelques articles choisis :
- <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
- <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
- <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
- <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
- <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
- <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
- <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
- <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
- <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
- <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
- <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
- <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
- <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
- <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
- <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
- et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
- </p>
- <p>
- On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
- </p>
- <p>
- Je ne traque pas ta navigation mais mon
- <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
- conserve des logs d’accès.
- </p>
- </div>
- </footer>
- <script type="text/javascript">
- ;(_ => {
- const jumper = document.getElementById('jumper')
- jumper.addEventListener('click', e => {
- e.preventDefault()
- const anchor = e.target.getAttribute('href')
- const targetEl = document.getElementById(anchor.substring(1))
- targetEl.scrollIntoView({behavior: 'smooth'})
- })
- })()
- </script>
|