ux – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Thu, 09 Feb 2023 19:45:53 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 ux – CSS-Tricks https://css-tricks.com 32 32 45537868 Healthcare, Selling Lemons, and the Price of Developer Experience https://css-tricks.com/healthcare-selling-lemons-and-the-price-of-developer-experience/ https://css-tricks.com/healthcare-selling-lemons-and-the-price-of-developer-experience/#comments Thu, 09 Feb 2023 19:45:48 +0000 https://css-tricks.com/?p=377169 Every now and then, a one blog post is published and it spurs a reaction or response in others that are, in turn, published as blogs posts, and a theme starts to emerge. That’s what happened this past week and …


Healthcare, Selling Lemons, and the Price of Developer Experience originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Every now and then, a one blog post is published and it spurs a reaction or response in others that are, in turn, published as blogs posts, and a theme starts to emerge. That’s what happened this past week and the theme developed around the cost of JavaScript frameworks — a cost that, in this case, reveals just how darn important it is to use JavaScript responsibly.

Eric Bailey: Modern Health, frameworks, performance, and harm

This is where the story begins. Eric goes to a health service provider website to book an appointment and gets… a blank screen.

In addition to a terrifying amount of telemetry, Modern Health’s customer-facing experience is delivered using React and Webpack.

If you are familiar with how the web is built, what happened is pretty obvious: A website that over-relies on JavaScript to power its experience had its logic collide with one or more other errant pieces of logic that it summons. This created a deadlock.

If you do not make digital experiences for a living, what happened is not obvious at all. All you see is a tiny fake loading spinner that never stops.

D’oh. This might be mere nuisance — or even laughable — in some situations, but not when someone’s health is on the line:

A person seeking help in a time of crisis does not care about TypeScript, tree shaking, hot module replacement, A/B tests, burndown charts, NPS, OKRs, KPIs, or other startup jargon. Developer experience does not count for shit if the person using the thing they built can’t actually get what they need.

This is the big smack of reality. What happens when our tooling and reporting — the very things that are supposed to make our work more effective — get in the way of the user experience? These are tools that provide insights that can help us anticipate a user’s needs, especially in a time of need.

I realize that pointing the finger at JavaScript frameworks is already divisive. But this goes beyond whether you use React or framework d’jour. It’s about business priorities and developer experience conflicting with user experiences.

Alex Russell: The Market for Lemons

Partisans for slow, complex frameworks have successfully marketed lemons as the hot new thing, despite the pervasive failures in their wake, crowding out higher-quality options in the process.

These technologies were initially pitched on the back of “better user experiences”, but have utterly failed to deliver on that promise outside of the high-management-maturity organisations in which they were born. Transplanted into the wider web, these new stacks have proven to be expensive duds.

There’s the rub. Alex ain’t mincing words, but notice that the onus is on the way frameworks haved been marketed to developers than developers themselves. The sales pitch?

Once the lemon sellers embed the data-light idea that improved “Developer Experience” (“DX”) leads to better user outcomes, improving “DX” became and end unto itself, and many who knew better felt forced to play along. The long lead times in falsifying trickle-down UX was a feature, not a bug; they don’t need you to succeed, only to keep buying.

As marketing goes, the “DX” bait-and-switch is brilliant, but the tech isn’t delivering for anyone but developers.

Tough to stomach, right? No one wants to be duped, and it’s tough to admit a sunken cost when there is one. It gets downright personal if you’ve invested time in a specific piece of tech and effort integrating it into your stack. Development workflows are hard and settling into one is sorta like settling into a house you plan on living in a little while. But you’d want to know if your house was built on what Alex calls a “sandy foundation”.

I’d just like to pause here a moment to say I have no skin in this debate. As a web generalist, I tend to adopt new tools early for familiarity then drop them fast, relegating them to my toolshed until I find a good use for them. In other words, my knowledge is wide but not very deep in one area or thing. HTML, CSS, and JavaScript is my go-to cocktail, but I do care a great deal about user experience and know when to reach for a tool to solve a particular thing.

And let’s acknowledge that not everyone has a say in the matter. Many of us work on managed teams that are prescribed the tools we use. Alex says as much, which I think is important to call out because it’s clear this isn’t meant to be personal. It’s a statement on our priorities and making sure they along to user expectations.

Let’s alow Chris to steer us back to the story…

Chris Coyier: End-To-End Tests with Content Blockers?

So, maybe your app is built on React and it doesn’t matter why it’s that way. There’s still work to do to ensure the app is reliable and accessible.

Just blocking a file shouldn’t totally wreck a website, but it often does! In JavaScript, that may be because the developers have written first-party JavaScript (which I’ll generally allow) that depends on third-party JavaScript (which I’ll generally block).

[…]

If I block resources from tracking-website.com, now my first-party JavaScript is going to throw an error. JavaScript isn’t chill. If an error is thrown, it doesn’t execute more JavaScript further down in the file. If further down in that file is transitionToOnboarding();— that ain’t gonna work.

Maybe it’s worth revisiting your workflow and tweaking it to account to identify more points of failure.

So here’s an idea: Run your end-to-end tests in browsers that have popular content blockers with default configs installed. 

Doing so may uncover problems like this that stop your customers, and indeed people in need, from being stopped in their tracks.

Good idea! Hey, anything that helps paint a more realistic picture of how the app is used. That sort of clarity could happen a lot earlier in the process, perhaps before settling on development decisions. Know your users. Why are they using the app? How do they browse the web? Where are they phsically located? What problems could get in their way? Chris has a great talk on that, too.


Healthcare, Selling Lemons, and the Price of Developer Experience originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/healthcare-selling-lemons-and-the-price-of-developer-experience/feed/ 3 377169
Creating UI Components in SVG https://css-tricks.com/creating-ui-components-in-svg/ https://css-tricks.com/creating-ui-components-in-svg/#comments Mon, 23 Nov 2020 23:35:41 +0000 https://css-tricks.com/?p=325860 I’m thoroughly convinced that SVG unlocks a whole entire world of building interfaces on the web. It might seem daunting to learn SVG at first, but you have a spec that was designed to create shapes and yet, still has …


Creating UI Components in SVG originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’m thoroughly convinced that SVG unlocks a whole entire world of building interfaces on the web. It might seem daunting to learn SVG at first, but you have a spec that was designed to create shapes and yet, still has elements, like text, links, and aria labels available to you. You can accomplish some of the same effects in CSS, but it’s a little more particular to get positioning just right, especially across viewports and for responsive development.

What’s special about SVG is that all the positioning is based on a coordinate system, a little like the game Battleship. That means deciding where everything goes and how it’s drawn, as well as how it’s relative to each other, can be really straightforward to reason about. CSS positioning is for layout, which is great because you have things that correspond to one another in terms of the flow of the document. This otherwise positive trait is harder to work with if you’re making a component that’s very particular, with overlapping and precisely placed elements.

Truly, once you learn SVG, you can draw anything, and have it scale on any device. Even this very site uses SVG for custom UI elements, such as my avatar, above (meta!).

That little half circle below the author image is just SVG markup.

We won’t cover everything about SVGs in this post (you can learn some of those fundamentals here, here, here and here), but in order to illustrate the possibilities that SVG opens up for UI component development, let’s talk through one particular use case and break down how we would think about building something custom.

The timeline task list component

Recently, I was working on a project with my team at Netlify. We wanted to show the viewer which video in a series of videos in a course they were currently watching. In other words, we wanted to make some sort of thing that’s like a todo list, but shows overall progress as items are completed. (We made a free space-themed learning platform and it’s hella cool. Yes, I said hella.)

Here’s how that looks:

So how would we go about this? I’ll show an example in both Vue and React so that you can see how it might work in both frameworks.

The Vue version

We decided to make the platform in Next.js for dogfooding purposes (i.e. trying out our own Next on Netlify build plugin), but I’m more fluent in Vue so I wrote the initial prototype in Vue and ported it over to React.

Here is the full CodePen demo:

Let’s walk through this code a bit. First off, this is a single file component (SFC), so the template HTML, reactive script, and scoped styles are all encapsulated in this one file.

We’ll store some dummy tasks in data, including whether each task is completed or not. We’ll also make a method we can call on a click directive so that we can toggle whether the state is done or not.

<script>
export default {
  data() {
    return {
      tasks: [
        {
          name: 'thing',
          done: false
        },
        // ...
      ]
    };
  },
  methods: {
    selectThis(index) {
      this.tasks[index].done = !this.tasks[index].done
    }
  }
};
</script>

Now, what we want to do is create an SVG that has a flexible viewBox depending on the amount of elements. We also want to tell screen readers that this a presentational element and that we will provide a title with a unique id of timeline. (Get more information on creating accessible SVGs.)

<template>
  <div id="app">
    <div>
      <svg :viewBox="`0 0 30 ${tasks.length * 50}`"
           xmlns="http://www.w3.org/2000/svg" 
           width="30" 
           stroke="currentColor" 
           fill="white"
           aria-labelledby="timeline"
           role="presentation">
           <title id="timeline">timeline element</title>
        <!-- ... -->
      </svg>
    </div>
  </div>
</template>

The stroke is set to currentColor to allow for some flexibility — if we want to reuse the component in multiple places, it will inherit whatever color is used on the encapsulating div.

Next, inside the SVG, we want to create a vertical line that’s the length of the task list. Lines are fairly straightforward. We have x1 and x2 values (where the line is plotted on the x-axis), and similarly, y1 and y2.

<line x1="10" x2="10" :y1="num2" :y2="tasks.length * num1 - num2" />

The x-axis stays consistently at 10 because we’re drawing a line downward rather than left-to-right. We’ll store two numbers in data: the amount we want our spacing to be, which will be num1, and the amount we want our margin to be, which will be num2.

data() {
  return {
    num1: 32,
    num2: 15,
    // ...
  }
}

The y-axis starts with num2, which is subtracted from the end, as well as the margin. The tasks.length is multiplied by the spacing, which is num1.

Now, we’ll need the circles that lie on the line. Each circle is an indicator for whether a task has been completed or not. We’ll need one circle for each task, so we’ll use v-for with a unique key, which is the index (and is safe to use here as they will never reorder). We’ll connect the click directive with our method and pass in the index as a param as well.

CIrcles in SVG are made up of three attributes. The middle of the circle is plotted at cx and cy, and then we draw a radius with r. Like the line, cx starts at 10. The radius is 4 because that’s what’s readable at this scale. cy will be spaced like the line: index times the spacing (num1), plus the margin (num2).

Finally, we’ll put use a ternary to set the fill. If the task is done, it will be filled with currentColor. If not, it will be filled with white (or whatever the background is). This could be filled with a prop that gets passed in the background, for instance, where you have light and dark circles.

<circle 
  @click="selectThis(i)" 
  v-for="(task, i) in tasks"
  :key="task.name"
  cx="10"
  r="4"
  :cy="i * num1 + num2"
  :fill="task.done ? 'currentColor' : 'white'"
  class="select"/>

Finally, we are using CSS grid to align a div with the names of tasks. This is laid out much in the same way, where we’re looping through the tasks, and are also tied to that same click event to toggle the done state.

<template>
  <div>
    <div 
      @click="selectThis(i)"
      v-for="(task, i) in tasks"
      :key="task.name"
      class="select">
      {{ task.name }}
    </div>
  </div>
</template>

The React version

Here is where we ended up with the React version. We’re working towards open sourcing this so that you can see the full code and its history. Here are a few modifications:

  • We’re using CSS modules rather than the SCFs in Vue
  • We’re importing the Next.js link, so that rather than toggling a “done” state, we’re taking a user to a dynamic page in Next.js
  • The tasks we’re using are actually stages of the course —or “Mission” as we call them — which are passed in here rather than held by the component.

Most of the other functionality is the same :)

import styles from './MissionTracker.module.css';
import React, { useState } from 'react';
import Link from 'next/link';

function MissionTracker({ currentMission, currentStage, stages }) {
 const [tasks, setTasks] = useState([...stages]);
 const num1 = 32;
 const num2 = 15;

 const updateDoneTasks = (index) => () => {
   let tasksCopy = [...tasks];
   tasksCopy[index].done = !tasksCopy[index].done;
   setTasks(tasksCopy);
 };

 const taskTextStyles = (task) => {
   const baseStyles = `${styles['tracker-select']} ${styles['task-label']}`;

   if (currentStage === task.slug.current) {
     return baseStyles + ` ${styles['is-current-task']}`;
   } else {
     return baseStyles;
   }
 };

 return (
   <div className={styles.container}>
     <section>
       {tasks.map((task, index) => (
         <div
           key={`mt-${task.slug}-${index}`}
           className={taskTextStyles(task)}
         >
           <Link href={`/learn/${currentMission}/${task.slug.current}`}>
             {task.title}
           </Link>
         </div>
       ))}
     </section>

     <section>
       <svg
         viewBox={`0 0 30 ${tasks.length * 50}`}
         className={styles['tracker-svg']}
         xmlns="http://www.w3.org/2000/svg"
         width="30"
         stroke="currentColor"
         fill="white"
         aria-labelledby="timeline"
         role="presentation"
       >
         <title id="timeline">timeline element</title>

         <line x1="10" x2="10" y1={num2} y2={tasks.length * num1 - num2} />
         {tasks.map((task, index) => (
           <circle
             key={`mt-circle-${task.name}-${index}`}
             onClick={updateDoneTasks(index)}
             cx="10"
             r="4"
             cy={index * +num1 + +num2}
             fill={
               task.slug.current === currentStage ? 'currentColor' : 'black'
             }
             className={styles['tracker-select']}
           />
         ))}
       </svg>
     </section>
   </div>
 );
}

export default MissionTracker;

Final version

You can see the final working version here:

This component is flexible enough to accommodate lists small and large, multiple browsers, and responsive sizing. It also allows the user to have better understanding of where they are in their progress in the course.

But this is just one component. You can make any number of UI elements: knobs, controls, progress indicators, loaders… the sky’s the limit. You can style them with CSS, or inline styles, you can have them update based on props, on context, on reactive data, the sky’s the limit! I hope this opens some doors on how you yourself can develop more engaging UI elements for the web.


Creating UI Components in SVG originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/creating-ui-components-in-svg/feed/ 13 325860
That’s Just How I Scroll https://css-tricks.com/thats-just-how-i-scroll/ https://css-tricks.com/thats-just-how-i-scroll/#comments Fri, 14 Aug 2020 20:00:33 +0000 https://css-tricks.com/?p=318581 How do you know a page (or any element on that page) scrolls? Well, if it has a scrollbar, that’s a pretty good indication. You might still have to scrapple with your client about “the fold” or whatever, but I …


That’s Just How I Scroll originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
How do you know a page (or any element on that page) scrolls? Well, if it has a scrollbar, that’s a pretty good indication. You might still have to scrapple with your client about “the fold” or whatever, but I don’t think anyone is confused at what a scrollbar is or what it indicates.

But let’s say there is no scrollbar. That’s super common. macOS hides scrollbars by default and only shows them during scroll. Most mobile browsers don’t have scrollbars, even if you attempt to force them with something like overflow: scroll;.

Why does this matter? If you don’t know an area is scrollable, you might miss out on important content or functionality.

I regularly think about the Perfectly Cropped story from Tyler Hall. There is a screen on iOS that has important functionality you need to scroll down to, but there is no indicator whatsoever that you can scroll there.

The result of that was Tyler’s mom literally not being able to find functionality she was used to. Not great.

There is an elaborate way to detect visible scrollbars and force them to be visible, but something about that rubs me the wrong way. It doesn’t honor a user’s preference (assuming it is the user’s preference), requires DOM manipulation tests, and uses vendor-prefixed CSS (which will probably live a long time, but has been standardized now, so maybe not forever).

I enjoy these approaches and by Chris Smith and his thinking:

My favorite are the shadow-based techniques. To me an inset shadow is a really clear indicator, as it makes it appear that content is flowing underneath and the shadow follows an edge that as a hint that you can scroll in that direction. Plus, you’ve got CSS control there so I’d think it could match whatever UI situation you’re in fairly easily.

It should be known though that it can be done entirely in CSS though, no JavaScript, and is one of the great CSS tricks.


That’s Just How I Scroll originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/thats-just-how-i-scroll/feed/ 7 318581
In Defense of a Fussy Website https://css-tricks.com/in-defense-of-a-fussy-website/ https://css-tricks.com/in-defense-of-a-fussy-website/#comments Fri, 26 Jun 2020 19:12:01 +0000 https://css-tricks.com/?p=314496 The other day I was doom-scrolling twitter, and I saw a delightful article titled “The Case for Fussy Breakfasts.” I love food and especially breakfast, and since the pandemic hit I’ve been using my breaks in between meetings …


In Defense of a Fussy Website originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The other day I was doom-scrolling twitter, and I saw a delightful article titled “The Case for Fussy Breakfasts.” I love food and especially breakfast, and since the pandemic hit I’ve been using my breaks in between meetings (or sometimes on meetings, shh) to make a full bacon, poached egg, vegetable plate, so I really got into the article. This small joy of creating a bit of space for myself for the most important meal of the day has been meaningful to me — while everything else feels out of control, indulging in some ceremony has done a tiny part to offset the intensity of our collective situation.

It caused me to think of this “fussiness” as applied to other inconsequential joys. A walk. A bath. What about programming?

While we’re all laser-focused on shipping the newest feature with the hottest software and the best Lighthouse scores, I’ve been missing a bit of the joy on the web. Apps are currently conveying little care for UX, guidance, richness, and — well, for humans trying to communicate through a computer, we’re certainly bending a lot to… the computer.

I’m getting a little tired of the web being seen as a mere document reader, and though I do love me a healthy lighthouse score, some of these point matrixes seem to live and die more by our developer ego in this gamification than actually considering what we can do without incurring much weight. SVGs can be very small while still being impactful. Some effects are tiny bits of CSS. JS animations can be lazy-loaded. You can even dazzle with words, color, and layout if you’re willing to be a bit adventurous, no weight at all!

A few of my favorite developer sites lately have been Josh Comeau, Johnson Ogwuru and Cassie Evans. The small delights and touches, the little a-ha moments, make me STAY. I wander around the site, exploring, learning, feeling actually more connected to each of these humans rather than as if I’m glancing at a PDF of their resume. They flex their muscles, show me the pride they have in building things, and it intrigues me! These small bits are more than the fluff that many portray any “excess” as: they do the job that the web is intending. We are communicating using this tool- the computer- as an extension of ourselves.

Nuance can be challenging. It’s easy as programmers to get stuck in absolutes, and one of these of late has been that if you’re having any bit of fun, any bit of style, that must mean it’s “not useful.” Honestly, I’d make the case that the opposite is true. Emotions attach to the limbic system, making memories easier to recall. If your site is a flat bit of text, how will anyone remember it?

Don’t you want to build the site that teams in companies the world over remember and cite as an inspiration? I’ve been at four different companies where people have mentioned Stripe as a site they would aspire to be like. Stripe took chances. Stripe told stories. Stripe engaged the imagination of developers, spoke directly to us.

I’m sad acknowledging the irony that after thinking about how spot on Stripe was, most of those companies ignored much of what they learned while exploring it. Any creativity, risk, and intention was slowly, piece by piece, chipped away by the drumbeat of “usefulness,” missing the forest for the trees.

When a site is done with care and excitement you can tell. You feel it as you visit, the hum of intention. The craft, the cohesiveness, the attention to detail is obvious. And in turn, you meet them halfway. These are the sites with the low bounce rates, the best engagement metrics, the ones where they get questions like “can I contribute?” No gimmicks needed.

What if you don’t have the time? Of course, we all have to get things over the line. Perhaps a challenge: what small thing can you incorporate that someone might notice? Can you start with a single detail? I didn’t start with a poached egg in my breakfast, one day I made a goofy scrambled one. It went on from there. Can you challenge yourself to learn one small new technique? Can you outsource one graphic? Can you introduce a tiny easter egg? Say something just a little differently from the typical corporate lingo?

If something is meaningful to you, the audience you’ll gather will likely be the folks that find it meaningful, too.


In Defense of a Fussy Website originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/in-defense-of-a-fussy-website/feed/ 12 314496
What is Developer Experience (DX)? https://css-tricks.com/what-is-developer-experience-dx/ https://css-tricks.com/what-is-developer-experience-dx/#comments Mon, 15 Jun 2020 23:31:36 +0000 https://css-tricks.com/?p=311245 Developer Experience¹ is a term² with a self-declaring meaning — the experience of developers — but it eludes definition in the sense that people invoke it at different times for different reasons referring to different things. For instance, …


What is Developer Experience (DX)? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Developer Experience¹ is a term² with a self-declaring meaning — the experience of developers — but it eludes definition in the sense that people invoke it at different times for different reasons referring to different things. For instance, our own Sarah Drasner’s current job title is “VP of Developer Experience” at Netlify, so it’s a very real thing. But a job title is just one way the term is used. Let’s dig in a bit and apply it to the different ways people think about and use the term.

People think of specific companies.

I hear DX and Stripe together a lot. That makes sense. Stripe is a payment gateway company almost exclusively for developers. They are serious about providing a good experience for their customers (developers), hence “developer experience.” Just listen to Suz Hinton talk about “friction journals”, which is the idea of sitting down to use a product (like Stripe) and noting down every single little WTF moment, confusion, and frustration so that improvements can be made:

Netlify is like Stripe in this way, as is Heroku, CodePen, and any number of companies where the entire customer base is developers. For companies like this, it’s almost like DX is what UX (User Experience) is for any other company.

People think of specific technologies.

It’s common to hear DX invoked when comparing technologies. For instance, some people will say that Vue offers a better developer experience than React. (I’m not trying to start anything, I don’t even have much of an opinion on this.) They are talking about things like APIs. Perhaps the state is more intuitive to manage in one vs. the other. Or they are talking about features. I know Vue and Svelte have animation helpers built-in while React does not. But React has hooks and people generally like those. These are aspects of the DX of these technologies.

Or they might be speaking about the feeling around the tools surrounding the core technology. I know create-react-app is widely beloved, but so is the Vue CLI. React Router is hugely popular, but Vue has a router that is blessed (and maintained) by the core team which offers a certain feeling of trust.

> vue create hello-world
> npx create-react-app my-app

I’m not using JavaScript frameworks/libraries as just any random example. I hear people talk about DX as it relates to JavaScript more than anything else — which could be due to the people in my circles, but it feels notable.

People think of the world around the technology.

Everybody thinks good docs are important. There is no such thing as a technology that is better than another but has much worse docs. The one with the better docs is better overall because it has better docs. That’s not the technology itself; that’s the world around it.

Have you ever seen a developer product with an API, and when you view the docs for the API while logged in, it uses API keys and data and settings from your own account to demonstrate? That’s extraordinary to me. That feels like DX to me.

Airtable docs showing me API usage with my own data.

“Make the right thing easy,” notes Jake Dohm.

That word, easy, feels highly related to DX. Technologies that make things easy are technologies with good DX. In usage as well as in understanding. How easily (and quickly) can I understand what your technology does and what I can do with it?

What the technology does is often only half of the story. The happy path might be great, but what happens when it breaks or errors? How is the error reporting and logging? I think of Apollo and GraphQL here in my own experience. It’s such a great technology, but the error reporting feels horrendous in that it’s very difficult to track down even stuff like typos triggering errors in development.

What is the debugging story like? Are there special tools for it? The same goes for testing. These things are fundamental DX issues.

People think of technology offerings.

For instance, a technology might be “good” already. Say it has an API that developers like. Then it starts offering a CLI. That’s (generally) a DX improvement, because it opens up doors for developers who prefer working in that world and who build processes around it.

I think of things like Netlify Dev here. They already have this great platform and then say, here, you can run it all on your own machine too. That’s taking DX seriously.

One aspect of Netlify Dev that is nice: The terminal command to start my local dev environment across all my sites on Netlify, regardless of what technology powers them, is the same: netlify dev

Having a dedicated CLI is almost always a good DX step, assuming it is well done and maintained. I remember WordPress before WP-CLI, and now lots of documentation just assumes you’re using it. I wasn’t even aware Cloudinary had a CLI until the other day when I needed it and was pleasantly surprised that it was there. I remember when npm scripts started taking over the world. (What would npm be without a CLI?) We used to have a variety of different task runners, but now it’s largely assumed a project has run commands built into the package.json that you use to do anything the project needs to do.

Melanie Sumner thinks of CLIs immediately as core DX.

People think of the literal experience of coding.

There is nothing more directly DX than the experience of typing code into code editing software and running it. That’s what “coding” is and that’s what developers do. It’s no wonder that developers take that experience seriously and are constantly trying to improve it for themselves and their teams. I think of things like VS Code in how it’s essentially the DX of it that has made it so dominant in the code editing space in such a short time. VS Code does all kinds of things that developers like, does them well, does them fast, and allows for a very wide degree of customization.

TypeScript keeps growing in popularity no doubt in part due to the experience it offers within VS Code. TypeScript literally helps you code better by showing you, for example, what functions need as parameters, and making it hard to do the wrong thing.

Then there is the experience outside the editor, which in the browser itself. Years ago, I wrote Style Injection is for Winners where my point was, as a CSS developer, the experience of saving CSS code and seeing the changes instantly in the browser is a DX you definitely want to have. That concept continues to live on, growing up to JavaScript as well, where “hot reloading” is goosebump-worthy.

The difference between a poor developer environment (no IDE help, slow saves, manual refreshes, slow pipelines) and a great developer environment (fancy editor assistance, hot reloading, fast everything) is startling. A good developer environment, good DX, makes you a better and more productive programmer.

People compare it to user experience (UX).

There is a strong negative connotation to DX sometimes. It happens when people blame it for it existing at the cost of user experience.

I think of things like client-side developer-only libraries. Think of the classic library that everyone loves to dunk: Moment.js. Moment allows you to manipulate dates in JavaScript, and is often used client-side to do that. Users don’t care if you have a fancy API available to manipulate dates. That is entirely a developer convenience. So, you ship this library for yourself (good DX) at the cost of slowing down the website (bad UX). Most client-side JavaScript is in this category.

Equally as often, people connect developer experience and user experience. If developers are empowered and effective, that will “trickle down” to produce good software, the theory goes.

Worst case, we’re in a situation where UX and DX are on a teeter totter. Pile on some DX and UX suffers on the other side. Best case, we find ways to disentangle DX and UX entirely, finding value in both and taking both seriously. Although if one has to win, certainly it should be the users. Like the HTML spec says:

In case of conflict, consider users over authors over implementors over specifiers over theoretical purity.

People think about time.

How long does a technology take to adopt? Good DX considers this. Can I take advantage of it without rewriting everything? How quickly can I spin it up? How well does it play with other technologies I use? What is my time investment?

This kind of thing makes me think of some recent experience with Cloudflare Workers. It’s really cool technology that we don’t have time to get all into right here, but suffice to say it gives you control over a website at a high level that we often don’t think about. Like what if you could manipulate a network request before it even gets to your web server? You don’t have to use it, but because of the level it operates on, new doors open up without caring about or interfering with whatever technologies you are using.

Not only does the technology itself position itself well, the DX of using it, while there are some rough edges, is at least well-considered, providing a browser-based testing environment.

A powerful tool with a high investment cost, eh, that’s cool. But a powerful tool with low investment cost is good DX.

People don’t want to think about it.

They say the best typography goes unnoticed because all you see is the what the words are telling you, not the typography itself. That can be true of developer experience. The best DX is that you never notice the tools or the technology because they just work.

Good DX is just being able to do your job rather than fight with tools. The tools could be your developer environment, it could be build tooling, it could be hosting stuff, or it could even be whatever APIs you are interfacing with. Is the API intuitive and helpful, or obtuse and tricky?


Feel free to keep going on this in the comments. What is DX to you?

  1. Are we capitalizing Developer Experience? I’m just gonna go for it.
  2. Looks like Michael Mahemoff has a decent claim on coining the term.

What is Developer Experience (DX)? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/what-is-developer-experience-dx/feed/ 8 311245
Block Links: The Search for a Perfect Solution https://css-tricks.com/block-links-the-search-for-a-perfect-solution/ https://css-tricks.com/block-links-the-search-for-a-perfect-solution/#comments Mon, 25 May 2020 19:58:40 +0000 https://css-tricks.com/?p=309808 I was reading this article by Chris where he talks about block links — you know, like wrapping an entire card element inside an anchor — being a bad idea. It’s bad accessibility because of how it affects screen readers. …


Block Links: The Search for a Perfect Solution originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I was reading this article by Chris where he talks about block links — you know, like wrapping an entire card element inside an anchor — being a bad idea. It’s bad accessibility because of how it affects screen readers. And it’s bad UX because it prevents simple user tasks, like selecting text.

But maybe there’s something else at play. Maybe it’s less an issue with the pattern than the implementation of it. That led me to believe that this is the time to write follow-up article to see if we can address some of the problems Chris pointed out.

Throughout this post, I’ll use the term “card” to describe a component using the block link pattern. Here’s what we mean by that.

Let’s see how we want our Card Components to work:

  1. The whole thing should be linked and clickable.
  2. It should be able to contain more than one link.
  3. Content should be semantic so assistive tech can understand it.
  4. The text should be selectable, like regular links.
  5. Things like right-click and keyboard shortcuts should work with it
  6. Its elements should be focusable when tabbing.

That’s a long list! And since we don’t have any standard card widget provided by the browser, we don’t have any standard guidelines to build it. 

Like most things on the web, there’s more than one way to make a card component. However, I haven’t found something that checks all the requirements we just covered. In this article, we will try to hit all of them. That’s what we’re going to do now!

Method 1: Wrap everything an <a>

This is the most common and the easiest way to make a linked card. Take the HTML for the card and wrap the entire thing in an anchor tag.

<a href="/">
  <!-- Card markup -->
</a>

Here’s what that gives us:

  1. It’s clickable.
  2. It works with right-click and keyboard shortcuts.

Well, not great. We still can’t:

  1. Put another link inside the card because the entire thing is a single link
  2. Use it with a screen reader — the content is not semantic, so assistive technology will announce everything inside the card, starting from the time stamp
  3. Select text

That’s enough 👎 that we probably shouldn’t use it. Let’s move onto the next technique.

This is a nice compromise that sacrifices a little UX for improved accessibility.

With this pattern we achieve most of our goals:

  1. We can put as many links as we want. 
  2. Content is semantic.
  3. We can select the text from Card.
  4. Right Click and keyboard shortcuts work.
  5. The focus is in proper order when tabbing.

But it is missing the main feature we want in a card: the whole thing should be clickable! Looks like we need to try some other way.

Method 3: The good ol’ ::before pseudo element

In this one, we add a ::before or ::after element, place it above the card with absolute positioning and stretch it over the entire width and height of the card so it’s clickable.

But now:

  1. We still can’t add more than one link because anything else that’s linked is under the pseudo element layer. We can try to put all the text above the pseudo element, but card link itself won’t work when clicking on top of the text.
  2. We still can’t select the text. Again, we could swap layers, but then we’re back to the clickable link issue all over again.

Let’s try to actually check all the boxes here in our final technique.

Method 4: Sprinkle JavaScript on the second method

Let’s build off the second method. Recall that’s what where we link up everything we want to be a link:

<article class="card">
  <time datetime="2020-03-20">Mar 20, 2020</time>
  <h2><a href="https://css-tricks.com/a-complete-guide-to-calc-in-css/" class="main-link">A Complete Guide to calc() in CSS</a></h2>
  <p>
    In this guide, let’s cover just about everything there is to know about this very useful function.
  </p>
  <a class="author-name" href="https://css-tricks.com/author/chriscoyier/" target="_blank">Chris Coyier</a>
    <div class="tags">
      <a class="tag" href="https://css-tricks.com/tag/calc/" >calc</a>
    </div>
</article>

So how do we make the whole card clickable? We could use JavaScript as a progressive enhancement to do that. We’ll start by adding a click event listener to the card and trigger the click on the main link when it is triggered.

const card = document.querySelector(".card")
const mainLink = document.querySelector('.main-link')


card.addEventListener("click", handleClick)


function handleClick(event) {
  mainLink.click();
}

Temporarily, this introduces the problem that we can’t select the text, which we’ve been trying to fix this whole time. Here’s the trick: we’ll use the relatively less-known web API window.getSelection. From MDN:

The Window.getSelection() method returns a Selection object representing the range of text selected by the user or the current position of the caret.

Although, this method returns an Object, we can convert it to a string with toString().

const isTextSelected = window.getSelection().toString()

With one line and no complicated kung-fu tricks with event listeners, we know if the user has selected text. Let’s use that in our handleClick function.

const card = document.querySelector(".card")
const mainLink = document.querySelector('.main-link')


card.addEventListener("click", handleClick)


function handleClick(event) {
  const isTextSelected = window.getSelection().toString();
  if (!isTextSelected) {
    mainLink.click();
  }
}

This way, the main link can be clicked when no text selected, and all it took was a few lines of JavaScript. This satisfies our requirements:

  1. The whole thing is linked and clickable.
  2. It is able to contain more than one link.
  3. This content is semantic so assistive tech can understand it.
  4. The text should be selectable, like regular links.
  5. Things like right-click and keyboard shortcuts should work with it
  6. Its elements should be focusable when tabbing.

We have satisfied all the requirements but there are still some gotchas, like double event triggering on clickable elements like links and buttons in the card. We can fix this by adding a click event listener on all of them and stopping the propagation of event.

// You might want to add common class like 'clickable' on all elements and use that for the query selector.
const clickableElements = Array.from(card.querySelectorAll("a"));
clickableElements.forEach((ele) =>
  ele.addEventListener("click", (e) => e.stopPropagation())
);

Here’s the final demo with all the JavaScript code we have added:

I think we’ve done it! Now you know how to make a perfect clickable card component.

What about other patterns? For example, what if the card contains the excerpt of a blog post followed by a “Read More’ link? Where should that go? Does that become the “main” link? What about image?

For those questions and more, here’s some further reading on the topic:


Block Links: The Search for a Perfect Solution originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/block-links-the-search-for-a-perfect-solution/feed/ 40 309808
Radio Buttons Are Like Selects; Checkboxes Are Like Multiple Selects https://css-tricks.com/radio-buttons-are-like-selects-checkboxes-are-like-multiple-selects/ https://css-tricks.com/radio-buttons-are-like-selects-checkboxes-are-like-multiple-selects/#comments Wed, 20 May 2020 14:41:01 +0000 https://css-tricks.com/?p=311116 I was reading Anna Kaley’s “Listboxes vs. Dropdown Lists” post the other day. It’s a fairly straightforward comparison between different UI implementations of selecting options. There is lots of good advice there. Classics like that you should use radio buttons …


Radio Buttons Are Like Selects; Checkboxes Are Like Multiple Selects originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I was reading Anna Kaley’s “Listboxes vs. Dropdown Lists” post the other day. It’s a fairly straightforward comparison between different UI implementations of selecting options. There is lots of good advice there. Classics like that you should use radio buttons (single select) or checkboxes (multiple select) if you’re showing five or fewer options, and the different options when the number of options grows from there.

One thing that isn’t talked about is how you implement these things. I imagine that’s somewhat on purpose as the point is to talk UX, not tech. But how you implement them plays a huge part in UX. In web design and development circles, the conversation about these things usually involves whether you can pull these things off with native controls, or if you need to rebuild them from scratch. If you can use native controls, you often should, because there are tons of UX that you get for free that that might otherwise be lost or forgotten when you rebuild — like how everything works via the keyboard.

The reason people chose “rebuild” is often for styling reasons, but that’s changing slowly over time. We’ve got lots of control over radios and checkboxes now. We can style the outside of selects pretty well and even the inside with trickery.

But even without custom styling, we still have some UI options. If you need to select one option from many, we’ve got <input type="radio"> buttons, but data and end-result-wise, that’s the same as a <select>. If you need to select multiple options, we’ve got <input type="checkbox">, but that’s data and end-result-wise the same as <select multiple>.

You pick based on the room you have available and the UX of whatever you’re building.


Radio Buttons Are Like Selects; Checkboxes Are Like Multiple Selects originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/radio-buttons-are-like-selects-checkboxes-are-like-multiple-selects/feed/ 6 311116
Better Form Inputs for Better Mobile User Experiences https://css-tricks.com/better-form-inputs-for-better-mobile-user-experiences/ https://css-tricks.com/better-form-inputs-for-better-mobile-user-experiences/#comments Fri, 17 Apr 2020 15:08:17 +0000 https://css-tricks.com/?p=306387 Here’s one simple, practical way to make apps perform better on mobile devices: always configure HTML input fields with the correct type, inputmode, and autocomplete attributes. While these three attributes are often discussed in isolation, they make the …


Better Form Inputs for Better Mobile User Experiences originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Here’s one simple, practical way to make apps perform better on mobile devices: always configure HTML input fields with the correct type, inputmode, and autocomplete attributes. While these three attributes are often discussed in isolation, they make the most sense in the context of mobile user experience when you think of them as a team. 

There’s no question that forms on mobile devices can be time-consuming and tedious to fill in, but by properly configuring inputs, we can ensure that the data entry process is as seamless as possible for our users. Let’s take a look at some examples and best practices we can use to create better user experiences on mobile devices.

Use this demo to experiment on your own, if you’d like.

Using the correct input type

This is the easiest thing to get right. Input types, like email, tel, and url, are well-supported across browsers. While the benefit of using a type, like tel over the more generic text, might be hard to see on desktop browsers, it’s immediately apparent on mobile.

Choosing the appropriate type changes the keyboard that pops up on Android and iOS devices when a user focuses the field. For very little effort, just by using the right type, we will show custom keyboards for email, telephone numbers, URLs, and even search inputs

Text input type on iOS (left) and Android (right)
Email input type on iOS (left) and Android (right)
URL input type on iOS (left) and Android (right)
Search input type on iOS (left) and Android (right)

One thing to note is that both input type="email" and input type="url" come with validation functionality, and modern browsers will show an error tooltip if their values do not match the expected formats when the user submits the form. If you’d rather turn this functionality off, you can simply add the novalidate attribute to the containing form.

A quick detour into date types

HTML inputs comprise far more than specialized text inputs — you also have radio buttons, checkboxes, and so on. For the purposes of this discussion, though, I’m mostly talking about the more text-based inputs

There is a type of input that sits in the liminal space between the more free-form text inputs and input widgets like radio buttons: date. The date input type comes in a variety of flavors that are well-supported on mobile, including date, time, datetime-local, and month. These pop up custom widgets in iOS and Android when they are focused. Instead of triggering a specialized keyboard, they show a select-like interface in iOS, and various different types of widgets on Android (where the date and time selectors are particularly slick). 

I was excited to start using native defaults on mobile, until I looked around and realized that most major apps and mobile websites use custom date pickers rather than native date input types. There could be a couple reasons for this. First, I find the native iOS date selector to be less intuitive than a calendar-type widget. Second, even the beautifully-designed Android implementation is fairly limited compared to custom components — there’s no easy way to input a date range rather than a single date, for instance. 

Still, the date input types are worth checking out if the custom datepicker you’re using doesn’t perform well on mobile. If you’d like to try out the native input widgets on iOS and Android while making sure that desktop users see a custom widget instead of the default dropdown, this snippet of CSS will hide the calendar dropdown for desktop browsers that implement it:

::-webkit-calendar-picker-indicator {
  display: none;
}
Date input type on iOS (left) and Android (right)
Time input type on iOS (left) and Android (right)

One final thing to note is that date types cannot be overridden by the inputmode attribute, which we’ll discuss next.

Why should I care about inputmode?

The inputmode attribute allows you to override the mobile keyboard specified by the input’s type and directly declare the type of keyboard shown to the user. When I first learned about this attribute, I wasn’t impressed — why not just use the correct type in the first place? But while inputmode is often unnecessary, there are a few places where the attribute can be extremely helpful. The most notable use case that I’ve found for inputmode is building a better number input.

While some HTML5 input types, like url and email, are straightforward, input type="number" is a different matter. It has some accessibility concerns as well as a somewhat awkward UI. For example, desktop browsers, like Chrome, show tiny increment arrows that are easy to trigger accidentally by scrolling.

So here’s a pattern to memorize and use going forwards. For most numeric inputs, instead of using this: 

<input type="number" />

…you actually want to use this:

<input type="text" inputmode="decimal" />

Why not inputmode="numeric" instead of inputmode="decimal"

The numeric and decimal attribute values produce identical keyboards on Android. On iOS, however, numeric displays a keyboard that shows both numbers and punctuation, while decimal shows a focused grid of numbers that almost looks exactly like the tel input type, only without extraneous telephone-number focused options. That’s why it’s my preference for most types of number inputs.

iOS numeric input (left) and decimal input (right)
Android numeric input (left) and decimal input (right)

Christian Oliff has written an excellent article dedicated solely to the inputmode attribute.

Don’t forget autocomplete

Even more important than showing the correct mobile keyboard is showing helpful autocomplete suggestions. That can go a long way towards creating a faster and less frustrating user experience on mobile.

While browsers have heuristics for showing autocomplete fields, you cannot rely on them, and should still be sure to add the correct autocomplete attribute. For instance, in iOS Safari, I found that an input type="tel" would only show autocomplete options if I explicitly added a autocomplete="tel" attribute.

You may think that you are familiar with the basic autocomplete options, such as those that help the user fill in credit card numbers or address form fields, but I’d urge you to review them to make sure that you are aware of all of the options. The spec lists over 50 values! Did you know that autocomplete="one-time-code" can make a phone verification user flow super smooth?

Speaking of autocomplete…

I’d like to mention one final element that allows you to create your own custom autocomplete functionality: datalist. While it creates a serviceable — if somewhat basic — autocomplete experience on desktop Chrome and Safari, it shines on iOS by surfacing suggestions in a convenient row right above the keyboard, where the system autocomplete functionality usually lives. Further, it allows the user to toggle between text and select-style inputs.

On Android, on the other hand, datalist creates a more typical autocomplete dropdown, with the area above the keyboard reserved for the system’s own typeahead functionality. One possible advantage to this style is that the dropdown list is easily scrollable, creating immediate access to all possible options as soon as the field is focused. (In iOS, in order to view more than the top three matches, the user would have to trigger the select picker by pressing the down arrow icon.)

You can use this demo to play around with datalist:

And you can explore all the autocomplete options, as well as input type and inputmode values, using this tool I made to help you quickly preview various input configurations on mobile.

In summary

When I’m building a form, I’m often tempted to focus on perfecting the desktop experience while treating the mobile web as an afterthought. But while it does take a little extra work to ensure forms work well on mobile, it doesn’t have to be too difficult. Hopefully, this article has shown that with a few easy steps, you can make forms much more convenient for your users on mobile devices.


Better Form Inputs for Better Mobile User Experiences originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/better-form-inputs-for-better-mobile-user-experiences/feed/ 6 306387
“resize: none;” on textareas is bad UX https://css-tricks.com/resize-none-on-textareas-is-bad-ux/ https://css-tricks.com/resize-none-on-textareas-is-bad-ux/#comments Thu, 30 Jan 2020 20:20:07 +0000 https://css-tricks.com/?p=302594 Catalin Rosu:

Sometimes you need to type a long reply that consists of many paragraphs and wrapping that text within a tiny textarea box makes it hard to understand and to follow as you type. There were many times


“resize: none;” on textareas is bad UX originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Catalin Rosu:

Sometimes you need to type a long reply that consists of many paragraphs and wrapping that text within a tiny textarea box makes it hard to understand and to follow as you type. There were many times when I had to write that text within Notepad++ for example and then just paste the whole reply in that small textarea. I admit I also opened the DevTools to override the resize: none declaration but that’s not really a productive way to do things.

Removing the default resizeability of a <textarea> is generally user-hurting vanity. Even if the resized textarea “breaks” the site layout, too bad, the user is trying to do something very important on this site right now and you should not let anything get in the way of that. I know the web is a big place though, so feel free to prove me wrong in the comments.

This must have been cathartic for Catalin, who has been steadily gaining a reputation on Stack Overflow for an answer on how to prevent a textarea from resizing from almost a decade ago.

To Shared LinkPermalink on CSS-Tricks


“resize: none;” on textareas is bad UX originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/resize-none-on-textareas-is-bad-ux/feed/ 4 302594
UX Considerations for Web Sharing https://css-tricks.com/ux-considerations-for-web-sharing/ Fri, 20 Sep 2019 14:17:47 +0000 https://css-tricks.com/?p=295666 From trashy clickbait sites to the most august of publications, share buttons have long been ubiquitous across the web. And yet it is arguable that these buttons aren’t needed. All mobile browsers — Firefox, Edge, Safari, Chrome, Opera Mini, UC …


UX Considerations for Web Sharing originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
From trashy clickbait sites to the most august of publications, share buttons have long been ubiquitous across the web. And yet it is arguable that these buttons aren’t needed. All mobile browsers — Firefox, Edge, Safari, Chrome, Opera Mini, UC Browser, Samsung Internet — make it easy to share content directly from their native platforms. They all feature a built-in button to bring up a “share sheet” — a native dialog for sharing content. You can also highlight text to share an excerpt along with the link.

A collage of various share buttons from sites across the web.
The ubiquitous share button, as seen at the BBC, Wired, BuzzFeed, PBS, The Wall Street Journal and elsewhere.

Given that users can share by default, are custom buttons taking up unnecessary space and potentially distracting users from more important actions? And do people actually use them?

A (unscientific) poll of 12,500 CSS-Tricks readers found that 60% of its readers never used custom share buttons. That was in 2014 and native methods for sharing have only improved since then. A more recent poll from Smashing Magazine found much the same thing.

Users come with varying technological proficiency. Not everybody knows their way around there own mobile phone or browser meaning some users would struggle to find the native share button. It’s also worth thinking about what happens on desktop. Desktop browsers generally (with Safari as one exception) offer no built-in sharing functionality — users are left to copy and paste the link into their social network of choice.

Some data suggests that clickthrough rates are relatively low. However, clickthrough rates aren’t the best metric. For technically savvy users aware of how to share without assistance, the buttons can still act as a prompt — a visual reminder to share the content. Regardless of how the link is ultimately shared, a custom share button can still provide a cue, or a little nudge to elicit the share. For this reason, measuring click rates on the buttons themselves may not be entirely fair — people may see the button, feel encouraged to share the content, but then use the browsers built-in share button. A better metric would be whether shares increase after the addition of share buttons, regardless of how they’re shared.

We’ve established that having a share button is probably useful. Websites have traditionally featured separate buttons for two or three of the most popular social networks. With a new-ish API, we can do better. While browser support is currently limited to Chrome for Android and Safari, those two browsers alone make up the vast majority of web traffic.

The Web Share API

The Web Share API offers a simple way to bring up a share sheet — the native bit of UI that’s used for sharing. Rather than offering a standard list of popular social networks to share to (which the user may or may not be a member of), the options of the share sheet are catered to the individual. Only applications they have installed on their phone will be shown. Rather than a uniform list, the user will be shown only the option to share on networks they actually use — whether that be Twitter and Facebook or something more esoteric.

Not showing the user irrelevant networks is obviously a good thing. Unfortunately, this is counterbalanced by the fact that some users visit social media websites rather than downloading them as apps. If you use twitter.com, for example, but haven’t installed the Twitter application natively, then Twitter will not be listed as a sharing option. Currently, only native apps are listed but PWAs will be supported in the future.

websharebutton.addEventListener("click", function() {
  navigator.share({
    url: document.URL,
    title: document.title,
    text: "lorem ipsum..."
  });
});

The API requires user interaction (such as a button click as shown in the above code) to bring up the share sheet. This means you can’t do something obnoxious like bring up the share sheet on page load.

The text might be a short excerpt or a summation of the page. The title is used when sharing via email but will be ignored when sharing to social networks.

Comparing the share sheets of Android and iPhone.
Native sharesheet dialog on Android (left) and iOS (right). The apps listed here are dependent on which apps you have installed on your device.

Sharing on desktop

While we are pretty happy with the Web Share API for mobile, its implementation for desktop is currently limited to Safari and leaves a lot to be desired. (Chrome is planning to ship support eventually, but there is no clear timescale).

The provided options — Mail, Message, Airdrop, Notes, Reminders — omit social networks. Native apps for Twitter and Facebook are common on phones, but rare on other devices.

Instead of relying on the Web Share API for desktop, its relatively common to have a generic share button that opens a modal that offers more multiple sharing options. This is the approach adopted by YouTube, Instagram and Pinterest, among others.

Comparing Instagram and YouTube share options on desktop.
Instagram (left) compared to YouTube (right)

Facebook and Twitter account for the vast majority of sharing online, so offering an exhaustive list of social networks to choose from doesn’t feel necessary. (An option for Instagram would be ideal, but it is currently not technically possible to share to Instagram from a website.) It is also relatively common to include an email option. For anyone using a web-based email client like gmail.com or outlook.com rather than the operating system’s default email application, this is problematic.

Many people make use of web-based email client’s gmail.com or outlook.com. A share-by-email button will open the operating system’s default email application. Users will be greeted by a prompt to set this up, which is far more effort than simply copy and pasting the URL. It is therefore advisable to omit the email option and instead include a button to copy the link to the clipboard, which is only infinitesimally easier than doing a copy in the address bar with the keyboard.

Screenshot of the share options offered by Mac's email application, including iCloud, Exchange, Google, Yahoo and AOL.
A prompt to set up the default email application on Mac

Prompting the user to set up an application they never use is far more effort than simply copy and pasting a URL into my preferred email client.

Choosing a share icon

Grid of various share icons in different variations.
There have been plenty of other share icons over the years.

There is no universal standardized share icon — far from it. While the Android symbol might not be recognizable to long-term iPhone users, the iOS icon is problematic. It is identical to the download icon — but with the arrow in the opposite direction, which would imply uploading, not sharing.

Where I work at giffgaff, we polled 69 of our colleagues on whether they recognized the current iOS icon or the current Android icon as representing sharing. The Android icon was an overwhelming winner with 58 votes. While our sample did include iPhone users, some long-term iPhone users may not be familiar with this symbol (even though it has been adopted by some websites). Then there is the forward arrow, an icon that was abandoned by Apple, but adopted elsewhere. Reminiscent of the icon for forwarding an email, this symbol has been made recognizable by its usage on youtube.com. The icon was adopted by Microsoft in 2017 after A/B testing found a high level of familiarity.

It’s also possible to take a contextual approach. Twitter will change the icon used depending on the platform of the user. This approach is also taken by the icon library Ionicons.

Showing the same tweet on both Android and iOS
Android (left) and Mac/iOS (right)

Given the lack of a universally understood icon, this seems like a good approach. Alternatively, make sure to include a label alongside the icon to really spell things out to the user.


UX Considerations for Web Sharing originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
295666
Five Methods for Five-Star Ratings https://css-tricks.com/five-methods-for-five-star-ratings/ https://css-tricks.com/five-methods-for-five-star-ratings/#comments Fri, 05 Jul 2019 15:48:00 +0000 http://css-tricks.com/?p=292151 In the world of likes and social statistics, reviews are a very important method for leaving feedback. Users often like to know the opinions of others before deciding on items to purchase themselves, or even articles to read movies to …


Five Methods for Five-Star Ratings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In the world of likes and social statistics, reviews are a very important method for leaving feedback. Users often like to know the opinions of others before deciding on items to purchase themselves, or even articles to read movies to see, or restaurants to dine.

Developers often struggle with reviews — it is common to see inaccessible and over-complicated implementations. Hey, CSS-Tricks has a snippet for one that’s now bordering on a decade.

Let’s walk through new, accessible and maintainable approaches for this classic design pattern. Our goal will be to define the requirements and then take a journey on the thought-process and considerations for how to implement them.

Scoping the work

Did you know that using stars as a rating dates all the way back to 1844 when they were first used to rate restaurants in Murray’s Handbooks for Travellers — and later popularized by Michelin Guides in 1931 as a three-star system? There’s a lot of history there, so no wonder it’s something we’re used to seeing!

There are a couple of good reasons why they’ve stood the test of time:

  1. Clear visuals (in the form of five hollow or filled stars in a row)
  2. A straightforward label (that provides an accessible description, like aria-label)

When we implement it on the web, it is important that we focus on meeting both of those outcomes.

It is also important to implement features like this in the most versatile way possible. That means we should reach for HTML and CSS as much as possible and try to avoid JavaScript where we can. And that’s because:

  1. JavaScript solutions will always differ per framework. Patterns that are typical in vanilla JavaScript might be anti-patterns in frameworks (e.g. React prohibits direct document manipulation).
  2. Languages like JavaScript evolve fast, which is great for the community, but not so great articles like this. We want a solution that’s maintainable and relevant for the long haul, so we should base our decisions on consistent, stable tooling.

Methods for creating the visuals

One of the many wonderful things about CSS is that there are often many ways to write the same thing. Well, the same thing goes for how we can tackle drawing stars. There are five options that I see:

  • Using an image file
  • Using a background image
  • Using SVG to draw the shape
  • Using CSS to draw the shape
  • Using Unicode symbols

Which one to choose? It depends. Let’s check them all out.

Method 1: Using an image file

Using images means creating elements — at least 5 of them to be exact. Even if we’re calling the same image file for each star in a five-star rating, that’s five total requests. What are the consequences of that?

  1. More DOM nodes make document structure more complex, which could cause a slower page paint. The elements themselves need to render as well, which means either the server response time (if SSR) or the main thread generation (if we’re working in a SPA) has to increase. That doesn’t even account for the rendering logic that has to be implemented.
  2. It does not handle fractional ratings, say 2.3 stars out of 5. That would require a second group of duplicated elements masked with clip-path on top of them. This increases the document’s complexity by a minimum of seven more DOM nodes, and potentially tens of additional CSS property declarations.
  3. Optimized performance ought to consider how images are loaded and implementing something like lazy-loading) for off-screen images becomes increasingly harder when repeated elements like this are added to the mix.
  4. It makes a request, which means that caching TTLs should be configured in order to achieve an instantaneous second image load. However, even if this is configured correctly, the first load will still suffer because TTFB awaits from the server. Prefetch, pre-connect techniques or the service-worker should be considered in order to optimize the first load of the image.
  5. It creates minimum of five non-meaningful elements for a screen reader. As we discussed earlier, the label is more important than the image itself. There is no reason to leave them in the DOM because they add no meaning to the rating — they are just a common visual.
  6. The images might be a part of manageable media, which means content managers will be able to change the star appearance at any time, even if it’s incorrect.
  7. It allows for a versatile appearance of the star, however the active state might only be similar to the initial state. It’s not possible to change the image src attribute without JavaScript and that’s something we’re trying to avoid.

Wondering how the HTML structure might look? Probably something like this:

<div class="Rating" aria-label="Rating of this item is 3 out of 5">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star">
  <img src="/static/assets/star.png" class="Rating--Star">
</div>

In order to change the appearance of those stars, we can use multiple CSS properties. For example:

.Rating--Star {
  filter: grayscale(100%); // maybe we want stars to become grey if inactive
  opacity: .3; // maybe we want stars to become opaque
}

An additional benefit of this method is that the <img> element is set to inline-block by default, so it takes a little bit less styling to position them in a single line.

Accessibility: ★★☆☆☆
Management: ★★★★☆
Performance: ★☆☆☆☆
Maintenance: ★★★★☆
Overall: ★★☆☆☆

Method 2: Using a background image

This was once a fairly common implementation. That said, it still has its pros and cons.

For example:

  1. Sure, it’s only a single server request which alleviates a lot of caching needs. At the same time, we now have to wait for three additional events before displaying the stars: That would be (1) the CSS to download, (2) the CSSOM to parse, and (3) the image itself to download.
  2. It’s super easy to change the state of a star from empty to filled since all we’re really doing is changing the position of a background image. However, having to crack open an image editor and re-upload the file anytime a change is needed in the actual appearance of the stars is not the most ideal thing as far as maintenance goes.
  3. We can use CSS properties like background-repeat property and clip-path to reduce the number of DOM nodes. We could, in a sense, use a single element to make this work. On the other hand, it’s not great that we don’t technically have good accessible markup to identify the images to screen readers and have the stars be recognized as inputs. Well, not easily.

In my opinion, background images are probably best-used complex star appearances where neither CSS not SVG suffice to get the exact styling down. Otherwise, using background images still presents a lot of compromises.

Accessibility: ★★★☆☆
Management: ★★★★☆
Performance: ★★☆☆☆
Maintenance: ★★★☆☆
Overall: ★★★☆☆

Method 3: Using SVG to draw the shape

SVG is great! It has a lot of the same custom drawing benefits as raster images but doesn’t require a server call if it’s inlined because, well, it’s simply code!

We could inline five stars into HTML, but we can do better than that, right? Chris has shown us a nice approach that allows us to provide the SVG markup for a single shape as a <symbol></symbol> and call it multiple times with with <use></use>.

<!-- Draw the star as a symbol and remove it from view -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="star" viewBox="214.7 0 182.6 792">
    <!-- <path>s and whatever other shapes in here -->  
  </symbol>
</svg>
    
<!-- Then use anywhere and as many times as we want! -->
<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

What are the benefits? Well, we’re talking zero requests, cleaner HTML, no worries about pixelation, and accessible attributes right out of the box. Plus, we’ve got the flexibility to use the stars anywhere and the scale to use them as many times as we want with no additional penalties on performance. Score!

The ultimate benefit is that this doesn’t require additional overhead, either. For example, we don’t need a build process to make this happen and there’s no reliance on additional image editing software to make further changes down the road (though, let’s be honest, it does help).

Accessibility: ★★★★★
Management: ★★☆☆☆
Performance: ★★★★★
Maintenance: ★★★★☆
Overall: ★★★★☆

Method 4: Using CSS to draw the shape

This method is very similar to background-image method, though improves on it by optimizing drawing the shape with CSS properties rather than making a call for an image. We might think of CSS as styling elements with borders, fonts and other stuff, but it’s capable of producing ome pretty complex artwork as well. Just look at Diana Smith’s now-famous “Francine” portrait.

Francine, a CSS replica of an oil painting done in CSS by Diana Smith (Source)

We’re not going to get that crazy, but you can see where we’re going with this. In fact, there’s already a nice demo of a CSS star shape right here on CSS-Tricks.

See the Pen
Five stars!
by Geoff Graham (@geoffgraham)
on CodePen.

Or, hey, we can get a little more crafty by using the clip-path property to draw a five-point polygon. Even less CSS! But, buyer beware, because your cross-browser support mileage may vary.

See the Pen
5 Clipped Stars!
by Geoff Graham (@geoffgraham)
on CodePen.

Accessibility: ★★★★★
Manangement: ★★☆☆☆
Performance: ★★★★★
Maintenance: ★★☆☆☆
Overall: ★★★☆☆

Method 5: Using Unicode symbols

This method is very nice, but very limited in terms of appearance. Why? Because the appearance of the star is set in stone as a Unicode character. But, hey, there are variations for a filled star (★) and an empty star (☆) which is exactly what we need!

Unicode characters are something you can either copy and paste directly into the HTML:

See the Pen
Unicode Stars!
by Geoff Graham (@geoffgraham)
on CodePen.

We can use font, color, width, height, and other properties to size and style things up a bit, but not a whole lot of flexibility here. But this is perhaps the most basic HTML approach of the bunch that it almost seems too obvious.

Instead, we can move the content into the CSS as a pseudo-element. That unleashes additional styling capabilities, including using custom properties to fill the stars fractionally:

See the Pen
Tiny but accessible 5 star rating
by Fred Genkin (@FredGenkin)
on CodePen.

Let’s break this last example down a bit more because it winds up taking the best benefits from other methods and splices them into a single solution with very little drawback while meeting all of our requirements.

Let’s start with HTML. there’s a single element that makes no calls to the server while maintaining accessibility:

<div class="stars" style="--rating: 2.3;" aria-label="Rating of this product is 2.3 out of 5."></div>

As you may see, the rating value is passed as an inlined custom CSS property (--rating). This means there is no additional rendering logic required, except for displaying the same rating value in the label for better accessibility.

Let’s take a look at that custom property. It’s actually a conversion from a value value to a percentage that’s handled in the CSS using the calc() function:

--percent: calc(var(--rating) / 5 * 100%);

I chose to go this route because CSS properties — like width and linear-gradient — do not accept <number></number> values. They accept <length></length> and <percentage></percentage> instead and have specific units in them, like % and px, em. Initially, the rating value is a float, which is a <number></number> type. Using this conversion helps ensure we can use the values in a number of ways.

Filling the stars may sound tough, but turns out to be quite simple. We need a linear-gradient background to create hard color stops where the gold-colored fill should end:

background: linear-gradient(90deg,
  var(--star-background) var(--percent), 
  var(--star-color) var(--percent)
);

Note that I am using custom variables for colors because I want the styles to be easily adjustable. Because custom properties are inherited from the parent elements styles, you can define them once on the :root element and then override in an element wrapper. Here’s what I put in the root:

:root {
  --star-size: 60px;
  --star-color: #fff;
  --star-background: #fc0;
}

The last thing I did was clip the background to the shape of the text so that the background gradient takes the shape of the stars. Think of the Unicode stars as stencils that we use to cut out the shape of stars from the background color. Or like a cookie cutters in the shape of stars that are mashed right into the dough:

-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

The browser support for background clipping and text fills is pretty darn good. IE11 is the only holdout.

Accessibility: ★★★★★
Management: ★★☆☆☆
Performance: ★★★★★
Maintenance: ★★★★★
Overall: ★★★★★

Final thoughts

Image Files Background Image SVG CSS Shapes Unicode Symbols
Accessibility ★★☆☆☆ ★★★☆☆ ★★★★★ ★★★★★ ★★★★★
Management ★★★★☆ ★★★★☆ ★★☆☆☆ ★★☆☆☆ ★★☆☆☆
Performance ★☆☆☆☆ ★★☆☆☆ ★★★★★ ★★★★★ ★★★★★
Maintenance ★★★★☆ ★★★☆☆ ★★★★☆ ★★☆☆☆ ★★★★★
Overall ★★☆☆☆ ★★★☆☆ ★★★★☆ ★★★☆☆ ★★★★★

Of the five methods we covered, two are my favorites: using SVG (Method 3) and using Unicode characters in pseudo-elements (Method 5). There are definitely use cases where a background image makes a lot of sense, but that seems best evaluated case-by-case as opposed to a go-to solution.

You have to always consider all the benefits and downsides of a specific method. This is, in my opinion, is the beauty of front-end development! There are multiple ways to go, and proper experience is required to implement features efficiently.


Five Methods for Five-Star Ratings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/five-methods-for-five-star-ratings/feed/ 5 292151
The Place of UX https://css-tricks.com/the-place-of-ux/ Tue, 07 May 2019 14:21:51 +0000 http://css-tricks.com/?p=286953 Every time “UX” comes out of my mouth or is typed by my fingers, I think, “did I just use that term correctly?” It feels like such a big and loaded term these days, that perhaps the way …


The Place of UX originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Every time “UX” comes out of my mouth or is typed by my fingers, I think, “did I just use that term correctly?” It feels like such a big and loaded term these days, that perhaps the way I use it only contributes to the confusion. Ryan Singer frames that problem well:

Debates continue to rage about the role of UX designers, user research, and how far knowledge about the user should permeate the organization. On one extreme, UX is seen as a specialized pocket of knowledge that informs the definition of projects and sets requirements. On the other, UX is something for which the entire organization should somehow feel responsible.

It can feel so big, like UX is literally the only thing that matters in an entire project. It can also feel so small, like 2px of extra padding on a specific dropdown will make the options easier to tap.

To Shared LinkPermalink on CSS-Tricks


The Place of UX originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
286953
Writing Animations That Bring Your Site to Life https://css-tricks.com/writing-animations-that-bring-your-site-to-life/ https://css-tricks.com/writing-animations-that-bring-your-site-to-life/#comments Fri, 22 Feb 2019 17:36:41 +0000 http://css-tricks.com/?p=283132 Web animation is one of the factors that can strongly enhance your website’s look and feel. Sadly, unlike mobile apps, there aren’t as many websites using animation to their benefit as you would think. We don’t want to count yours …


Writing Animations That Bring Your Site to Life originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Web animation is one of the factors that can strongly enhance your website’s look and feel. Sadly, unlike mobile apps, there aren’t as many websites using animation to their benefit as you would think. We don’t want to count yours among those, so this article is for you and anyone else looking for ways to use animation for a better user experience! Specifically, we’re going to learn how to make web interactions delightful using CSS animations.

Here’s what we’re going to build together:

Live Demo GitHub Repo

Before we move ahead, it’s worth mentioning that I’m going to assume you have at least some familiarity with modern front-end frameworks and a basic understanding of CSS animations. If you don’t, then no fear! CSS-Tricks has a great guides on React and Vue, as well as a thorough almanac post on the CSS animation property.

Good? OK, let’s talk about why we’d want to use animation in the first place and cover some baseline information about CSS animations.

Why would we to animate anything?

We could probably do an entire post on this topic alone. Oh, wait! Sarah Drasner already did that and her points are both poignant and compelling.

But, to sum things up based on my own experiences:

  • Animations enhance the way users interact with an interface. For example, smart animations can reduce cognitive load by giving users better context between page transitions.
  • They can provide clear cues to users, like where we want them to focus attention.
  • Animations serve as another design pattern in and of themselves, helping users to get emotionally attached to and engage with the interface.
  • Another benefit of using animations is that they can create a perception that a site or app loads faster than it actually does.

A couple of house rules with animations

Have you ever bumped into a site that animates all the things? Wow, those can be jarring. So, here’s a couple of things to avoid when working with animations so our app doesn’t fall into the same boat:

  • Avoid animating CSS properties other than transform and opacity. If other properties have to be animated, like width or height, then make sure there aren’t a lot of layout changes happening at the same time. There’s actually a cost to animations and you can see exactly how much by referring to CSS Triggers.
  • Also, just because animations can create perceived performance gains, there’s actually a point of diminishing return when it comes to using them. Animating too many elements at the same time may result in decreased performance.

Now we can get our hands dirty with some code!

Let’s build a music app

We’re going to build the music app we looked at earlier, which is inspired by Aurélien Salomon’s Dribbble shot. I chose this example so that we can focus on animations, not only within a component, but also between different routes. We’ll build this app using Vue and create animations using vanilla (i.e. no framework) CSS.

Animations should go hand-in-hand with UI development. Creating UI before defining their movement is likely to cost much more time. In this case, the Dribbble shot provides that scope for us.

Let’s start with the development.

Step 1: Spin up the app locally

First things first. We need to set up a new Vue project. Again, we’re assuming some base-level understanding of Vue here, so please check out the Learning Vue guide for more info on setting up.

We need a couple of dependencies for our work, notably vue-router for transitioning between views and sass-loader so we can write in Sass and compile to CSS. Here’s a detailed tutorial on using routes and Sass can be installed by pointing the command line at the project directory and using npm install -D sass-loader node-sass.

We have what we need!

Step 2: Setting up routes

For creating routes, we’re first going to create two bare minimum components — Artists.vue and Tracks.vue. We’ll drop a new file in the src folder called router.js and add routes for these components as:

import Vue from 'vue'
import Router from 'vue-router'
import Artists from './components/Artists.vue'
import Tracks from './components/Tracks.vue'

Vue.use(Router)
export default new Router({
	mode: 'history',
	routes: [
		{
			path: '/',
			name: 'artists',
			component: Artists
		},
		{
			path: '/:id',
			name: 'tracks',
			component: Tracks
		}
	]
})

Import router.js into the main.js and inject it to the Vue instance. Lastly, replace the content of your App.vue by <router-view/>.

Step 3: Create the components and content for the music app

We need two components that we’ll transition between with animation. Those are going to be:

  1. Artists.vue: a grid of artists
  2. Tracks.vue: An artist image with a back button

If you wanna jump ahead a bit, here are some assets to work with:

  1. Images and sample data in JSON format.
  2. Content for the components

When all is said and done, the two views will come out to something like this:

Artists.vue (left) and Tracks.vue (right)

Step 4: Animate!

Here we are, the part we’ve really wanted to get to all this time. The most important animation in the app is transitioning from Artists to Tracks when clicking on an artist. It should feel seamless where clicking on an artist image puts that image in focus while transitioning from one view into the next. This is exactly the type of animation that we rarely see in apps but can drastically reduce cognitive load for users.

To make sure we’re all on the same page, we’re going to refer to the first image in the sequence as the “previous” image and the second one as the “current” image. Getting the effect down is relatively easy as long as we know the dimensions and position of the previous image in the transition. We can animate the current image by transforming it as per previous image.

The formula that I’m using is transform: translate(x, y) scale(n), where n is equal to the size of previous image divided by the size of current image. Note that we can use a static value of n since the dimensions are fixed for all the images. For example, the image size in the Artists view is 190x190 and 240x240 in the Tracks view. Thus, we can replace n by 190/240 = 0.791. That means the transform value becomes translate(x, y) scale(0.791) in our equation.

Animating from Artists to Tracks

Next thing is to find x and y. We can get these values though click event in the Artists view as:

const {x, y} = event.target.getBoundingClientRect()

…and then send these values to the Tracks view, all while switching the route. Since we aren’t using any state management library, the two components will communicate via their parent component, which is the top level component, App.vue. In App.vue, let’s create a method that switches the route and sends the image info as params.

gotoTracks(position, artistId) {
	this.$router.push({
		name: 'tracks',
		params: {
			id: artistId,
			position: position
		}
	})
}

Here’s the relevant code from the repo to reference, in case you’re interested.

Since we have received the position and ID of the image in Tracks, we have all the required data to show and animate it. We’ll first fetch artist information (specifically the name and image URL) using artist ID.

To animate the image, we need to calculate the transform value from the image’s starting position. To set the transform value, I’m using CSS custom properties, which can be done with CSS-in-JS techniques as well. Note that the image’s position that we received through props will be relative to window. Therefore we’ll have to subtract some fixed offset caused by the padding of the container <div> to even out our math.

const { x, y } = this.$route.params.position
// padding-left
const offsetLeft = 100
// padding-top
const offsetTop = 30

// Set CSS custom property value
document.documentElement.style.setProperty(
	'--translate', 
	`translate(${x - offsetLeft}px, ${y - offsetTop}px) scale(0.792)`
)

We’ll use this value to create a keyframe animation to move the image:

@keyframes move-image {
	from {
		transform: var(--translate);
	}
}

This gets assigned to the CSS animation:

.image {
	animation: move-image 0.6s;
}

…and it will animate the image from this transform value to its original position on component load.

Transitioning from Artists to Tracks

We can use the same technique when going the opposite direction, Tracks to Artists. As we already have the clicked image’s position stored in the parent component, we can pass it to props for Artists as well.

Transitioning from Tracks to Artists

Step 5: Show the tracks!

It’s great that we can now move between our two views seamlessly, but the Tracks view is pretty sparse at the moment. So let’s add the track list for the selected artist.

We’ll create an empty white box and a new keyframe to slide it upwards on page load. Then we’ll add three subsections to it: Recent Tracks, Popular Tracks, and Playlist. Again, if you want to jump ahead, feel free to either reference or copy the final code from the repo.

The Tracks view with content

Recent Tracks is the row of thumbnails just below the artist image where each thumbnail includes the track name and track length below it. Since we’re covering animations here, we’ll create a scale-up animation, where the image starts invisible (opacity: 0) and a little smaller than it’s natural size (scale(0.7)), then is revealed (opacity: 1 )and scales up to its natural size (transform: none).

.track {
	opacity: 0;
	transform: scale(0.7);
	animation: scale-up 1s ease forwards;
}

@keyframes scale-up {
	to {
		opacity: 1;
		transform: none;
	}
}

The Popular Tracks list and Playlist sit side-by-side below the Recent Tracks, where Popular tracks takes up most of the space. We can slide them up a bit on initial view with another set of keyframes:

.track {
	...
	animation: slide-up 1.5s;
}

@keyframes slide-up {
	from {
		transform: translateY(140px);
	}
}

To make the animation feel more natural, we’ll create a stagger effect by adding an incremental animation delay to each item.

@for $i from 1 to 5 {
	&:nth-child(#{$i + 1}) {
		animation-delay: #{$i * 0.05}s;
	}
}

The code above is basically looking for each child element, then adding a 0.05 second delay to each element it finds. So, for example, the first child gets a 0.05 second delay, the second child gets a 0.10 second delay and so on.

Check out how nice and natural this all looks:

Bonus: micro-interactions!

One of the fun things about working with animations is thinking through the small details because they’re what tie things together and add delight to the user experience. We call these micro-interactions and they serve a good purpose by providing visual feedback when an action is performed.

Depending on the complexity of the animations, we might need a library like anime.js or GSAP. This example is pretty straightforward, so we can accomplish everything we need by writing some CSS.

First micro-interaction: The volume icon

Let’s first get a volume icon in SVG format (Noun Project and Material Design are good sources). On click, we’ll animate-in and out its path element to show the level of volume. For this, we’ll create a method which switches its CSS class according to the volume level.

<svg @click="changeVolume">
	<g :class="`level-${volumeLevel}`">
		<path d="..."/> <!-- volume level 1 -->
		<path d="..."/> <!-- volume level 2 -->
		<path d="..."/> <!-- volume level 3 -->
		<polygon points="..."/>
	</g>
</svg>

Based on this class, we can show and hide certain path elements as:

path {
	opacity: 0;
	transform-origin: left;
	transform: translateX(-5px) scale(0.6);
	transition: transform 0.25s, opacity 0.2s;
}

.level-1 path:first-child,
.level-2 path:first-child,
.level-2 path:nth-child(2),
.level-3 path {
	opacity: 1;
	transform: none;
}
The animated volume control

Second micro-interaction: The favorite icon

Do you like it when you click on Twitter’s heart button? That’s because it feels unique and special by the way it animates on click. We’ll make something similar but real quick. For this, we first get an SVG heart icon and add it to the the markup. Then we’ll add a bouncy animation to it that’s triggered on click.

@keyframes bounce {
	0%, 100% {
		transform: none;
	}
	30% {
		transform: scale(1.3);
	}
	60% {
		transform: scale(0.9);
	}
}

Another fun thing we can do is add other small heart icons around it with random sizes and positions. Ideally, we’d add a few absolute-positioned HTML elements that a heart as the background. Let’s Arrange each of them as below by setting their left and bottom values.

We’ll also include a fade away effect so the icons appear to dissolve as they move upward by adding a keyframe animation on the same click event.

@keyframes float-upwards {
	0%, 100% {
		opacity: 0;
	}
	50% {
		opacity: 0.7;
	}
	50%, 100% {
		transform: translate(-1px, -5px);
	}
}
The animated favorite button

Summing up

That’s all! I hope you find all this motivating to try animations on your own websites and projects.

While writing this, I also wanted to expand on the fundamental animation principles we glossed over earlier because I believe that they help choose animation durations, and avoid non-meaningful animations. That’s important to discuss because doing animations correctly is better than doing them at all. But this sounds like a whole another topic to be covered in a future article.


Writing Animations That Bring Your Site to Life originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/writing-animations-that-bring-your-site-to-life/feed/ 4 283132
Don’t Get Clever with Login Forms https://css-tricks.com/dont-get-clever-with-login-forms/ https://css-tricks.com/dont-get-clever-with-login-forms/#comments Tue, 19 Feb 2019 15:18:13 +0000 http://css-tricks.com/?p=283081 Brad points out some UX problems with a variety of apps that are doing things a little outside of the norm when it comes to their login forms. There is already a bunch of things to get right with forms …


Don’t Get Clever with Login Forms originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Brad points out some UX problems with a variety of apps that are doing things a little outside of the norm when it comes to their login forms. There is already a bunch of things to get right with forms to begin with (e.g. use the right input types, label your inputs, don’t have whack password requirements, use SSL, etc.)… OMG why complicate it even more?!

A “password manager test” should be a development best practice here. Does it work cleanly with the built-in browser password manager? How about 1Password and LastPass? No? Give it some love, please and thank you.

To Shared LinkPermalink on CSS-Tricks


Don’t Get Clever with Login Forms originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/dont-get-clever-with-login-forms/feed/ 1 283081
Preventing Suicide with UX: A Case Study on Google Search https://css-tricks.com/preventing-suicide-with-ux-a-case-study-on-google-search/ https://css-tricks.com/preventing-suicide-with-ux-a-case-study-on-google-search/#comments Tue, 30 Oct 2018 14:08:47 +0000 http://css-tricks.com/?p=278018 I came clean about my long-running and ongoing battle with chronic depression last year in a blog post on my personal site. But don’t worry, things are no worse than they were then and this post is about something else. …


Preventing Suicide with UX: A Case Study on Google Search originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I came clean about my long-running and ongoing battle with chronic depression last year in a blog post on my personal site. But don’t worry, things are no worse than they were then and this post is about something else. This post is about designing empathetic user experiences.

Several other sites have been posting on this topic, whether it’s how UX can improve mental health or how it can be used to prevent suicide.

It’s the latter I’d like to focus on here. In fact, Lucas Chae did such a fantastic job on that post that you should stop reading this right now and head over there. Seriously, if you only have time to read one post today, that’s the one.

Lucas goes to great lengths to show how UX can prevent suicide using Google search as a case study. I don’t disagree with any of his ideas. I love them. But anything has room for improvement or at least refinement, and I have a few ideas I’d like to toss in the ring. Again, not because the ideas are bad or screaming to be fixed, but because I have a personal connection to this topic and am interested in seeing great ideas like this move forward.

Let’s briefly rehash the context

I really hope you took up my suggestion to pop over to Lucas’s post, but if you didn’t the main gist of it goes:

  • Roughly 500,000 people submit suicide-related searches on Google every month.
  • Google returns some helpful information pinned to the top of the results, but it feels like a requirement more than a helpful interaction.
  • Lucas mocked up a proposed experience that replaces the existing pinned result with UI that feels more conversational and relatable.

There’s a lot more nuance to it, but that’s roughly what we’re looking at. My four suggestions are merely standing on the shoulders of what’s proposed there.

Gut check

At this point, you might be asking how much responsibility Google has in preventing suicide and whether it really needs to invest more into this than it already does. I like the way Lucas phrases it in his proposal:

“We are only a search engine, and cannot give you answers to your hardest questions. But we can help you get there.”

That is a good line to draw. And, yes, Google is technically already doing that to some extent, but this is an opportunity to provide recommendations that are as relevant as the search results that are Google’s bread and butter.

It’s also worth couching this entire diatribe with a note that there are zero expectations and absolutely no responsibility for Google to do anything proposed in this post. This is merely demonstrating the impact that UX design can have on a real-world problem using Google as the vehicle to drive these points home. We really could have done this with Bing, Yahoo, DuckDuckGo or any similar product.

Suggestion 1: Reach the user earlier

Lucas’s work zeroes in on what Google delivers after the search query has been made. Thinking about this as a user flow, we’re looking at something like this:

Step Description Expected Outcome Emotions
1 User is contemplating suicide, reaches for phone, computer Able to start up a device and fire up a browser to navigate to Google Hopeless
Sad
Lonely
2 Enters “How to kill myself” into the search field Possibly some related search suggestions, but ultimately a means to submit the search. Probably not much different than the previous step, but maybe some pensiveness over what search term will produce the best results.
3 Submits search A page refresh with relevant links Anxious
Scared

The majority of Lucas’s work is driven by Step 3 (and beyond). I think we can narrow the gap of time between contemplation and search submission by zooming in on Step 2.

Have you ever typed a partial query into Google? The auto-suggestions are often extremely useful (at least to me) but they can be pretty hilarious as well. Take, for example:

I’m not sure why that was the first thing that came to mind as an example but, hey, it’s still nuts that those are actual examples of user submissions and have made the list of predicted suggestions. I mean, of course, Russell Crowe is alive… right?

(Does some more searching.)

Right!

Funny (or not funny) enough, Google does not provide those suggestions for suicide-related searches. Or, more accurately, it weeds out suicide-related results and provides others until it simple can’t suggest anything:

😂 LOL, did you catch “how to kill mysql process” in there?

I understand why Google would want to exclude suicidal terms from their suggestions. Why plant ideas in people’s heads if that is not what the user is actually looking for? Seems like something to avoid.

But what if it’s an opportunity rather than an obstacle? If we have a chance to interact with someone even a few seconds earlier in the process, then it’s possible we’re talking about saving some lives.

I would suggest embracing the prediction engine and even beefing it up to take sensitive searches head on. For example, what if we took Lucas’s initial idea of interacting with the user right from here instead of waiting for a submitted search and its results?

Suggestion 2: Amp up the personalization

Let’s all agree that Google knows way too much about people in general. I know, I know. Some people love it and see it as a potential force for good while others are wary of the impact a digital footprint can have IRL. I read The Circle, too.

Either way, Google likely knows a thing or two about the user, even if they are not logged in. But, assuming that the user is logged and has at least a partial profile (both of which I think are safe assumptions given Google’s ubiquitous nature, prevalent reliance on it for oAuth, and that the user turned to it instead, say, Bing), then we can make a personal appeal to that user instead of generalized content.

For example, we can make use of avatars, names, locations, search history, etc. And, yes, the likelihood of Google having all of this among many, many (MANY!) other bits of data are extremely good — nay, great!

If we are going to utilize the predictive search feature, then we can put Google’s treasure trove of user data into play to grab the user’s attention and extend an invitation to engage before the search has even happened. That said, while I’m suggesting that we “amp” up the personalization, let’s agree that any attempt to be too smart can also lead to poor user experiences and, at worst, even more personal pain.

So, while we have a treasure trove of data, keeping the scope to a personalized greeting or introduction will suffice.

Suggestion 3: Leverage Google’s technical arsenal

The biggest criticism of Google’s existing experience is that it feels like a requirement. I wholeheartedly agree with Lucas here. Just look.

And, yes, that is now in my search history.

What that uninviting and impersonal approach has going for it is that it provides the user with two clear paths to get help: phone and online chat. Google has developed products that make calls and power video chats, so there’s no reason why we can’t take these already great innovations and put them to use in this new context.

The proposed design from Lucas maintains a call link in the UI, but it seems buried beneath the core interaction and totally removes online chat. If Google has the technical means to apply one-on-one interactions that narrow geographical distances between hurt and help, and has influence to partner with suicide prevention groups and mental health professionals, then by all means! Those are things I would absolutely work into the UI.

Suggestion 4: Go further to maintain the Google brand

Lucas makes a stellar point that any improvement to the UX should be mindful of Google’s own brand and positioning:

This is a redesign, not a new service that I am launching. One principle I value the most when redesigning an existing interface is respecting the original design principles. Design is never just about making it look pretty. Design is a manifestation of a company’s philosophy and core-values based on years of research and testing.

Amen!

Lucas absolutely nails the grid system, color palette, iconography and baseline card component that come straight from the Material Design guidelines. Still, I think there is room to be even more faithful to Google’s design DNA.

There is a specific point where Lucas deviates from the card component guidelines — the UI that allows the user to categorize feelings.

The animation and general interaction is slick. However, it does feel off-brand… at least to me. We’ll get to my mockups in a bit, but I wanted to make sure any new UI took the card component as far as it could go, always using established Google components. For example, I took the UI Lucas created for feeling categories and “dumbed” it down to literal card patterns as they’re described in the docs.

OK, onto the mockups…

Looking past my lack of design chops, here’s where I landed with everything we’ve covered so far.

Predictive search interface

The user has landed on google.com and is in the process of typing, “how to kill myself.” Rather than disabling predictive suggestions like the current functionality does, we tackle the tough query head on and engage the user, making a personalized plea and making an offer to point the user to positive answers.

Notice that the “Continue” text link is in a disabled state. That’s to add a little friction in the flow to encourage the user to engage with the slider. Of course, we’re also creating a clear path to “Call Help” if the user does indeed need to talk with someone and bail on this UI.

Interacting with the user

What’s the slider? Well, it’s more or less an interpretation of the UI Lucas created that allows the user to provide more detail for the pain they’re suffering:

I find that my proposed pattern is more in line with Google’s Material Design guidelines, specifically with sliders.

The slider is a nice way for users to make a selection across a wide variety of options in a small space. In this case, we’re allowing the user to slide between the same categories Lucas defined in his research and introducing sub-categories from there as text links.

One thing we want to make sure of is that the intent of the options in the slider are not misinterpreted. For example, is “Love & Relationships” first because it’s the most important? It’d be a shame if that’s the way it came across. One idea (among others, I’m sure) is to float a little information icon in there that displays a tooltip on hover explaining that the options are in no particular order.

I think the outcome here, again, is a nice way to get the same level of detail that Lucas mocked up into a smaller space while gaining valuable feedback from the user that helps us learn the context of their feelings.

The first step to help

Once the user has made a selection in the slider and clicked on a sub-category, we can provide the same encouraging, inspiring content Lucas proposed, perhaps pulled from real articles on the subject.

Note that we technically changed the state of the “Continue” text link from disabled to active in the last screen. We can use the context the user has provided so far to allow them to proceed with a much safer and productive search query based on the category/sub-category that is selected.

Additional guidance

Will the UX so far prevent a suicide? Maybe. I hope! But there’s a chance it won’t.

But, hey, we now have better context for the user’s feelings and can provide a relevant path to suggest answers. So, if the user has chosen the category “Love & Relationships” and selected the “Death of a loved one” sub-category, then we can send the user to search results for that subject rather than “How to kill myself” — which would inevitably lead to a more destructive set of search results than something on love and relationships.

Google already does a pretty darn good job of this…

Seriously, say what you want about the lack of design flare, but having a featured result up top that the user can personally relate to, additional search suggestions, and the organic results at the end makes for a pretty compelling experience. A much better place to send the user!

The only change I would suggest is to maintain the ability to make a call to or initiate a chat with a trained professional. It’s doesn’t need to scream for attention in the UI, but be available. Material Design’s banner component seems pretty relevant here, though I can see push back on that as far as the literal use case.

Are we making progress?

I give the greatest hat tip of all hat tips to Lucas Chae for broaching such a hard topic. Not only does he do a bang-up job to solve a real-world problem, but brings awareness to it. Obviously, it’s something I’m able to relate to on a deep personal level and it’s encouraging to see others both empathizing with it and pushing forward ideas to deal with it.

Thank you for that, Lucas.

I hope that by putting my own ideas on the table that we can keep this conversation moving. And that means getting even more ideas on the table and seeing where we can take this bad boy as a community.

So, do you have feedback on anything you’ve seen so far? Maybe ideas of your own you’d like to mock up and share? Please do! The web community is a great one and we can accomplish amazing things together. 💪


Note: My sincere thanks to Chris, Andy Bell and Eric Bailey for providing thoughtful, insightful and thorough feedback on earlier drafts of this post.


Preventing Suicide with UX: A Case Study on Google Search originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/preventing-suicide-with-ux-a-case-study-on-google-search/feed/ 12 278018