CSS-Tricks

Subscribe to CSS-Tricks feed
Tips, Tricks, and Techniques on using Cascading Style Sheets.
Updated: 4 hours 22 min ago

Animating Layouts with the FLIP Technique

Mon, 11/27/2017 - 23:41

User interfaces are most effective when they are intuitive and easily understandable to the user. Animation plays a major role in this - as Nick Babich said, animation brings user interfaces to life. However, adding meaningful transitions and micro-interactions is often an afterthought, or something that is “nice to have” if time permits. All too often, we experience web apps that simply “jump” from view to view without giving the user time to process what just happened in the current context.

This leads to unintuitive user experiences, but we can do better, by avoiding “jump cuts” and “teleportation” in creating UIs. After all, what’s more natural than real life, where nothing teleports (except maybe car keys), and everything you interact with moves with natural motion?

In this article, we’ll explore a technique called “FLIP” that can be used to animate the positions and dimensions of any DOM element in a performant manner, regardless of how their layout is calculated or rendered (e.g., height, width, floats, absolute positioning, transform, flexbox, grid, etc.)

Why the FLIP technique?

Have you ever tried to animate height, width, top, left, or any other properties besides transform and opacity? You might have noticed that the animations look a bit janky, and there's a reason for that. When any property that triggers layout changes (such as `height`), the browser has to recursively check if any other element's layout has changed as a result, and that can be expensive. If that calculation takes longer than one animation frame (around 16.7 milliseconds), then the animation frame will be skipped, resulting in "jank"
since that frame wasn't rendered in time. In Paul Lewis' article "Pixels are Expensive", he goes further in depth at how pixels are rendered and the various performance expenses.

In short, our goal is to be short -- we want to calculate the least amount of style changes necessary, as quickly as possible. The key to this is only animating transform and opacity, and FLIP explains how we can simulate layout changes using only transform.

What is FLIP?

FLIP is a mnemonic device and technique first coined by Paul Lewis, which stands for First, Last, Invert, Play. His article contains an excellent explanation of the technique, but I’ll outline it here:

  • First: before anything happens, record the current (i.e., first) position and dimensions of the element that will transition. You can use getBoundingClientRect() for this, as will be shown below.
  • Last: execute the code that causes the transition to instantaneously happen, and record the final (i.e., last) position and dimensions of the element.*
  • Invert: since the element is in the last position, we want to create the illusion that it’s in the first position, by using transform to modify its position and dimensions. This takes a little math, but it’s not too difficult.
  • Play: with the element inverted (and pretending to be in the first position), we can move it back to its last position by setting its transform to none.

Below is how these steps can be implemented:

const elm = document.querySelector('.some-element'); // First: get the current bounds const first = getBoundingClientRect(elm); // execute the script that causes layout change doSomething(); // Last: get the final bounds const last = getBoundingClientRect(elm); // Invert: determine the delta between the // first and last bounds to invert the element const deltaX = first.left - last.left; const deltaY = first.top - last.top; const deltaW = first.width / last.width; const deltaH = first.height / last.height; // Play: animate the final element from its first bounds // to its last bounds (which is no transform) elm.animate([{ transformOrigin: 'top left', transform: ` translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH}) ` }, { transformOrigin: 'top left', transform: 'none' }], { duration: 300, easing: 'ease-in-out', fill: 'both' });

See the Pen How the FLIP technique works by David Khourshid (@davidkpiano) on CodePen.

There are two important things to note:

  1. If the element’s size changed, you can transform scale in order to “resize” it with no performance penalty; however, make sure to set transformOrigin to 'top left' since that’s where we based our delta calculations.
  2. We’re using the Web Animations API to animate the element here, but you’re free to use any other animation engine, such as GSAP, Anime, Velocity, Just-Animate, Mo.js and more.
Shared Element Transitions

One common use-case for transitioning an element between app views and states is that the final element might not be the same DOM element as the initial element. In Android, this is similar to a shared element transition, except that the element isn’t “recycled” from view to view in the DOM as it is on Android.

Nevertheless, we can still achieve the FLIP transition with a little magic illusion:

const firstElm = document.querySelector('.first-element'); // First: get the bounds and then hide the element (if necessary) const first = getBoundingClientRect(firstElm); firstElm.style.setProperty('visibility', 'hidden'); // execute the script that causes view change doSomething(); // Last: get the bounds of the element that just appeared const lastElm = document.querySelector('.last-element'); const last = getBoundingClientRect(lastElm); // continue with the other steps, just as before. // remember: you're animating the lastElm, not the firstElm.

Below is an example of how two completely disparate elements can appear to be the same element using shared element transitions. Click one of the pictures to see the effect.

See the Pen FLIP example with WAAPI by David Khourshid (@davidkpiano) on CodePen.

Parent-Child Transitions

With the previous implementations, the element bounds are based on the window. For most use cases, this is fine, but consider this scenario:

  • An element changes position and needs to transition.
  • That element contains a child element, which itself needs to transition to a different position inside the parent.

Since the previously calculated bounds are relative to the window, our calculations for the child element are going to be off. To solve this, we need to ensure that the bounds are calculated relative to the parent element instead:

const parentElm = document.querySelector('.parent'); const childElm = document.querySelector('.parent > .child'); // First: parent and child const parentFirst = getBoundingClientRect(parentElm); const childFirst = getBoundingClientRect(childElm); doSomething(); // Last: parent and child const parentLast = getBoundingClientRect(parentElm); const childLast = getBoundingClientRect(childElm); // Invert: parent const parentDeltaX = parentFirst.left - parentLast.left; const parentDeltaY = parentFirst.top - parentLast.top; // Invert: child relative to parent const childDeltaX = (childFirst.left - parentFirst.left) - (childLast.left - parentLast.left); const childDeltaY = (childFirst.top - parentFirst.top) - (childLast.top - parentLast.top); // Play: using the WAAPI parentElm.animate([ { transform: `translate(${parentDeltaX}px, ${parentDeltaY}px)` }, { transform: 'none' } ], { duration: 300, easing: 'ease-in-out' }); childElm.animate([ { transform: `translate(${childDeltaX}px, ${childDeltaY}px)` }, { transform: 'none' } ], { duration: 300, easing: 'ease-in-out' });

A few things to note here, as well:

  1. The timing options for the parent and child (duration, easing, etc.) do not necessarily need to match with this technique. Feel free to be creative!
  2. Changing dimensions in parent and/or child (width, height) was purposefully omitted in this example, since it is an advanced and complex topic. Let’s save that for another tutorial.
  3. You can combine the shared element and parent-child techniques for greater flexibility.
Using Flipping.js for Full Flexibility

The above techniques might seem straightforward, but they can get quite tedious to code once you have to keep track of multiple elements transitioning. Android eases this burden by:

  • baking shared element transitions into the core SDK
  • allowing developers to identify which elements are shared by using a common android:transitionName XML attribute

I’ve created a small library called Flipping.js with the same idea in mind. By adding a data-flip-key="..." attribute to HTML elements, it’s possible to predictably and efficiently keep track of elements that might change position and dimensions from state to state.

For example, consider this initial view:

<section class="gallery"> <div class="photo-1" data-flip-key="photo-1"> <img src="/photo-1"/> </div> <div class="photo-2" data-flip-key="photo-2"> <img src="/photo-2"/> </div> <div class="photo-3" data-flip-key="photo-3"> <img src="/photo-3"/> </div> </section>

And this separate detail view:

<section class="details"> <div class="photo" data-flip-key="photo-1"> <img src="/photo-1"/> </div> <p class="description"> Lorem ipsum dolor sit amet... </p> </section>

Notice in the above example that there are 2 elements with the same data-flip-key="photo-1". Flipping.js tracks the “active” element by choosing the first element that meet these criteria:

  • The element exists in the DOM (i.e., it hasn’t been removed or detached)
  • The element is not hidden (hint: getBoundingClientRect(elm) will have { width: 0, height: 0 } for hidden elements)
  • Any custom logic specified in the selectActive option.
Getting Started with Flipping.js

There’s a few different packages for Flipping, depending on your needs:

  • flipping.js: tiny and low-level; only emits events when element bounds change
  • flipping.web.js: uses WAAPI to animate transitions
  • flipping.gsap.js: uses GSAP to animate transitions
  • More adapters coming soon!

You can grab the minified code directly from unpkg:

Or you can npm install flipping --save and import it into your projects:

// import not necessary when including the unpkg scripts in a <script src="..."> tag import Flipping from 'flipping/adapters/web'; const flipping = new Flipping(); // First: let Flipping read all initial bounds flipping.read(); // execute the change that causes any elements to change bounds doSomething(); // Last, Invert, Play: the flip() method does it all flipping.flip();

Handling FLIP transitions as a result of a function call is such a common pattern, that the .wrap(fn) method transparently wraps (or “decorates”) the given function by first calling .read(), then getting the return value of the function, then calling .flip(), then returning the return value. This leads to much less code:

const flipping = new Flipping(); const flippingDoSomething = flipping.wrap(doSomething); // anytime this is called, FLIP will animate changed elements flippingDoSomething();

Here is an example of using flipping.wrap() to easily achieve the shifting letters effect. Click anywhere to see the effect.

See the Pen Flipping Birthstones #Codevember by David Khourshid (@davidkpiano) on CodePen.

Adding Flipping.js to Existing Projects

In another article, we created a simple React gallery app using finite state machines. It works just as expected, but the UI could use some smooth transitions between states to prevent “jumping” and improve the user experience. Let’s add Flipping.js into our React app to accomplish this. (Keep in mind, Flipping.js is framework-agnostic.)

Step 1: Initialize Flipping.js

The Flipping instance will live on the React component itself, so that it’s isolated to only changes that occur within that component. Initialize Flipping.js by setting it up in the componentDidMount lifecycle hook:

componentDidMount() { const { node } = this; if (!node) return; this.flipping = new Flipping({ parentElement: node }); // initialize flipping with the initial bounds this.flipping.read(); }

By specifying parentElement: node, we’re telling Flipping to only look for elements with a data-flip-key in the rendered App, instead of the entire document.

Then, modify the HTML elements with the data-flip-key attribute (similar to React’s key prop) to identify unique and “shared” elements:

renderGallery(state) { return ( <section className="ui-items" data-state={state}> {this.state.items.map((item, i) => <img src={item.media.m} className="ui-item" style={{'--i': i}} key={item.link} onClick={() => this.transition({ type: 'SELECT_PHOTO', item })} data-flip-key={item.link} /> )} </section> ); } renderPhoto(state) { if (state !== 'photo') return; return ( <section className="ui-photo-detail" onClick={() => this.transition({ type: 'EXIT_PHOTO' })}> <img src={this.state.photo.media.m} className="ui-photo" data-flip-key={this.state.photo.link} /> </section> ) }

Notice how the img.ui-item and img.ui-photo are represented by data-flip-key={item.link} and data-flip-key={this.state.photo.link} respectively: when the user clicks on an img.ui-item, that item is set to this.state.photo, so the .link values will be equal.

And since they are equal, Flipping will smoothly transition from the img.ui-item thumbnail to the larger img.ui-photo.

Now we need to do two more things:

  1. call this.flipping.read() whenever the component will update
  2. call this.flipping.flip() whenever the component did update

Some of you might have already guessed where these method calls are going to occur: componentWillUpdate and componentDidUpdate, respectively:

componentWillUpdate() { this.flipping.read(); } componentDidUpdate() { this.flipping.flip(); }

And, just like that, if you’re using a Flipping adapter (such as flipping.web.js or flipping.gsap.js), Flipping will keep track of all elements with a [data-flip-key] and smoothly transition them to their new bounds whenever they change. Here is the final result:

See the Pen FLIPping Gallery App by David Khourshid (@davidkpiano) on CodePen.

If you would rather implement custom animations yourself, you can use flipping.js as a simple event emitter. Read the documentation for more advanced use-cases.

Flipping.js and its adapters handle the shared element and parent-child transitions by default, as well as:

  • interrupted transitions (in adapters)
  • enter/move/leave states
  • plugin support for plugins such as mirror, which allows newly entered elements to “mirror” another element’s movement
  • and more planned in the future!
Resources

Similar libraries include:

  • FlipJS by Paul Lewis himself, which handles simple single-element FLIP transitions
  • React-Flip-Move, a useful React library by Josh Comeau
  • BarbaJS, not necessarily a FLIP library, but one that allows you to add smooth transitions between different URLs, without page jumps.

Further resources:

Animating Layouts with the FLIP Technique is a post from CSS-Tricks

Netflix functions without client-side React, and it’s a good thing

Mon, 11/27/2017 - 20:18

Recently Netflix removed client-side React from their landing page which caused a bit of a stir. So Jake Archibald investigated why the team did that and how it’s actually a good thing for the React community in the long term:

When the PS4 was released in 2013, one of its advertised features was progressive downloading – allowing gamers to start playing a game while it's downloading. Although this was a breakthrough for consoles, the web has been doing this for 20 years. The HTML spec (warning: 8mb document), despite its size, starts rendering once ~20k is fetched.

Unfortunately, it's a feature we often engineer-away with single page apps, by channelling everything through a medium that isn't streaming-friendly, such as a large JS bundle.

I like the whole vibe of this post because it suggests that we should be careful when we pick our tools; we only should pick the right tool for the right job, instead of treating every issue as if it needs a giant hammer made of JavaScript. Also! Burke Holland wrote a funny piece last week on this topic with some of his thoughts.

Direct Link to ArticlePermalink

Netflix functions without client-side React, and it’s a good thing is a post from CSS-Tricks

Apps Have Command Prompts Now

Mon, 11/27/2017 - 18:43

Command lines were an early innovation in computers, and were the dominant way to interact with them in the 1960's - 80's. That gave way to GUIs for most users after that. I don't think we need to launch a scientific study to figure out why. Most users find it more comfortable and intuitive to accomplish things with interactive moments and visual feedback.

But command lines never went away. GUI's are generally a limited abstraction of what you could do through a command line anyway, so power users gravitate toward the closer-to-the-metal nature of the command line.

But we might be in the middle of a return to a happy medium.

Finder-ing

We know Apple is quite fond of cutting features. Particularly little-used features or power-user-only features. Curiously, this one has stuck around:

The "Go To Folder" dialog, via Command-Shift-G

William Pearson wrote:

If there’s only one keyboard shortcut you should remember in Mac OS X it’s this: Go To Folder. ... Is there a keyboard shortcut that is more useful than “Go To Folder”? I don’t think so.

I'm not sure about that, but it's clear some people take this shortcut pretty seriously! And yes, a keyboard shortcut, but one that essentially opens a command line prompt that can do one thing.

I guess that isn't terribly surprising, considering the success of apps like Alfred, which perhaps it's fair to say is a command line for finding, opening and doing things.

The Finder also has Spotlight (since OS X 10.4 Tiger anyway, 2005) which is largely a thing for search (especially these days, as it returns results the web as well).

Spotlight has a keyboard command (Command-Space) and then you just type to do stuff, so it's very much a command prompt. Just one that's pretty decked out in user-friendliness.

And while we're on this bend, we can't forget about Quicksilver. Interestingly, both Alfred and Quicksilver postdate Spotlight. I guess that speaks to Spotlight kind of sucking in the early days, and leaving people wanting more.

Code Editors

Most developers, I'm sure, are quite aware of the literal command line. Almost all the big development tools are command line based tools. Everything from Git to Gulp, image optimizers to package managers, Capistrano to webpack... they are all tools you use from the command line. If you have a GUI for any of them, it's probably a light abstraction over command line methods.

But, aside from the most hardcore of all Vim users who do all their code editing from a terminal window, we don't actually write code on the command line, but in an editor with a GUI.

Code Editors are a perfect breeding ground for ideas that combine the best of GUI's and command lines.

Let's look at Sublime Text. When creating a new folder, I might want to do that with the GUI. There I can see the existing folder structure and see exactly what I'm doing.

But say I want to jump to a file I know exists. Say it's buried a number of directories deep, and I'm glad that it is because it adheres to the structure of the current project. I might have to click - click - scroll - click - scroll - click to get there with a GUI, which isn't the greatest interaction.

Instead, I can fire up a command prompt in Sublime Text, in this case it's iconic Goto Anything command, type in something close to the file name, and find it.

Perhaps even more command-prompt-like is the literal Command Palette which is an extensible command-running menu triggered by a keyboard shortcut. Perhaps I want to run a specific Emmet command, correct syntax highlighting, or trigger an a find/replace extension to do its thing.

These things are in a similar boat as finding a file-in-a-haystack. There could be hundreds or thousands of commands. Your brain and typing fingers can find them quicker than your hand on a mouse in a UI can.

Sketch Runner

Sketch Runner is a popular plugin for Sketch that adds a command prompt to Sketch. Here's their product video:

If you think of elements and groups in a design document just like files in a code project, the "Jump anywhere" feature makes sense. It's just like "Goto Anything".

Perhaps your design document has hundreds of symbols. Your brain probably has a mental map of that that is quicker to navigate than moving your mouse through nested menus. Thus, a command prompt to type in the name (fuzzy search) and insert it.

Slack

Too many Slacks, amiright?

I don't think it would be terrible uncommon to have a dozen Slack teams, hundreds of channels, and thousands of people. Particularly if you're fond of joining "Public Slacks", like say the A11Y Slack.

Say I want to shoot a message to Sarah. I can open the Quick Switcher and just start typing her name and get there.

You have to be in the right Slack for names (or channels) to work, but you can get to the right slack via Quick Switcher and then do a new search.

Notion

Notion has a pretty awesome take on the command prompt. It's available everywhere you are in a document just by pressing the slash / key.

There are probably ~30 things you can do. The menu is nice, but being able to type what you mean quickly is even better.

In addition to searching the menu, you can just complete the word after the slash (a slash command) to do the thing.

Chrome DevTools

David Khourshid:

I've been using the command prompt in Chrome Dev Tools _so much more_ because opening the Animate tab takes like 17 clicks.

Yet another good use case!

So

There is a lot of apps doing interesting things here. I'm a fan of all of it!

Even more could probably benefit from it. Photoshop is notoriously complex, but a lot of us have familiarity with the things it can do. Seems like a perfect canidate for a fuzzy-search enabled command prompt!

Users might be able to take things into their own hands a bit here too. Alfred users could use the Menu Bar Search plugin which allows you to:

Search for and activate application menu items for the frontmost application. The workflow lists the menu items for the current application, filtering them by whatever is entered into Alfred.

Apps can easily have dozens of menu items, and this would make them all command prompt-able.

Standardization is also an interesting thing to consider. It seems some apps have followed each other. Command-Shift-P is the Sublime Text command runner, which was used by Chrome DevTools, and also by VS Code. I kinda like the Command-Space of Spotlight, but that doesn't mean web-based apps should copy it. In fact, it means they can't, because the OS would override it.

TL;DR

When UI is cumbersome or impractical, a command line makes good sense. Many apps benefit from offering both a UI and a command line, in various forms.

Apps Have Command Prompts Now is a post from CSS-Tricks

Editing the W3C HTML5 spec

Fri, 11/24/2017 - 14:53

Bruce Lawson has been tapped to co-edit the W3C HTML5 spec and, in his announcement post, clarified the difference between that and the WHATWG spec:

The WHATWG spec is a future-facing document; lots of ideas are incubated there. The W3C spec is a snapshot of what works interoperably – authors who don’t care much about what may or may not be round the corner, but who need solid advice on what works now may find this spec easier to use.

I was honestly unfamiliar with the WHATWG spec and now I find it super interesting to know there are two working groups pushing HTML forward in distinct but (somewhat) cooperative ways.

Kudos to you, Bruce! And, yes, Vive open standards!

Direct Link to ArticlePermalink

Editing the W3C HTML5 spec is a post from CSS-Tricks

On the Growing Popularity of Atomic CSS

Fri, 11/24/2017 - 14:43

Even if you consider yourself a CSS expert, chances are that at some point on a large project you've had to deal with a convoluted, labyrinthine stylesheet that never stops growing. Some stylesheets can feel like a messy entangled web of inheritance.

Spaghetti Monster

The cascade is incredibly powerful. Small changes can have large effects, making it harder to know what the immediate consequences will be. Refactoring, changing, and removing CSS is seen as risky and approached with trepidation as it's difficult to know all the places it's being used.

One thing that is often hard to articulate with new tooling is when, exactly do you start to reach for this? The answer is rarely (if ever) immediately and in all situations.

One of those situations, in my limited experience, is on large teams with large codebases. The feeling is that the CSS can get far too large and team members essentially become afraid of it, and the CSS becomes jokingly-but-accurately “append-only”.

Along comes a tool that delivers on a promise of shipping far less CSS and in a way that (after a learning curve) nobody is ever afraid of again… I can see the appeal.

- Chris Coyier

Atomic CSS keeps things simple

I no longer had to think about how to organise my CSS. I didn't have to think about what to name my 'components', where to draw the line between one component and another, what should live where, and crucially, how to refactor things when new requirements came in.

- Callum Jefferies, Takeaways from trying out Tachyons CSS after ages using BEM

Atomic CSS offers a straightforward, obvious, and simple methodology. Classes are immutable - they don't change. This makes the application of CSS predictable and reliable as classes will always do exactly the same thing. The scope of adding or removing a utility class in an HTML file is unambiguous, giving you the confidence that you aren't breaking anything else. This can reduce cognitive load and mental-overhead.

Naming components is notoriously difficult. Deciding on a class name that is both meaningful but also vague enough to be reusable is time-consuming and mentally taxing.

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton

Coming up with the appropriate abstractions is hard. Naming utility classes, by contrast, is completely straightforward.

/* naming utility classes */ .relative { position: relative; } .mt10 { margin-top: 10px; } .pb10 { padding-bottom: 10px; }

Atomic classes speak for themselves. Their intent and effect are immediately obvious. While littering HTML with countless classes may look cluttered, HTML is much easier to reason about than an impenetrably gargantuan and incomprehensible wall of tangled styles.

In a mixed-ability team, perhaps involving backend developers with limited interest and knowledge of CSS, there's less chance of people messing up the stylesheet.

Taken from ryanair.com - a whole load of CSS all doing one thing. Dealing with stylistic variation

Utility classes are perfect for dealing with small stylistic variations. While design systems and pattern libraries may be all the rage these days, what this approach recognizes is that there will continuously be new requirements and variations. All the talk about component reusability often isn't reflected in the design mocks that get passed your way. While visual and brand consistency is good, the wide variety of contexts on a large website make some variation inevitable and justified.

The Medium development team moved away from BEM modifiers, as documented on their blog.

What if we want a component to differ from another in only one single small way. If you've adopted a BEM naming convention, the modifier classes may well get out of hand - countless modifiers that often do only a single thing. Lets take margins as an example. The margins of a component are unlikely to remain universally consistent for a component. The desired spacing depends not only on the component but also its position on a page and its relation to its surrounding elements. Much of the time designs will contain similar but non-identical UI elements, which are arduous to deal with using traditional CSS.

A lot of people dislike it Aaron Gustafson, chief editor of A List Apart, former manager of the Web Standards Project, Microsoft employee. Mozilla Engineer Soledad Penades From the creator of CSS Zen Garden How is Atomic CSS different from inline styles?

This is the question always asked of atomic CSS by its critics. Inline styles have long been deemed a bad practice, rarely used since the early days of the web. Critics aren't completely wrong to equate atomic CSS to inline styles because they both suffer from the same major pain point. Here's an example: What if we want to change everything with a .black class to be navy instead? We could do this:

.black { color: navy; }

That's obviously a terrible idea.

Text editors are sophisticated things these days. It feels somewhat hazardous, but it would be simple enough to use find and replace to change all instances of the .black class with a new .navy class. The real problem is when you want to change only certain instances of .black to be .navy.

In traditional approaches to CSS, adjusting the styling of a component is as easy as updating a single value in a single class in a CSS file. With atomic CSS this becomes the tedious task of searching through every piece of HTML to update every instance of said component. However advanced code editors become, there's no getting around this. Even if you're separating your markup into reusable templates, this is still a major drawback. Perhaps this manual labour is worth it for the simplicity of this approach. Updating HTML files with different classes may be tedious but its not difficult. (Although there have been times when I have temporarily introduced stylistic inconsistency by missing certain instances of the relevant component when manually updating.) If a design changes, chances are you'll need to hand-edit classes from all over your HTML.

While atomic CSS shares inline styles big drawback, they aren't a retrograde step into the past. Utility classes are better than inline styles in all kinds of ways.

Atomic CSS vs. Inline Styles Atomic classes allow abstraction, inline styles don't

With atomic classes, it is possible to create abstractions that would be impossible with inline styles.

<p style="font-family: helvetica; color: rgb(20, 20, 20)"> Inline styles suck. </p> <p class="helvetica rgb202020"> Badly written CSS isn't very different. </p> <p class="sans-serif color-dark"> Utility classes allow for abstraction. </p>

The first two examples shown above would require a manual find-and-replace in order to update styling were the design to change. The styles in the third example can be adjusted in a single place within a stylesheet.

Tooling

Sass, Less, PostCSS, Autoprefixer… The CSS community has created a lot of useful tools that weren't available for inline styles.

Brevity

Rather than writing out verbose inline styles, atomic classes can be terse abbreviations of declarations. It's less typing: mt0 vs margin-top: 0, flex vs display: flex, etc.

Specificity

This is a contentious point. If a class or inline style only does one single thing, chances are you want it to do that thing. Some people have even advocated using !important on all utility classes to ensure they override everything else. Similarly, proponents of inline styles see its inability to be overridden (by anything other than !important) as a selling point - it means you can be sure the style will be applied. However, a class alone is specific enough to override any base style. The lower specificity of atomic classes compared to inline styles is a good thing. It allows more versatility. Were all used to changing classes on JavaScript to change styles. Inline styles make this harder.

Classes in stylesheets can do things inline styles can't

Inline styles do not support media queries, pseudo selectors, @supports, or CSS animations. Perhaps you have a single hover effect you want to apply to disparate elements rather than to only one component.

.circle { border-radius: 50%; } .hover-radius0:hover { border-radius: 0; }

Simple reusable media query rules can also be turned into a utility class. Its common to use a classname prefix for small, medium and large screen sizes. Here is an example of a flexbox class that will only apply on medium and large screen sizes:

@media (min-width: 600px) { .md-flex { display: flex; } }

This wouldn't be possible with an inline style.

Perhaps you want a reusable pseudo-content icon or label?

.with-icon::after { content: 'some icon goes here!'; } Limiting choice can be a good thing

Inline styles can be anything. This freedom could easily lead to design anarchy and inconsistency. By predefining classes for everything, atomic CSS can ensure a certain amount of stylistic consistency. Rather than ad libbing colours and values from an infinite amount of options, utility classes offer a curated set of predefined options. Developers choose from this limited set of single-purpose utility classes. This constraint can both eliminate the problem of an ever-growing stylesheet and maintain visual consistency.

Take the box-shadow as an example. An inline style will have an almost limitless amount of options for offset, spread, color, opacity and blur radius.

<div style="box-shadow: 2px 2px 2px rgba(10, 10, 250, .4)">stuff</div>

With an atomic approach, CSS authors can define the preferred style, which is then simply applied, without the possibility of stylistic inconsistency.

<div class="box-shadow">stuff</div> Atomic CSS is not all or nothing

There's no doubt that utility class frameworks like Tachyons have grown in popularity. However, CSS approaches are not mutually exclusive. There are plenty of cases where utility classes aren't the best option:

  • If you need to change a lot of styles for a particular component inside of a media query.
  • If you want to change multiple styles with JavaScript, it's easier to abstract that into a single class.

Utility classes can coexist with other approaches. Its probably a good idea to define base styles and sane defaults globally. If you keep duplicating the same long string of utility classes, chances are the styles should be abstracted into a single class. You can mix in component classes, but do so only when you know they will be reused.

Taking a component-first approach to CSS means you create components for things even if they will never get reused. This premature abstraction is the source of a lot of bloat and complexity in stylesheets.

- Adam Wathan

The smaller the unit, the more reusable it is.

- Thierry Koblentz

Looking at the newest release of Bootstrap, a whole host of utility classes is now offered, while still including its traditional components. Increasingly, popular frameworks are taking this mixed approach.

On the Growing Popularity of Atomic CSS is a post from CSS-Tricks

Declining Complexity in CSS

Wed, 11/22/2017 - 20:00

The fourth edition of Eric Meyer and Estelle Weyl's CSS: The Definitive Guide was recently released. The new book weighs in at 1,016 pages, which is up drastically from 447 in the third edition, which was up slightly from 436 in the second edition.

Despite the appearance of CSS needing more pages to capture more complicated concepts, Eric suggests that CSS is actually easier to grasp than ever before and its complexity has actually declined between editions:

But the core principles and mechanisms are no more complicated than they were a decade or even two decades ago. If anything, they’re easier to grasp now, because we don’t have to clutter our minds with float behaviors or inline layout just to try to lay out a page. Flexbox and Grid (chapters 12 and 13, by the way) make layout so much simpler than ever before, while simultaneously providing far more capability than ever before.

In short, yes, lots of new concepts have been introduced since 2007 when the third edition was released, but they're solving the need to use layout, err, tricks to make properties bend in ways they were never intended:

It’s still an apparent upward trend, but think about all the new features that have come out since the 3rd Edition, or are coming out right now: gradients, multiple backgrounds, sticky positioning, flexbox, Grid, blending, filters, transforms, animation, and media queries, among others. A lot of really substantial capabilities. They don’t make CSS more convoluted, but instead extend it into new territories.

Hear, hear! Onward and upward, no matter how many pages it takes.

Direct Link to ArticlePermalink

Declining Complexity in CSS is a post from CSS-Tricks

Save 15% or More on Car Insurance by Switching to Plain JavaScript

Wed, 11/22/2017 - 16:34

Satire disclaimer: This article is as much satire as it is serious insight if there is even any of that at all. Don’t take it too seriously, but do tell all your friends. Also, the bit about Taco Bell is 100% true. I wouldn’t joke about something like that.

My day usually begins like this: I wake up at 6:15 a.m. (kill me) to get the kids ready for school. They’re mad. I’m mad. Everyone is on the brink of an emotional breakdown because it's 6:15 in the morning.

Usually the first thing that I do when I wake up is roll out of bed and start hammering out pushups like Christian Bale.

BWAHAHAHA. No.

Before I’m even fully awake and out of bed, I grab my phone and look at Twitter. It’s a sickness, I know. I’m not proud of it but at least I’m out here admitting that I have a problem and I believe according to the rules of science that fully negates my problem and makes me better than you.

One morning a few weeks ago I wake up to this tweet…

Removing client-side React.js (but keeping it on the server) resulted in a 50% performance improvement on our landing page pic.twitter.com/vM7JhWhYKu

— Netflix UI Engineers (@NetflixUIE) October 26, 2017

The wonderful thing about Twitter is that there is essentially zero context for anything you see, which means your crazy brain gets to fill in all the holes and, in my case, that’s a recipe for utter disaster.

Here is how I read this tweet….

Heavily doctored by me. My Photoshop skills are a huge embarrassing failure.

I believe my brain read it that way because that’s literally what the original tweet says. My brain just adds the “Your whole life is a lie” part to pretty much everything I read or hear.

Your Whole Life is a Lie

This immediately dumped me into an existential crisis.

To be fair, I’m almost constantly in a state of crisis so it’s not like this was a big leap for me. Just last night at Taco Bell I had to choose between the Beefy 5-layer Burrito and the Cheesy Gordita Crunch and I almost came apart in the drive through. You can’t force decisions like that on people and expect an immediate response! And why do I need 50 packets of Fire sauce!?!

The point is that I’m kind of emotionally fragile as it is, so you can’t suggest to me that you got rid of React because all of a sudden people just don’t need it anymore.

I had so, so, so many. questions like:

  • What about binding?
  • What about components?
  • What about state?
  • What about templates?

You’re telling me that all of a sudden you just don’t need any of that stuff anymore? One does not simply “move to plain JavaScript” by removing React from their project. If you actually did that you would just be moving from React to your own version of React. Facebook could say that their site is built in “plain JavaScript” too. They just decided to name some of that JavaScript “React" in the process.

It was nonsensical. You might as well have said that you saved 15% on car insurance by moving to plain JavaScript. Thankfully, I only had to wait 6 agonizing days before Jake Archibald took to the blogs to clear everything up.

&#x1f4dd; Netflix "removed" React and improved performance.
➡️ Despite appearances, this reflects well on React.https://t.co/R8SohrLX6q

— Jake Archibald (@jaffathecake) October 31, 2017

THIS IS NOT HELPING, JAKE! I’M LOSING IT OVER HERE!

The post goes on to explain that Netflix is actually deferring client-side React until it’s needed and going with server rendered React in the meantime. He also points out that it’s only logical that it would be faster because the browser is doing less work. Netflix is apparently loading client-side React in the background. It’s there when you need it, but you don’t have to parse it if you don’t.

I decided to check this out and see for myself what is going on.

Netflix Login

One of the places Jake mentions that server-side React is appropriate is on the login screen. So let’s start there. I loaded the login screen and it looks to me like client-side React is still every much in effect here.

As an aside, Netflix is great at naming things. I mean, look at these components—AkiraLayout, JawboneLinkProvider, FreezedWrapper? OK, FreezedWrapper isn’t that exciting but you can’t take AkiraLayout from me.

So I can’t find where React has been removed. The login page itself comes in at around 194KB and that’s before it loads the loginController.jsx file which bumps it up another 204KB.

I then did what I should have done the first time which is to watch the video from Netflix that was responsible for this descent into the depths of my insecurity and I noticed that they only mentioned the splash page.

The splash page is just netflix.com. No login. No videos. The splash page. That slide? The one that made it’s way all over the internet and into my therapy sessions? That slide is referring only to the splash page. Netflix did remove React from their splash page and replace the few interactions they had with plain JavaScript.

And there is your context. So let’s fix the slide again…

That is the actual story here.

It’s unfortunate that we latch on to a single slide taken completely out of context. This is not the fault of Netflix. Or maybe it is. I mean, they did tweet it out but, look, this is really the fault of 2017. This is how all of the news in our lives plays out.

What’s super unfortunate here, and what Jake was trying to convey in his post, is that we completely missed some actual cool things that Netflix is doing. Mainly the combination of server-side React and Prefetching. Or rather the idea that more complex code can be downloaded and parsed in the background instead of when the page loads.

Prefetching is Not a Solved Problem

We tend to forget that things like prefetching are not necessarily a solved problem. While Service Workers are awesome, Netflix can’t use them because the support is too sparse. Beyond that, the browser Prefetching API is flaky. In that same presentation, Netflix reports that the API (which is just the link tag) has a success rate as low as a 30%. That means your prefetch will only work about a third of the time in some cases. &#x1f633;

The reason for this is that the API is trying to make a bunch of decisions about whether or not it should prefetch depending on your device and resources. It’s not a guarantee that your resources will be loaded at all.

What’s most remarkable to me is that Netflix hit on another solution that is so simple it hurts: just make an AJAX call and don’t do anything with the result; the browser will cache that resource.

MY GOODNESS I LOVE THE WEB!

You Uh, Still Need React

So yes, you still need React on the client-side. Netflix is still using it and never said that they were not.

What they did say was that they had figured out some creative ways to make the experience better for the user and had combined that with their current React implementation. This should be exciting to you if you’re a React developer.

Maybe Netflix will open source some library for prefetching with a way cool name. Is "fakenews.js” taken?

Special Thanks to Brian Holt who reviewed this article and was still willing to be my friend.

Save 15% or More on Car Insurance by Switching to Plain JavaScript is a post from CSS-Tricks

HTML Email and Accessibility

Wed, 11/22/2017 - 14:40

You love HTML emails, don't you?

As a developer, probably not... but subscribers absolutely do. They devour them, consume them on every device known to man, and drive a hell of a lot of revenue for companies that take their email marketing seriously.

But most web developers tasked with building HTML emails merely want to get them out the door as quickly as possible and move on to more interesting assignments. Despite email's perennial value for subscribers, tight timelines, and a general loathing of the work result in things falling by the wayside; and, just like in the web world, one of the first things to be set aside in email is accessibility.

I think we all agree that accessibility is a vital topic. Unfortunately, it's one that's ignored in the email marketing world even more than on the web.

Accessibility in email doesn't have to consume a lot of time, though. There are a few simple practices you can build into your own campaigns that will make your emails more accessible and your subscribers even happier.

Accessible Tables?

One of the main reasons that web developers hate building emails is that we're still stuck using tables for layout in email. Although there are a few different ways to get around using HTML tables, most emails still rely on them to ensure that emails look good in Microsoft Outlook, which doesn't support more traditional CSS positioning, let alone newer CSS layout techniques like Grid (although that's possible in email, too).

But HTML tables present a hurdle for users relying on screen readers for consuming their emails. This is made clear when you hear the output of a screen reader working through the typical HTML email campaign. Mark Robbins of Rebel posted an excellent example of this behavior a while back.

The screen reader is doing it's job: it sees a table, assumes that it contains tabular data, and reads it appropriately.

However, since we're using tables purely for structural purposes, we need screen readers to ignore those tables. This is where ARIA roles can help us out. By applying the role="presentation" attribute to a table, we can instruct the screen reader to skip over those elements and move straight into the content.

See the Pen Accessible Emails - Tables ARIA Presentation by Jason Rodriguez (@rodriguezcommaj) on CodePen.

With that one simple addition, our emails are much more accessible. It should be noted that nested tables don't inherit this behavior, so you will have to apply role="presentation" individually to every table in your campaign. Creating a snippet or building this into your email boilerplate is a good way to ensure accessibility without having to even think about it.

Out of the Image and Into the Code

A common practice in email marketing is to use images for everything in the email: graphics, illustrations, copy, links, and buttons. Although this can be efficient (slice, dice, and send it on its way), it's another huge problem for subscribers relying on screen readers. The typical image-based email has a lot of information that can't be parsed by a machine. What's more is that a lot of email clients disable images by default, too. Ever see something like this?

An example of image-blocking behavior in Microsoft Outlook.

We want to avoid or improve situations where content can't be seen by users or content can't be read by a screen reader. There are two ways to do this.

The first is to rely less on images and more on HTML to convey your message. Pull copy out of your images and put it into your email as real, live text.

HTML text vs. image-blocking. Lyft does this really well.

HTML text isn't susceptible to image blocking in email clients, so it will always be shown. Further, most copy that's typically found within an email can be converted to HTML text. You can style that text however you want, even using web fonts, and your content can be seen by users and understood by screen readers.

This is especially important when it comes to links and buttons in emails. A lot of designers will rely on images for buttons since they can style those buttons however they want. However, those image-based buttons are victims of the same image-blocking behavior as any other image. Using HTML, CSS, and, in some cases, Microsoft's proprietary VML language, you can create code-based buttons that display everywhere and still fit in with your design.

See the Pen Accessible Emails - Bulletproof Buttons by Jason Rodriguez (@rodriguezcommaj) on CodePen.

The second is to rely on alternative text for images. By adding the alt attribute, we can describe the content of images for screen readers so that users get some context and a better understanding of the email.

The same rules apply in email as on the web:

  1. All images should have an alt attribute
  2. Alternative text should present the content and function of an image
  3. Alternative text should never be redundant
  4. Alternative text relies heavily on the context provided by the content surrounding an image
  5. Decorative images should use an empty alt attribute

A simple example of alternative text in an email would be for something like a retail sale.

See the Pen Accessible Emails - Styled ALT Text by Jason Rodriguez (@rodriguezcommaj) on CodePen.

On top of making our emails more accessible, we can actually style that alternative text so that it better fits in with the rest of our email design when images are disabled. Using things like color, font-family, font-size, font-weight, and line-height allows you to style alternative text in largely the same way you would any other text in the email. Combined with something like background-color on the image, these styles make it possible to have highly-optimized—and accessible—emails for when images are disabled.

Styled alternative text keeps emails accessible and on-brand. It's All Semantics

Despite what some email marketers and developers will tell you, semantics in email do matter. Not only do they provide accessible hooks for navigating an email, they can provide fallback styles that help maintain the hierarchy of emails in the unfortunate event CSS isn't loaded or supported.

It used to be that all text styling was done on table cells within a campaign, with any copy being a direct descendant of that table cell.

See the Pen Accessible Emails - Old Text Approach by Jason Rodriguez (@rodriguezcommaj) on CodePen.

Email developers would avoid using semantic elements like headings and paragraphs because email clients (correctly) displayed their own default styling of those elements, which sometimes resulted in broken layouts or unintended designs. I don't know if it was sheer laziness or something else, but very few developers would use semantic elements with simple overrides to keep their designs accessible and consistent across clients.

Adding the margin property on block-level semantic elements—and relying on style inheritance from the table cell—can create more accessible emails that display properly nearly everywhere.

See the Pen Accessible Emails - Semantic Text Approach by Jason Rodriguez (@rodriguezcommaj) on CodePen.

You don't have to stop at simple headings or paragraphs, either. You can use sectioning elements like main, header, footer, article and more to provide extra semantic value to your emails. I would caution you to use them on top of your existing table-based structure, though. Not all email clients support styles being applied to those elements, so something like this is a good approach:

See the Pen Accessible Emails - Semantic Article by Jason Rodriguez (@rodriguezcommaj) on CodePen.

Designing for Subscribers

The last technique I want to discuss—although not the last technique available to us—is adhering to tried-and-true design principles within our campaigns to keep them accessible.

Accessibility isn't all about screen readers. Subscribers can have visual impairments as well as physical or cognitive disabilities that make consuming emails difficult, especially when an email's design hasn't been updated in years. By relying on design principles like hierarchy, space, pattern, proximity, type size, and contrast, we can ensure that a broad spectrum of subscribers can understand and enjoy our email campaigns.

This is especially apparent when it comes to viewing emails on mobile devices. If you're not taking the mobile view into account from the outset, or using responsive email design, then your desktop-first email campaigns can be a pain to use when scaled down on most mobile email clients.

Trello uses large visuals, type, and buttons to keep things readable and usable across all device sizes.

Simply revisiting your designs with mobile and disabled users in mind can go a long way to keeping your emails accessible. Using larger type that's legible for a wide variety of users, combined with proper heading styles and a hierarchy that is easy to scan is a great baseline. Adding in repeatable patterns within your emails that further aid scanning and understanding, along with plenty of white space and properly contrasting colors take your emails even further.

I encourage you to use tools like Chrome Lighthouse and Accessible-Colors.com to check the accessibility of your HTML email designs. It's all HTML and CSS, so the same tools that work on the web work on email as well. Use them!

Have Your Own Tips?

Although a lot of email development is stuck in the past, that doesn't mean we can't modernize our campaigns right along with our websites. Many of these tips can be baked right into your email boilerplate or code snippets, allowing you to create more accessible HTML emails without too much thought.

At the same time, don't let that stop you from putting that extra thought into your emails. This article merely scrapes the surface of what's possible in HTML email development. I'd love to hear about your tips for building accessible emails in the comments below.

HTML Email and Accessibility is a post from CSS-Tricks

Styleable

Tue, 11/21/2017 - 17:43

The Wix dev team throws their hat into the CSS preprocessor ring:

Stylable is a CSS preprocessor that enables you to write reusable, highly-performant, styled components. Each component exposes a style API that maps its internal parts so you can reuse components across teams without sacrificing stylability.

  • Scopes styles to components so they don’t “leak” and clash with other styles.
  • Enables custom pseudo-classes and pseudo-elements that abstract the internal structure of a component. These can then be styled externally.
  • Uses themes so you can apply different look and feel across your web application.

At build time, the preprocessor converts the Stylable CSS into flat, static, valid, vanilla CSS that works cross-browser.

Looks like Sass luminary Chris Eppstein is getting in on the game of scoped styles with the not-yet-released CSS Blocks. And think of Vue's support for <style scoped>, and the popularity of utility libraries. I think scoped styles might be the hottest CSS topic in 2018.

Direct Link to ArticlePermalink

Styleable is a post from CSS-Tricks

Advocating for Accessible UI Design

Tue, 11/21/2017 - 14:05

Accessibility is a hot topic these days, and the older we web-makers get, the hotter it's going to become! That might be a snarky outlook, but what I'm trying to say is that it's about time we start designing the web for everyone because the web was meant to be for everyone, and less and less are we able to predict where, when, and how our work will be consumed.

Accessibility is not just up to developers

As developers, we often encounter accessibility post-design, when we do things like implementating the correct role and aria attributes, ensuring navigation is keyboard friendly, and responsibly hiding elements. In general, our accessibility efforts go towards thinking about how to make specific components and features accessible, such as an SVG icon system or helpful tool-tips.

Given our roles as developers, this makes sense. Accessibility flaws, however, often originate in the UI design itself, and depending on our work environment, we developers don't necessarily have the authority or bandwidth to advocate for accessibility in the designs we are handed.

For example, let's say you are tasked with turning a Sketch file into a one-page WordPress site.

The design has finally been approved by the client, and now you have a weekend to build the thing, plus another two days to work with QA to perfect it. As you take a look at the design for the first time, you notice that, on small devices, the dainty serif typeface overlaid on a background image would be difficult for low-sighted visitors to read.

You, the accessibility-minded developer, could proceed in a few ways:

  1. Remain silent and sate your accessibility conscience by making accessible choices in the code where you can
  2. Go ahead and make accessibility improvements to the UI as you develop, present them in the finished product, and explain yourself after
  3. Compile a list of suggested changes to send to the designer and request they be implemented in the mockups so you can then develop them

I was in a situation like this recently and, judge me if you will, I chose number one.

If I'd had the time and the guts, number 2 would've gotten me the furthest, but given the nature of my role as a first-time contractor at this high-speed agency I was hoping to develop a working relationship with, I felt I'd be overstepping my bounds and wasn't ready to take the risk of being too vocal out of the gate. I chose not to do number 3 for similar reasons, mainly for fear of causing more work and stress for the already extremely busy designer.

Now that I have the benefit of hindsight, however, might I add a fourth item to the list?

  1. Send a succinct list of non-technical accessibility tips for UI design to everyone on the team so they make more accessible design choices in future

Where to find such a list? Well, you are in luck! Read on!

Non-technical Accessibility Tips for UI Design

What follows is a list of plain language, no-jargon, "Accessibility Tips for UI Design" you, developer, can share with everyone at work: UI designers, content providers, project managers, and clients alike. The more we can spread awareness about accessibility and think critically about the mockups we are handed to implement, the more accessible the web will be!

I have chosen the examples below from various trendy website feeds, and I used the fantastic Funkify Chrome Extension to simulate the viewing experience of site visitors with varying abilities and disabilities.

First up:

Easy on the animations.

With great power comes great responsibility. The modern web affords us the power to bounce-in, fly-in, or drop-in any content we please, but besides the wow factor, how are these animations contributing to a reader's experience on your site? How are the animations triggered? Can they be mistakenly triggered, causing a confusing jolt in the flow of your site visitor's experience?

Take this example of a car repair company's website. I've applied the "Elderly Ellen" filter from Funkify to simulate slightly blurred vision and shaky hands:

Elderly Ellen's trembling hands cause a jarring experience with bold animations.

If I were Ellen, this experience would likely steer me away from Service King's services! Someone like Elderly Ellen is constantly frustrated with technology. It's unnecessary to cause her that stress when she's trying to read about a service for repairing her car after an already traumatizing fender bender.

Make sure background and text colors have enough contrast.

Although that medium grey text looks just right on that light grey background, it's hard to read...and impossible to read if you are working out in the sunshine (not a common occurance, but I've done it before). Here's an example of the aforementioned grey-on-grey scenario:

The medium grey text color of these icons' captions does not contrast enough with the light grey background color.

And now, the same example affected by the "Sunshine Sue" filter from Funkify deems our low contrast captions simply invisible!

And now, simulating sunshine on a screen, the text is completely gone!

The solution? Run your color choices through the WebAIM contrast checker to see if they meet standards for readability and color contrast, and if they don't, adjust the color values until they do.

The Funkify extension can be used to test anything that is visible in a browser. Even if a design mock isn't yet implemented in code, an image or PDF can be opened in the browser and the extension will still work!

Be very careful when overlaying text on images, or don't.

It might look just right to have that dainty serif overlaid on the big header image, but can you read it if you slightly blur your vision? If not, up the contrast between the text and image, perhaps by brightening the text color and increasing the transparency of the image on a dark background.

On Burberry's website, for example, the user must select from a drop-down in order to enter the site, but the text identifying the drop-down is barely readable over top the background image. There are many ways to solve this from a design standpoint, but for a quick example, we could add a dark background beneath the light text to provide a bit more contrast:

Adding a contrasting background beneath the text overlaid on an image can help with readability.

Similarly, while the delicate descriptive text below the image on Tesla's new Semi website is delicate and beautiful, it is barely legiible when simulating slightly blurred vision with "Blurry Bianca":

The descriptive text overlaid on the bottom of this image is barely legible when simulating slightly blurred vision. Double-check the readability of font weights and sizes.

The thinner the font weight and the smaller the size, the harder it is to read. Even I, as a hearing, well-sighted individual, find myself zooming in on body text at times because it is so darn lightweight and small, even if the color contrast is up to speed. If you must stick with the lightweight font, increasing the sizes and line height can do wonders as well.

I like to ask myself, does it pass the slightly-cross-eye test? That is when I slightly cross my eyes, can I still make out the text?

Some contrast, line-height, and font-size adjustments make for a more readable text in a disclaimer we are supposed to read. Indicate external links.

If it is a requirement for a link to open in a new tab, first question whether it should be a requirement, then indicate it visually with a small icon or note in the UI.

Additionally, designers can make a note in their designs where there should be screen-reader-only text indicating the link will navigate the user away from their current viewing portal. This was brought to mind by way of some excellent replies to a Twitter conversation; read through that here.

Differentiate between action-oriented social media links vs. profile links.

When we see small social media icons, I think the general assumption is that they link to the relevant social media profiles. Sometimes, however, these icons are actually actions that, rather than linking to a profile, open a "New Tweet" dialog or similar. These actions should be marked as such.

Don't rely 100% on icons and colors to communicate.

It's easy to assume everyone knows that a hamburger icon indicates a menu or that everyone is familiar with the various versions of LinkedIn's icon. However, this is not the case, and it causes a moment of confusion and insult that isn't necessary to site visitors that are less in-the-know than we are. Especially if your audience tends to be older and/or less tech-savvy, make sure you aren't relying on what you think is common knowledge.

Reliance on colors for meaning causes a similar issue, and more-so for any users that deal with color blindness. A recent Smashing Magazine article covers this problem in detail and uses the example of a color picker on shoe sales website that, for color-blind users, results in an entirely different palette.

What would the design look like without interactivity?

If all a user could do was scroll, does the content still make sense? Are there areas where, rather than hiding the thumbnail caption under a fancy hover event, the caption could be plainly visible instead? What about on a touch screen, where hover events are treated quite differently?

What else?

Have you encountered issues with accessibility in designs you've implemented? How did you handle it? What other tips can we give designers and producers for creating more accessible UI designs?

The first step to advocating for accessible UI design is to simply think twice about what you, the developer, are told to implement. While coding up a design, try applying a few of these Funkify filters and see what results they yield. Think critically about the designs you are handed, and start a conversation with your coworkers.

Advocating for Accessible UI Design is a post from CSS-Tricks

Happier HTML5 Form Validation

Mon, 11/20/2017 - 23:58

HTML has given us loads of form validation stuff in the last few years. Dave Rupert puts a point on the UX problems with it:

If you’ve ever experimented with HTML5 Form Validation, you’ve probably been disappointed. The out-of-box experience isn’t quite what you want. Adding the required attribute to inputs works wonderfully. However the styling portion with input:invalid sorta sucks because empty inputs are trigger the :invalid state, even before the user has interacted with the page.

Fortunately, there is an invalid DOM event that does fire with useful timing: when the form is submitted. Remember this doesn't buy you super deep browser support though. If you need that, look into polyfilling. I imagine the future of form validation is either HTML/CSS offering better and more controllable UX, or this.

Direct Link to ArticlePermalink

Happier HTML5 Form Validation is a post from CSS-Tricks

Airplanes and Ashtrays

Mon, 11/20/2017 - 23:53

Harry Roberts wrote about design systems and how compromise has to be baked into them from the very start. He argues that we can’t be dictatorial about what is and isn’t permitted because design, whether that’s the design of a product, service or system, is always about compromise.

Harry writes:

Whenever you plan or design a system, you need to build in your own ashtrays—a codified way of dealing with the inevitability of somebody doing the wrong thing. Think of what your ideal scenario is—how do you want people to use whatever you’re building—and then try to identify any aspects of it which may be overly opinionated, prescriptive, or restrictive. Then try to preempt how people might try to avoid or circumvent these rules, and work back from there until you can design a safe middle-ground into your framework that can accept these deviations in the safest, least destructive way possible.

Direct Link to ArticlePermalink

Airplanes and Ashtrays is a post from CSS-Tricks

Live Share / Teletype

Mon, 11/20/2017 - 18:57

Amanda Silver introduces "Visual Studio Live Share", which:

enables developers using Visual Studio 2017 or Visual Studio Code to collaborate in real-time!

This goes a bit deeper than just a multiple-cursors thing. Both people get all the same fancy VS code UI stuff like IntelliSense and Peek.

GitHub's Atom editor also has Teletype, which:

lets developers share their workspace with team members and collaborate on code in real time.

Atom has the concept of a host, in which:

As the host moves between files, collaborators follow along with the active tab automatically.

I'd be remiss not to mention CodePen has Collab Mode and Professor Mode, which require zero setup. Shoot someone a URL and go!

Direct Link to ArticlePermalink

Live Share / Teletype is a post from CSS-Tricks

Recreating the Apple Watch Breathe App Animation

Mon, 11/20/2017 - 14:04

The Apple Watch comes with a stock app called Breathe that reminds you to, um, breathe. There's actually more to it than that, but the thought of needing a reminder to breathe makes me giggle. The point is, the app has this kinda awesome interface with a nice animation.

Photo courtesy of Apple Support

I thought it would be fun to recreate the design in vanilla CSS. Here's how far I got, which feels pretty close.

See the Pen Apple Watch Breathe App Animation by Geoff Graham (@geoffgraham) on CodePen.

Making the circles

First things first, we need a set of circles that make up that flower looking design. The app itself adds a circle to the layout for each minute that is added to the timer, but we're going to stick with a static set of six for this demo. It feels like we could get tricky by using ::before and ::after to reduce the HTML markup, but we can keep it simple.

<div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div>

We're going to make the full size of each circle 125px which is an arbitrary number. The important thing is that the default state of the circles should be all of them stacked on top of one another. We can use absolute positioning to do that.

.circle { border-radius: 50%; height: 125px; position: absolute; transform: translate(0, 0); width: 125px; }

Note that we're using the translate function of the transform property to center everything. I had originally tried using basic top, right, bottom, left properties but found later that animating translate is much smoother. I also originally thought that positioning the circles in the full expanded state would be the best place to start, but also found that the animations were cumbersome to create that way because it required resetting each one to center. Lessons learned!

If we were to stop here, there would be nothing on the screen and that's because we have not set a background color. We'll get to the nice fancy colors used in the app in a bit, but it might be helpful to add a white background for now with a hint of opacity to help see what's happening as we work.

See the Pen Apple Watch Breathe App - Step 1 by Geoff Graham (@geoffgraham) on CodePen.

We need a container!

You may have noticed that our circles are nicely stacked, but nowhere near the actual center of the viewport. We're going to need to wrap these bad boys in a parent element that we can use to position the entire bunch. Plus, that container will serve as the element that pulses and rotates the entire set later. That was another lesson I had to learn the hard way because I stubbornly did not want the extra markup of a container and thought I could work around it.

We're calling the container .watch-face here and setting it to the same width and height as a single circle.

<div class="watch-face"> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> </div>

Now, we can add a little flex to the body element to center everything up.

body { background: #000; display: flex; align-items: center; justify-content: center; height: 100vh; }

See the Pen Apple Watch Breathe App - Step 2 by Geoff Graham (@geoffgraham) on CodePen.

Next up, animate the circles

At this point, I was eager to see the circles positioned in that neat floral, overlapping arrangement. I knew that it would be difficult to animate the exact position of each circle without seeing them positioned first, so I overrode the transform property in each circle to see where they'd land.

We could set up a class for each circle, but using :nth-child seems easier.

.circle:nth-child(1) { transform: translate(-35px, -50px); } /* Skipping 2-5 for brevity... */ .circle:nth-child(6) { transform: translate(35px, 50px); }

It took me a few swings and misses to find coordinates that worked. It ultimately depends on the size of the circles and it may take some finessing.

See the Pen Apple Watch Breathe App - Step 3 by Geoff Graham (@geoffgraham) on CodePen.

Armed with the coordinates, we can register the animations. I removed the transform coordinates that were applied to each :nth-child and moved them into keyframes:

@keyframes circle-1 { 0% { transform: translate(0, 0); } 100% { transform: translate(-35px, -50px); } } /* And so on... */

I have to admit that the way I went about it feels super clunky because each circle has it's own animation. It would be slicker to have one animation that can rule them all to push and re-center the circles, but maybe someone else reading has an idea and can share it in the comments.

Now we can apply those animations to each :nth-child in place of transform:

.circle:nth-child(1) { animation: circle-1 4s ease alternate infinite; } /* And so on... */

Note that we set the animation-timing-function to ease because that feels smooth...at least to me! We also set the animation-direction to alternate so it plays back and forth and set the animation-iteration-count to inifinite so it stays running.

See the Pen Apple Watch Breathe App - Step 4 by Geoff Graham (@geoffgraham) on CodePen.

Color, color, color!

Oh yeah, let's paint this in! From what I can tell, there are really only two colors in the design and the opacity is what makes it feel like more of a spectrum.

The circles on the left are a greenish color and the ones on the right are sorta blue. We can select the odd-numbered circles to apply the green and the even-numbered ones to apply the blue.

.circle:nth-child(odd) { background: #61bea2; } .circle:nth-child(even) { background: #529ca0; }

Oh, and don't forget to remove the white background from the .circle element. It won't hurt anything, but it's nice to clean up after ourselves. I admittedly forgot to do this on the first go.

See the Pen Apple Watch Breathe App - Step 5 by Geoff Graham (@geoffgraham) on CodePen.

Pulse and rotate

Remember that pesky .watch-face container we created? Well, we can animate it to pulse the circles in and out while rotating the entire bunch.

I had totally forgotten that transform functions can be chained together. That makes things a little cleaner because it allows us to apply scale() and rotate() on the same line.

@keyframes pulse { 0% { transform: scale(.15) rotate(180deg); } 100% { transform: scale(1); } }

...and apply that to the .watch-face element.

.watch-face { height: 125px; width: 125px; animation: pulse 4s cubic-bezier(0.5, 0, 0.5, 1) alternate infinite; }

Like the circles, we want the animation to run both ways and repeat infinitely. In this case, the scale drops to a super small size as the circles stack on top of each other and the whole thing rotates halfway on the way out before returning back on the way in.

I'll admit that I am not a buff when it comes to finding the right animation-timing-function for the smoothest or exact animations. I played with cubic-bezier and found something I think feels pretty good, but it's possible that a stock value like ease-in would work just as well.

All together now!

Here's everything smushed into the same demo.

See the Pen Apple Watch Breathe App Animation by Geoff Graham (@geoffgraham) on CodePen.

Now, just remember to breathe and let's all have a peaceful day. ☮️

Recreating the Apple Watch Breathe App Animation is a post from CSS-Tricks

Simple Patterns for Separation (Better Than Color Alone)

Sat, 11/18/2017 - 21:55

Color is pretty good for separating things. That's what your basic pie chart is, isn't it? You tell the slices apart by color. With enough color contrast, you might be OK, but you might be even better off (particularly where accessibility is concerned) using patterns, or a combination.

Patrick Dillon tackled the Pie Chart thing

Enhancing Charts With SVG Patterns:

When one of the slices is filled with something more than color, it's easier to figure out [who the Independents are]:

See the Pen Political Party Affiliation - #2 by Patrick Dillon (@pdillon) on CodePen.

Filling a pie slice with a pattern is not a common charting library feature (yet), but if your library of choice is SVG-based, you are free to implement SVG patterns.

As in, literally a <pattern /> in SVG!

Here's a simple one for horizontal lines:

<pattern id="horzLines" width="8" height="4" patternUnits="userSpaceOnUse"> <line x1="0" y1="0" x2="8" y2="0" style="stroke:#999;stroke-width:1.5" /> </pattern>

Now any SVG element can use that pattern as a fill. Even strokes. Here's an example of mixed usage of two simple patterns:

See the Pen Simple Line Patterns by Chris Coyier (@chriscoyier) on CodePen.

That's nice for filling SVG elements, but what about HTML elements?

Irene Ros created Pattern Fills that are SVG based, but usable in CSS also.

Using SVG Patterns as Fills:

There are several ways to use Pattern Fills:

  • You can use the patterns.css file that contains all the current patterns. That will only work for non-SVG elements.

  • You can use individual patterns, but copying them from the sample pages. CSS class definitions can be found here and SVG pattern defs can be found here

  • You can add your own patterns or modify mine! The conversion process from SVG document to pattern is very tedious. The purpose of the pattern fills toolchain is to simplify this process. You can clone the repo, run npm install and grunt dev to get a local server going. After that, any changes or additions to the src/patterns/**/* files will be automatically picked up and will re-render the CSS file and the sample pages. If you make new patterns, send them over in a pull request!

Here's me applying them to SVG elements (but could just as easily be applied to HTML elements):

See the Pen Practical Patterns by Chris Coyier (@chriscoyier) on CodePen.

The CSS usage is as base64 data URLs though, so once they are there they aren't super duper manageable/changeable.

Here's Irene with an old timey chart, using d3:

Managing an SVG pattern in CSS

If your URL encode the SVG just right, you and plop it right into CSS and have it remain fairly managable.

See the Pen Simple Line Patterns by Chris Coyier (@chriscoyier) on CodePen.

Other Examples Combining Color

Here's one by John Schulz:

See the Pen SVG Colored Patterns by Chris Coyier (@chriscoyier) on CodePen.

Ricardo Marimón has an example creating the pattern in d3. The pattern looks largely the same on the slices, but perhaps it's a start to modify.

Other Pattern Sources

We rounded a bunch of them up recently!

Simple Patterns for Separation (Better Than Color Alone) is a post from CSS-Tricks

How to Disable Links

Fri, 11/17/2017 - 15:17

The topic of disabling links popped up at my work the other day. Somehow, a "disabled" anchor style was added to our typography styles last year when I wasn't looking. There is a problem though: there is no real way to disable an <a> link (with a valid href attribute) in HTML. Not to mention, why would you even want to? Links are the basis of the web.

At a certain point, it looked like my co-workers were not going to accept this fact, so I started thinking of how this could be accomplished. Knowing that it would take a lot, I wanted to prove that it was not worth the effort and code to support such an unconventional interaction, but I feared that by showing it could be done they would ignore all my warnings and just use my example as proof that it was OK. This hasn't quite shaken out for me yet, but I figured we could go through my research.

First, things first:

Just don't do it.

A disabled link is not a link, it's just text. You need to rethink your design if it calls for disabling a link.

Bootstrap has examples of applying the .disabled class to anchor tags, and I hate them for it. At least they mention that the class only provides a disabled style, but this is misleading. You need to do more than just make a link look disabled if you really want to disable it.

Surefire way: remove the href

If you have decided that you are going to ignore my warning and proceed with disabling a link, then removing the href attribute is the best way I know how.

Straight from the official Hyperlink spec:

The href attribute on a and area elements is not required; when those elements do not have href attributes they do not create hyperlinks.

An easier to understand definition from MDN:

This attribute may be omitted (as of HTML5) to create a placeholder link. A placeholder link resembles a traditional hyperlink, but does not lead anywhere.

Here is basic JavaScript code to set and remove the href attribute:

/* * Use your preferred method of targeting a link * * document.getElementById('MyLink'); * document.querySelector('.link-class'); * document.querySelector('[href="https://unfetteredthoughts.net"]'); */ // "Disable" link by removing the href property link.href = ''; // Enable link by setting the href property link.href = 'https://unfetteredthoughts.net';

Styling this via CSS is also pretty straightforward:

a { /* Disabled link styles */ } a:link, a:visited { /* or a[href] */ /* Enabled link styles */ }

That's all you need to do!

That's not enough, I want something more complex so that I can look smarter!

If you just absolutely have to over-engineer some extreme solution, here are some things to consider. Hopefully, you will take heed and recognize that what I am about to show you is not worth the effort.

First, we need to style our link so that it looks disabled.

.isDisabled { color: currentColor; cursor: not-allowed; opacity: 0.5; text-decoration: none; } <a class="isDisabled" href="https://unfetteredthoughts.net">Disabled Link</a>

Setting color to currentColor should reset the font color back to your normal, non-link text color. I am also setting the mouse cursor to not-allowed to display a nice indicator on hover that the normal action is not allowed. Already, we have left out non-mouse users that can't hover, mainly touch and keyboard, so they won't get this indication. Next the opacity is cut to half. According to WCAG, disabled elements do not need to meet color contrast guidelines. I think this is very risky since it's basically plain text at this point, and dropping the opacity in half would make it very hard to read for users with low-vision, another reason I hate this. Lastly, the text decoration underline is removed as this is usually the best indicator something is a link. Now this looks like a disabled link!

But it's not really disabled! A user can still click/tap on this link. I hear you screaming about pointer-events.

.isDisabled { ... pointer-events: none; }

Ok, we are done! Disabled link accomplished! Except, it's only really disabled for mouse users clicking and touch users tapping. What about browsers that don't support pointer-events? According to caniuse, this is not supported for Opera Mini and IE<11. IE11 and Edge actually don't support pointer-events unless display is set to block or inline-block. Also, setting pointer-events to none overwrites our nice not-allowed cursor, so now mouse users will not get that additional visual indication that the link is disabled. This is already starting to fall apart. Now we have to change our markup and CSS...

.isDisabled { cursor: not-allowed; opacity: 0.5; } .isDisabled > a { color: currentColor; display: inline-block; /* For IE11/ MS Edge bug */ pointer-events: none; text-decoration: none; } <span class="isDisabled"><a href="https://unfetteredthoughts.net">Disabled Link</a></span>

Wrapping the link in a <span> and adding the isDisabled class gives us half of our disabled visual style. A nice side-affect here is that the disabled class is now generic and can be used on other elements, like buttons and form elements. The actual anchor tag now has the pointer-events and text-decoration set to none.

What about keyboard users? Keyboard users will use the ENTER key to activate links. pointer-events are only for pointers, there is no keyboard-events. We also need to prevent activation for older browsers that don't support pointer-events. Now we have to introduce some JavaScript.

Bring in the JavaScript // After using preferred method to target link link.addEventListener('click', function (event) { if (this.parentElement.classList.contains('isDisabled')) { event.preventDefault(); } });

Now our link looks disabled and does not respond to activation via clicks, taps, and the ENTER key. But we are still not done! Screen reader users have no way of knowing that this link is disabled. We need to describe this link as being disabled. The disabled attribute is not valid on links, but we can use aria-disabled="true".

<span class="isDisabled"><a href="https://unfetteredthoughts.net" aria-disabled="true">Disabled Link</a></span>

Now I am going to take this opportunity to style the link based on the aria-disabled attribute. I like using ARIA attributes as hooks for CSS because having improperly styled elements is an indicator that important accessibility is missing.

.isDisabled { cursor: not-allowed; opacity: 0.5; } a[aria-disabled="true"] { color: currentColor; display: inline-block; /* For IE11/ MS Edge bug */ pointer-events: none; text-decoration: none; }

Now our links look disabled, act disabled, and are described as disabled.

Unfortunately, even though the link is described as disabled, some screen readers (JAWS) will still announce this as clickable. It does that for any element that has a click listener. This is because of developer tendency to make non-interactive elements like div and span as pseudo-interactive elements with a simple listener. Nothing we can do about that here. Everything we have done to remove any indication that this is a link is foiled by the assistive technology we were trying to fool, ironically because we have tried to fool it before.

But what if we moved the listener to the body?

document.body.addEventListener('click', function (event) { // filter out clicks on any other elements if (event.target.nodeName == 'A' && event.target.getAttribute('aria-disabled') == 'true') { event.preventDefault(); } });

Are we done? Well, not really. At some point we will need to enable these links so we need to add additional code that will toggle this state/behavior.

function disableLink(link) { // 1. Add isDisabled class to parent span link.parentElement.classList.add('isDisabled'); // 2. Store href so we can add it later link.setAttribute('data-href', link.href); // 3. Remove href link.href = ''; // 4. Set aria-disabled to 'true' link.setAttribute('aria-disabled', 'true'); } function enableLink(link) { // 1. Remove 'isDisabled' class from parent span link.parentElement.classList.remove('isDisabled'); // 2. Set href link.href = link.getAttribute('data-href'); // 3. Remove 'aria-disabled', better than setting to false link.removeAttribute('aria-disabled'); }

That's it. We now have a disabled link that is visually, functionally, and semantically disabled for all users. It only took 10 lines of CSS, 15 lines of JavaScript (including 1 listener on the body), and 2 HTML elements.

Seriously folks, just don't do it.

How to Disable Links is a post from CSS-Tricks

4 Reasons to Go PRO on CodePen

Thu, 11/16/2017 - 22:33

I could probably list about 100 reasons, since as a founder, user, and (ahem) PRO member of CodePen myself, I'm motivated to do so. But let me just list a few here. Some of these are my favorites, some are what PRO members have told us are their favorite, and some are lesser-known but very awesome.

1) No-hassle Debug View

Debug View is a way to look at your the Pen you've built with zero CodePen UI around it and no <iframe> containing it. Raw output! That's a dangerous thing, in the world of user-generated code. It could be highly abused if we let it go unchecked. The way it works is fairly simple.

You can use Debug View if :

  1. You're logged in
  2. The Pen is PRO-owned

Logging in isn't too big of a deal, but sometimes that's a pain if you just wanna shoot over a Debug View URL to your phone or to CrossBrowserTesting or something. If you're PRO, you don't worry about it at all, Debug View is totally unlocked for your Pens.

2) Collab with anybody anytime

Collab Mode on CodePen is the one that's like Google Docs: people can work together in real time on the same Pen. You type, they see you type, they type, you see what they type.

Here's what is special about that:

  • There is nothing to install or set up, just shoot anybody a link.
  • Only you need to be PRO. Nobody else does. They don't even have to be logged in.

Basically, you can be coding together with someone (or just one or the other of you watching, if you please) in about 2 seconds. Here's a short silent video if you wanna see:

People use it for all sorts of things. In classrooms and educational contexts, for hiring interviews, and just for working out problems with people across the globe.

Drag and drop uploading

Need to quickly host an asset (like an image) somewhere? As in, quickly get a URL for it that you can use and count on forever? It's as easy as can be on CodePen.

If you're working on a Project, you can drag and drop files right into the sidebar as well:

Save Anything Privately

Privacy is unlimited on CodePen. If you're PRO, you can make unlimited Private Pens and Private Collections. You're only limited in Private Projects by the total number of Projects on your plan. This is the number one PRO feature on CodePen for a variety of reasons. People use them to keep client work safe. People use them to experiment without anyone seeing messy tidbits. People use them to keep in-progress ideas.

I didn't even mention my actual favorite CodePen PRO feature. I'll have to share that one some other time ;)

Go PRO on CodePen

4 Reasons to Go PRO on CodePen is a post from CSS-Tricks

SVG as a Placeholder

Thu, 11/16/2017 - 20:58

It wasn't long ago when Mikael Ainalem's Pen demonstrated how you might use SVG outlines in HTML then lazyload the image (later turned into a webpack loader by Emil Tholin). It's kind of like a skeleton screen, in that it gives the user a hint of what's coming. Or the blur up technique, which loads a very small image blurrily blown up as the placeholder image.

José M. Pérez documents those, plus some more basic options (nothing, an image placeholder, or a solid color), and best of all, a very clever new idea using Primitive (of which there is a mac app and JavaScript version), which creates overlapping SVG shapes to use as the placeholder image. Probably a bit bigger-in-size than some of the other techniques, but still much smaller than a high res JPG!

Direct Link to ArticlePermalink

SVG as a Placeholder is a post from CSS-Tricks

Accessible Web Apps with React, TypeScript, and AllyJS

Thu, 11/16/2017 - 15:21

Accessibility is an aspect of web development that is often overlooked. I would argue that it is as vital as overall performance and code reusability. We justify our endless pursuit of better performance and responsive design by citing the users, but ultimately these pursuits are done with the user's device in mind, not the user themselves and their potential disabilities or restrictions.

A responsive app should be one that delivers its content based on the needs of the user, not only their device.

Luckily, there are tools to help alleviate the learning curve of accessibility-minded development. For example, GitHub recently released their accessibility error scanner, AccessibilityJS and Deque has aXe. This article will focus on a different one: Ally.js, a library simplifying certain accessibility features, functions, and behaviors.

One of the most common pain points regarding accessibility is dialog windows.

There're a lot of considerations to take in terms of communicating to the user about the dialog itself, ensuring ease of access to its content, and returning to the dialog's trigger upon close.

A demo on the Ally.js website addresses this challenge which helped me port its logic to my current project which uses React and TypeScript. This post will walk through building an accessible dialog component.

Demo of accessible dialog window using Ally.js within React and TypeScript

View the live demo

Project Setup with create-react-app

Before getting into the use of Ally.js, let's take a look at the initial setup of the project. The project can be cloned from GitHub or you can follow along manually. The project was initiated using create-react-app in the terminal with the following options:

create-react-app my-app --scripts-version=react-scripts-ts

This created a project using React and ReactDOM version 15.6.1 along with their corresponding @types.

With the project created, let's go ahead and take a look at the package file and project scaffolding I am using for this demo.

Project architecture and package.json file

As you can see in the image above, there are several additional packages installed but for this post we will ignore those related to testing and focus on the primary two, ally.js and babel-polyfill.

Let's install both of these packages via our terminal.

yarn add ally.js --dev && yarn add babel-polyfill --dev

For now, let's leave `/src/index.tsx` alone and hop straight into our App container.

App Container

The App container will handle our state that we use to toggle the dialog window. Now, this could also be handled by Redux but that will be excluded in lieu of brevity.

Let's first define the state and toggle method.

interface AppState { showDialog: boolean; } class App extends React.Component<{}, AppState> { state: AppState; constructor(props: {}) { super(props); this.state = { showDialog: false }; } toggleDialog() { this.setState({ showDialog: !this.state.showDialog }); } }

The above gets us started with our state and the method we will use to toggle the dialog. Next would be to create an outline for our render method.

class App extends React.Component<{}, AppState> { ... render() { return ( <div className="site-container"> <header> <h1>Ally.js with React &amp; Typescript</h1> </header> <main className="content-container"> <div className="field-container"> <label htmlFor="name-field">Name:</label> <input type="text" id="name-field" placeholder="Enter your name" /> </div> <div className="field-container"> <label htmlFor="food-field">Favourite Food:</label> <input type="text" id="food-field" placeholder="Enter your favourite food" /> </div> <div className="field-container"> <button className='btn primary' tabIndex={0} title='Open Dialog' onClick={() => this.toggleDialog()} > Open Dialog </button> </div> </main> </div> ); } }

Don't worry much about the styles and class names at this point. These elements can be styled as you see fit. However, feel free to clone the GitHub repo for the full styles.

At this point we should have a basic form on our page with a button that when clicked toggles our showDialog state value. This can be confirmed by using React's Developer Tools.

So let's now have the dialog window toggle as well with the button. For this let's create a new Dialog component.

Dialog Component

Let's look at the structure of our Dialog component which will act as a wrapper of whatever content (children) we pass into it.

interface Props { children: object; title: string; description: string; close(): void; } class Dialog extends React.Component<Props> { dialog: HTMLElement | null; render() { return ( <div role="dialog" tabIndex={0} className="popup-outer-container" aria-hidden={false} aria-labelledby="dialog-title" aria-describedby="dialog-description" ref={(popup) => { this.dialog = popup; } } > <h5 id="dialog-title" className="is-visually-hidden" > {this.props.title} </h5> <p id="dialog-description" className="is-visually-hidden" > {this.props.description} </p> <div className="popup-inner-container"> <button className="close-icon" title="Close Dialog" onClick={() => { this.props.close(); }} > × </button> {this.props.children} </div> </div> ); } }

We begin this component by creating the Props interface. This will allow us to pass in the dialog's title and description, two important pieces for accessibility. We will also pass in a close method, which will refer back to the toggleDialog method from the App container. Lastly, we create the functional ref to the newly created dialog window to be used later.

The following styles can be applied to create the dialog window appearance.

.popup-outer-container { align-items: center; background: rgba(0, 0, 0, 0.2); display: flex; height: 100vh; justify-content: center; padding: 10px; position: absolute; width: 100%; z-index: 10; } .popup-inner-container { background: #fff; border-radius: 4px; box-shadow: 0px 0px 10px 3px rgba(119, 119, 119, 0.35); max-width: 750px; padding: 10px; position: relative; width: 100%; } .popup-inner-container:focus-within { outline: -webkit-focus-ring-color auto 2px; } .close-icon { background: transparent; color: #6e6e6e; cursor: pointer; font: 2rem/1 sans-serif; position: absolute; right: 20px; top: 1rem; }

Now, let's tie this together with the App container and then get into Ally.js to make this dialog window more accessible.

App Container

Back in the App container, let's add a check inside of the render method so any time the showDialog state updates, the Dialog component is toggled.

class App extends React.Component<{}, AppState> { ... checkForDialog() { if (this.state.showDialog) { return this.getDialog(); } else { return false; } } getDialog() { return ( <Dialog title="Favourite Holiday Dialog" description="Add your favourite holiday to the list" close={() => { this.toggleDialog(); }} > <form className="dialog-content"> <header> <h1 id="dialog-title">Holiday Entry</h1> <p id="dialog-description">Please enter your favourite holiday.</p> </header> <section> <div className="field-container"> <label htmlFor="within-dialog">Favourite Holiday</label> <input id="within-dialog" /> </div> </section> <footer> <div className="btns-container"> <Button type="primary" clickHandler={() => { this.toggleDialog(); }} msg="Save" /> </div> </footer> </form> </Dialog> ); } render() { return ( <div className="site-container"> {this.checkForDialog()} ... ); } }

What we've done here is add the methods checkForDialog and getDialog.

Inside of the render method, which runs any time the state updates, there is a call to run checkForDialog. So upon clicking the button, the showDialog state will update, causing a re-render, calling checkForDialog again. Only now, showDialog is true, triggering getDialog. This method returns the Dialog component we just built to be rendered onto the screen.

The above sample includes a Button component that has not been shown.

Now, we should have the ability to open and close our dialog. So let's take a look at what problems exist in terms of accessibility and how we can address them using Ally.js.

Using only your keyboard, open the dialog window and try to enter text into the form. You'll notice that you must tab through the entire document to reach the elements within the dialog. This is a less-than-ideal experience. When the dialog opens, our focus should be the dialog  -  not the content behind it. So let's look at our first use of Ally.js to begin remedying this issue.

Ally.js

Ally.js is a library providing various modules to help simplify common accessibility challenges. We will be using four of these modules for the Dialog component.

The .popup-outer-container acts as a mask that lays over the page blocking interaction from the mouse. However, elements behind this mask are still accessible via keyboard, which should be disallowed. To do this the first Ally module we'll incorporate is maintain/disabled. This is used to disable any set of elements from being focussed via keyboard, essentially making them inert.

Unfortunately, implementing Ally.js into a project with TypeScript isn't as straightforward as other libraries. This is due to Ally.js not providing a dedicated set of TypeScript definitions. But no worries, as we can declare our own modules via TypeScript's types files.

In the original screenshot showing the scaffolding of the project, we see a directory called types. Let's create that and inside create a file called `global.d.ts`.

Inside of this file let's declare our first Ally.js module from the esm/ directory which provides ES6 modules but with the contents of each compiled to ES5. These are recommended when using build tools.

declare module 'ally.js/esm/maintain/disabled';

With this module now declared in our global types file, let's head back into the Dialog component to begin implementing the functionality.

Dialog Component

We will be adding all the accessibility functionality for the Dialog to its component to keep it self-contained. Let's first import our newly declared module at the top of the file.

import Disabled from 'ally.js/esm/maintain/disabled';

The goal of using this module will be once the Dialog component mounts, everything on the page will be disabled while filtering out the dialog itself.

So let's use the componentDidMount lifecycle hook for attaching any Ally.js functionality.

interface Handle { disengage(): void; } class Dialog extends React.Component<Props, {}> { dialog: HTMLElement | null; disabledHandle: Handle; componentDidMount() { this.disabledHandle = Disabled({ filter: this.dialog, }); } componentWillUnmount() { this.disabledHandle.disengage(); } ... }

When the component mounts, we store the Disabled functionality to the newly created component property disableHandle. Because there are no defined types yet for Ally.js we can create a generic Handle interface containing the disengage function property. We will be using this Handle again for other Ally modules, hence keeping it generic.

By using the filter property of the Disabled import, we're able to tell Ally.js to disable everything in the document except for our dialog reference.

Lastly, whenever the component unmounts we want to remove this behaviour. So inside of the componentWillUnmount hook, we disengage() the disableHandle.

We will now follow this same process for the final steps of improving the Dialog component. We will use the additional Ally modules:

  • maintain/tab-focus
  • query/first-tabbable
  • when/key

Let's update the `global.d.ts` file so it declares these additional modules.

declare module 'ally.js/esm/maintain/disabled'; declare module 'ally.js/esm/maintain/tab-focus'; declare module 'ally.js/esm/query/first-tabbable'; declare module 'ally.js/esm/when/key';

As well as import them all into the Dialog component.

import Disabled from 'ally.js/esm/maintain/disabled'; import TabFocus from 'ally.js/esm/maintain/tab-focus'; import FirstTab from 'ally.js/esm/query/first-tabbable'; import Key from 'ally.js/esm/when/key'; Tab Focus

After disabling the document with the exception of our dialog, we now need to restrict tabbing access further. Currently, upon tabbing to the last element in the dialog, pressing tab again will begin moving focus to the browser's UI (such as the address bar). Instead, we want to leverage tab-focus to ensure the tab key will reset to the beginning of the dialog, not jump to the window.

class Dialog extends React.Component<Props> { dialog: HTMLElement | null; disabledHandle: Handle; focusHandle: Handle; componentDidMount() { this.disabledHandle = Disabled({ filter: this.dialog, }); this.focusHandle = TabFocus({ context: this.dialog, }); } componentWillUnmount() { this.disabledHandle.disengage(); this.focusHandle.disengage(); } ... }

We follow the same process here as we did for the disabled module. Let's create a focusHandle property which will assume the value of the TabFocus module import. We define the context to be the active dialog reference on mount and then disengage() this behaviour, again, when the component unmounts.

At this point, with a dialog window open, hitting tab should cycle through the elements within the dialog itself.

Now, wouldn't it be nice if the first element of our dialog was already focused upon opening?

First Tab Focus

Leveraging the first-tabbable module, we are able to set focus to the first element of the dialog window whenever it mounts.

class Dialog extends React.Component<Props> { dialog: HTMLElement | null; disabledHandle: Handle; focusHandle: Handle; componentDidMount() { this.disabledHandle = Disabled({ filter: this.dialog, }); this.focusHandle = TabFocus({ context: this.dialog, }); let element = FirstTab({ context: this.dialog, defaultToContext: true, }); element.focus(); } ... }

Within the componentDidMount hook, we create the element variable and assign it to our FirstTab import. This will return the first tabbable element within the context that we provide. Once that element is returned, calling element.focus() will apply focus automatically.

Now, that we have the behavior within the dialog working pretty well, we want to improve keyboard accessibility. As a strict laptop user myself (no external mouse, monitor, or any peripherals) I tend to instinctively press esc whenever I want to close any dialog or popup. Normally, I would write my own event listener to handle this behavior but Ally.js provides the when/key module to simplify this process as well.

class Dialog extends React.Component<Props> { dialog: HTMLElement | null; disabledHandle: Handle; focusHandle: Handle; keyHandle: Handle; componentDidMount() { this.disabledHandle = Disabled({ filter: this.dialog, }); this.focusHandle = TabFocus({ context: this.dialog, }); let element = FirstTab({ context: this.dialog, defaultToContext: true, }); element.focus(); this.keyHandle = Key({ escape: () => { this.props.close(); }, }); } componentWillUnmount() { this.disabledHandle.disengage(); this.focusHandle.disengage(); this.keyHandle.disengage(); } ... }

Again, we provide a Handle property to our class which will allow us to easily bind the esc functionality on mount and then disengage() it on unmount. And like that, we're now able to easily close our dialog via the keyboard without necessarily having to tab to a specific close button.

Lastly (whew!), upon closing the dialog window, the user's focus should return to the element that triggered it. In this case, the Show Dialog button in the App container. This isn't built into Ally.js but a recommended best practice that, as you'll see, can be added in with little hassle.

class Dialog extends React.Component<Props> { dialog: HTMLElement | null; disabledHandle: Handle; focusHandle: Handle; keyHandle: Handle; focusedElementBeforeDialogOpened: HTMLInputElement | HTMLButtonElement; componentDidMount() { if (document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLButtonElement) { this.focusedElementBeforeDialogOpened = document.activeElement; } this.disabledHandle = Disabled({ filter: this.dialog, }); this.focusHandle = TabFocus({ context: this.dialog, }); let element = FirstTab({ context: this.dialog, defaultToContext: true, }); this.keyHandle = Key({ escape: () => { this.props.close(); }, }); element.focus(); } componentWillUnmount() { this.disabledHandle.disengage(); this.focusHandle.disengage(); this.keyHandle.disengage(); this.focusedElementBeforeDialogOpened.focus(); } ... }

What has been done here is a property, focusedElementBeforeDialogOpened, has been added to our class. Whenever the component mounts, we store the current activeElement within the document to this property.

It's important to do this before we disable the entire document or else document.activeElement will return null.

Then, like we had done with setting focus to the first element in the dialog, we will use the .focus() method of our stored element on componentWillUnmount to apply focus to the original button upon closing the dialog. This functionality has been wrapped in a type guard to ensure the element supports the focus() method.

Now, that our Dialog component is working, accessible, and self-contained we are ready to build our App. Except, running yarn test or yarn build will result in an error. Something to this effect:

[path]/node_modules/ally.js/esm/maintain/disabled.js:21 import nodeArray from '../util/node-array'; ^^^^^^ SyntaxError: Unexpected token import

Despite Create React App and its test runner, Jest, supporting ES6 modules, an issue is still caused with the ESM declared modules. So this brings us to our final step of integrating Ally.js with React, and that is the babel-polyfill package.

All the way in the beginning of this post (literally, ages ago!), I showed additional packages to install, the second of which being babel-polyfill. With this installed, let's head to our app's entry point, in this case ./src/index.tsx.

Index.tsx

At the very top of this file, let's import babel-polyfill. This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool.

import 'babel-polyfill';

With that, we can return to our terminal to run the test and build scripts from create-react-app without any error.

Demo of accessible dialog window using Ally.js within React and TypeScript

View the live demo

Now that Ally.js is incorporated into your React and TypeScript project, more steps can be taken to ensure your content can be consumed by all users, not just all of their devices.

For more information on accessibility and other great resources please visit these resources:

Accessible Web Apps with React, TypeScript, and AllyJS is a post from CSS-Tricks

Aspect Ratios for Grid Items

Wed, 11/15/2017 - 16:22

We've covered Aspect Ratio Boxes before. It involves trickery with padding such that an element's width and height are in proportion to your liking. It's not an ultra-common need, since fixing an element's height is asking for trouble, but it comes up.

One way to lower the risk is The Psuedo Element Tactic, in which a pseudo element pushes its parent element to the aspect ratio, but if the content inside pushes it taller, it will get taller, aspect ratio be damned.

You can use that technique in CSS grid with grid items! Although there are a couple of different ways to apply it that are worth thinking about.

Remember that grid areas and the element that occupy them aren't necessarily the same size.

We just covered this. That article started as a section in this article but felt important enough to break off into its own concept.

Knowing this, it leads to: do you need the grid area to have an aspect ratio, and the element will stretch within? Or does the element just need an aspect ratio regardless of the grid area it is in?

Scenario 1) Just the element inside needs to have an aspect ratio.

Cool. This is arguably easier. Make sure the element is 100% as wide as the grid area, then apply a pseudo element to handle the height-stretching aspect ratio.

<div class="grid"> <div style="--aspect-ratio: 2/1;">2/1</div> <div style="--aspect-ratio: 3/1;">3/1</div> <div style="--aspect-ratio: 1/1;">1/1</div> </div> .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; place-items: start; } .grid > * { background: orange; width: 100%; } .grid > [style^='--aspect-ratio']::before { content: ""; display: inline-block; width: 1px; height: 0; padding-bottom: calc(100% / (var(--aspect-ratio))); }

Which leads to this:

Note that you don't need to apply aspect ratios through custom properties necessarily. You can see where the padding-bottom is doing the heavy lifting and that value could be hard-coded or whatever else.

Scenario 2) Span as many columns as needed for width

I bet it's more likely that what you are needing is a way to make a, say 2-to-1 aspect ratio element, to actually span two columns, not be trapped in one. Doing this is a lot like what we just did above, but adding in rules to do that column spanning.

[style="--aspect-ratio: 1/1;"] { grid-column: span 1; } [style="--aspect-ratio: 2/1;"] { grid-column: span 2; } [style="--aspect-ratio: 3/1;"] { grid-column: span 3; }

If we toss grid-auto-flow: dense; in there too, we can get items with a variety of aspect ratios packing in nicely as they see fit.

Now is a good time to mention there little ways to screw up exact aspect ratios here. The line-height on some text might push a box taller than you want. If you want to use grid-gap, that might throw ratios out of whack. If you need to get super exact with the ratios, you might have more luck hard-coding values.

Doing column spanning also gets tricky if you're in a grid that doesn't have a set number of rows. Perhaps you're doing a repeat/auto-fill thing. You might end up in a scenario with unequal columns that won't be friendly to aspect ratios. Perhaps we can dive into that another time.

Scenario 3) Force stuff

Grid has a two-dimensional layout capability and, if we like, we could get our aspect ratios just by forcing the grid areas to the height and width we want. For instance, nothing is stopping you from hard-coding heights and widths into columns and rows:

.grid { display: grid; grid-template-columns: 200px 100px 100px; grid-template-rows: 100px 200px 300px; }

We normally don't think that way, because we want elements to be flexible and fluid, hence the percentage-based techniques used above for aspect ratios. Still, it's a thing you can do.

See the Pen Aspect Ratio Boxes Filling by Chris Coyier (@chriscoyier) on CodePen.

This example forces grid areas to be the size they are and the elements stretch to fill, but you could fix the element sizes as well.

Real world example

Ben Goshow wrote to me trying to pull this off, which is what spurred this:

Part of the issue there was not only getting the boxes to have aspect ratios, but then having alignment ability inside. There are a couple of ways to approach that, but I'd argue the easiest way is nested grids. Make the grid element dispaly: grid; and use the alignment capabilities of that new internal grid.

See the Pen CSS Grid Items with Aspect Ratio and Internal Alignment by Chris Coyier (@chriscoyier) on CodePen.

Note in this demo instead of spanning rows, the elements are explicitly placed (not required, an example alternative layout method).

Aspect Ratios for Grid Items is a post from CSS-Tricks

Pages