Archiwum kategorii: CSS

Form Validation Part 1: Constraint Validation in HTML

Post pobrano z: Form Validation Part 1: Constraint Validation in HTML

Most JavaScript form validation libraries are large, and often require other libraries like jQuery. For example, MailChimp’s embeddable form includes a 140kb validation file (minified). It includes the entire jQuery library, a third-party form validation plugin, and some custom MailChimp code. In fact, that setup is what inspired this new series about modern form validation. What new tools do we have these days for form validation? What is possible? What is still needed?

In this series, I’m going to show you two lightweight ways to validate forms on the front end. Both take advantage of newer web APIs. I’m also going to teach you how to push browser support for these APIs back to IE9 (which provides you with coverage for 99.6% of all web traffic worldwide).

Finally, we’ll take a look at MailChimp’s sign-up form, and provide the same experience with 28× (2,800%) less code.

It’s worth mentioning that front-end form validation can be bypassed. You should always validate your code on the server, too.

Alright, let’s get started!

Article Series:

  1. Constraint Validation in HTML (You are here!)
  2. The Constraint Validation API in JavaScript (Coming Soon!)
  3. A Validity State API Polyfil (Coming Soon!)l
  4. Validating the MailChimp Subscribe Form (Coming Soon!)

The Incredibly Easy Way: Constraint Validation

Through a combination of semantic input types (for example, <input type="email">) and validation attributes (such as required and pattern), browsers can natively validate form inputs and alert users when they’re doing it wrong.

Support for the various input types and attributes varies wildly from browser to browser, but I’ll provide some tricks and workarounds to maximize browser compatibility.

Basic Text Validation

Let’s say you have a text field that is required for a user to fill out before the form can be submitted. Add the required attribute, and supporting browsers will both alert users who don’t fill it out and refuse to let them submit the form.

<input type="text" required>
A required text input in Chrome.

Do you need the response to be a minimum or maximum number of characters? Use minlength and maxlength to enforce those rules. This example requires a value to be between 3 and 12 characters in length.

<input type="text" minlength="3" maxlength="12">
Error message for the wrong number of characters in Firefox.

The pattern attribute let’s you run regex validations against input values. If you, for example, required passwords to contain at least 1 uppercase character, 1 lowercase character, and 1 number, the browser can validate that for you.

<input type="password" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$" required>
Wrong format error message in Safari.
Wrong format error message in Safari.

If you provide a title attribute with the pattern, the title value will be included with any error message if the pattern doesn’t match.

<input type="password" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$" title="Please include at least 1 uppercase character, 1 lowercase character, and 1 number." required>
Wrong format message in Opera, with title text explaining RegEx.

You can even combine it with minlength and (as seems to be the case with banks, maxlength) to enforce a minimum or maximum length.

<input type="password" minlength="8" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$" title="Please include at least 1 uppercase character, 1 lowercase character, and 1 number." required>

See the Pen Form Validation: Basic Text by Chris Ferdinandi (@cferdinandi) on CodePen.

Validating Numbers

The number input type only accepts numbers. Browsers will either refuse to accept letters and other characters, or alert users if they use them. Browser support for input[type="number"] varies, but you can supply a pattern as a fallback.

<input type="number" pattern="[-+]?[0-9]">

By default, the number input type allows only whole numbers.

You can allow floats (numbers with decimals) with the step attribute. This tells the browser what numeric interval to accept. It can be any numeric value (example, 0.1 ), or any if you want to allow any number.

You should also modify your pattern to allow decimals.

<input type="number" step="any" pattern="[-+]?[0-9]*[.,]?[0-9]+">

If the numbers should value between a set of values, the browser can validate those with the min and max attributes. You should also modify your pattern to match. For example, if a number has to be between 3 and 42, you would do this:

<input type="number" min="3" max="42" pattern="[3-42]">

See the Pen Form Validation: Numbers by Chris Ferdinandi (@cferdinandi) on CodePen.

Validating Email Addresses and URLs

The email input type will alert users if the supplied email address is invalid. Like with the number input type, you should supply a pattern for browsers that don’t support this input type.

Email validation regex patterns are a hotly debated issue. I tested a ton of them specifically looking for ones that met RFC822 specs. The one used below, by Richard Willis, was the best one I found.

<input type="email" pattern="^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$">

One „gotcha” with the the email input type is that it allows email addresses without a TLD (the „example.com” part of „email@example.com”). This is because RFC822, the standard for email addresses, allows for localhost emails which don’t need one.

If you want to require a TLD (and you likely do), you can modify the pattern to force a domain extension like so:

<input type="email" title="The domain portion of the email address is invalid (the portion after the @)." pattern="^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*(\.\w{2,})+$">

Similarly, the url input type will alert users if the supplied value is not a valid URL. Once again, you should supply a pattern for browsers that don’t support this input type. The one included below was adapted from a project by Diego Perini, and is the most robust I’ve encountered.

<input type="url" pattern="^(?:(?:https?|HTTPS?|ftp|FTP):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)(?:\.(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)*)(?::\d{2,5})?(?:[\/?#]\S*)?$">

Like the email attribute, url does not require a TLD. If you don’t want to allow for localhost URLs, you can update the pattern to check for a TLD, like this.

<input type="url" title="The URL is a missing a TLD (for example, .com)." pattern="^(?:(?:https?|HTTPS?|ftp|FTP):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)(?:\.(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)*(?:\.(?:[a-zA-Z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$">

See the Pen Form Validation: Email & URLs by Chris Ferdinandi (@cferdinandi) on CodePen.

Validating Dates

There are a few really awesome input types that not only validate dates but also provide native date pickers. Unfortunately, Chrome and Mobile Safari are the only two browsers that implement it. (I’ve been waiting years for Firefox to adopt this feature!) Other browsers just display it as a text field.

As always, we can provide a pattern to catch browsers that don’t support it.
The date input type is for standard day/month/year dates.

<input type="date" pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))">

In supporting browsers, the selected date is displayed like this: MM/DD/YYYY. But the value is actually in this format: YYYY-MM-DD.

You should provide guidance to users of unsupported browsers about this format—something like, „Please use the YYYY-MM-DD format.” However, you don’t want people visiting with Chrome or Mobile Safari to see this since that’s not the format they’ll see, which is confusing.

See the Pen Form Validation: Dates by Chris Ferdinandi (@cferdinandi) on CodePen.

A Simple Feature Test

We can write a simple feature test to check for support, though. We’ll create an input[type="date"] element, add a value that’s not a valid date, and then see if the browser sanitizes it or not. You can then hide the descriptive text for browsers that support the date input type.

<label for="date">Date <span class="description-date">YYYY-MM-DDD</span></label>
<input type="date" id="date" pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))">

<script>
  var isDateSupported = function () {
      var input = document.createElement('input');
      var value = 'a';
      input.setAttribute('type', 'date');
      input.setAttribute('value', value);
      return (input.value !== value);
  };

  if (isDateSupported()) {
      document.documentElement.className += ' supports-date';
  }
</scipt>

<style>
  .supports-date .description-date {
      display: none;
  }
</style>

See the Pen Form Validation: Dates with a Feature Test by Chris Ferdinandi (@cferdinandi) on CodePen.

Other Date Types

The time input type let’s visitors select a time, while the month input type let’s them choose from a month/year picker. Once again, we’ll include a pattern for non-supporting browsers.

<input type="time" pattern="(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9])">
<input type="month" pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2]))">

The time input displays time in 12-hour am/pm format, but the value is 24-hour military time. The month input is displayed as May 2017 in supporting browsers, but the value is in YYYY-MM format.

Just like with input[type="date"], you should provide a pattern description that’s hidden in supporting browsers.

See the Pen Form Validation: Add `novalidate` programatically by Chris Ferdinandi (@cferdinandi) on CodePen.

This seems super easy. What’s the catch?

While the Constraint Validation API is easy and light-weight, it does have some drawbacks.

You can style fields that have errors on them with the :invalid pseudo-selector, but you can’t style the error messages themselves.

Behavior is also inconsistent across browsers. Chrome doesn’t display any errors until you try to submit the form. Firefox displays a red border when the field loses focus, but only displays error messages on hover (whereas WebKit browsers keep the errors persistent).

User studies from Christian Holst and Luke Wroblewski (separately) found that displaying an error when the user leaves a field, and keeping that error persistent until the issue is fixed, provided the best and fastest user experience. Bonus CSS tip: style invalid selectors only when they arern’t currently being edited with :not(:focus):invalid { }.

Unfortunately, none of the browsers behave exactly this way by default.

In the next article in this series, I’ll show you how to use the native Constraint Validation API to bolt-in our desired UX with some lightweight JavaScript. No third-party library required!

Article Series:

  1. Constraint Validation in HTML (You are here!)
  2. The Constraint Validation API in JavaScript (Coming Soon!)
  3. A Validity State API Polyfil (Coming Soon!)l
  4. Validating the MailChimp Subscribe Form (Coming Soon!)

Form Validation Part 1: Constraint Validation in HTML is a post from CSS-Tricks

Stickybits: an alternative to `position: sticky` polyfills

Post pobrano z: Stickybits: an alternative to `position: sticky` polyfills

Stickybits is a small JavaScript utility plugin. It’s goal is not to get in the way. It does one thing well: help with sticky elements. It is not dependent on other JavaScript Plugins, can be imported via npm, and approaches sticky elements in a very utility-oriented way.

Solving the sticky element problem can lead to sticky situations

When navigating sites, it is common to see HTML elements, like banners and navigations, sticking to the top and bottom of the browser. There are a couple of ways that can be done.

One, there is position: sticky, a native CSS feature. You might use it something like this:

header {
  position: sticky;
  top: -1px;
}

MDN explains it well:

Sticky positioning is a hybrid of relative and fixed positioning. The element is treated as relative positioned until it crosses a specified threshold, at which point it is treated as fixed positioned.

Two, you can essentially fake that behavior with JavaScript. You measure scroll positions and flip-flop the element between position: relative (or static or anything else) and position: fixed as needed.

I’d say that neither of these techniques are quite ideal.

By doing the flip-flopping yourself, there may be jumpiness when these elements go from fixed position to not. This issues is worsened in mobile device browsers.

With native CSS alone, you don’t have the ability to know when the element is in one state or the other.

Get the best of both worlds with StickyBits

Stickybits a lightweight (~2KB) alternative to position: sticky polyfills. It is an easy to set up plugin that is cross-compatible with any other plugins, libraries, or frameworks.

Installation with npm:

npm i stickybits --save-dev

Or, installation with Yarn:

yarn add stickybits --dev

Usage:

stickybits('[your-sticky-selector]');

With the out-of-the-box solution above, you now have set any element with your selector to be sticky. This will work for browsers that support .classList whether position: sticky is supported or not.

Stickybits, with the additional useStickyClasses: true property set will add sticky and stuck classes when elements become sticky or stuck. This makes it easy to hook up CSS styles based on when the selected element become static, sticky or stuck. This useful utility was added after Dave Rupert mentioned it on the Shop Talk Show Podcast.

Stickybits also supplies offset properties and a clean-up method hook to help better manage its sticky state.

Demos

See the Pen Njwpep by Jeff Wainwright (@yowainwright) on CodePen.

See the Pen CSS `position: sticky` example by Jeff Wainwright (@yowainwright) on CodePen.

More demos provided on GitHub.

Conclusion

Stickybits is a JavaScript Plugin for making an HTML element stick to the top or bottom of a browser window within its parent. With the varying implementations of position: fixed; and position: sticky; across browsers, making high quality sticky features is challenging. Stickybits solves this.

Stickybits was inspired by FixedSticky from Fillament Group, who has recently deprecated their plugin.

It is open-sourced by Dollar Shave Club and maintained by our team and I.


Stickybits: an alternative to `position: sticky` polyfills is a post from CSS-Tricks

Reactive UI’s with VanillaJS – Part 2: Class Based Components

Post pobrano z: Reactive UI’s with VanillaJS – Part 2: Class Based Components

In Part 1, I went over various functional-style techniques for cleanly rendering HTML given some JavaScript data. We broke our UI up into component functions, each of which returned a chunk of markup as a function of some data. We then composed these into views that could be reconstructed from new data by making a single function call.

This is the bonus round. In this post, the aim will be to get as close as possible to full-blown, class-based React Component syntax, with VanillaJS (i.e. using native JavaScript with no libraries/frameworks). I want to make a disclaimer that some of the techniques here are not super practical, but I think they’ll still make a fun and interesting exploration of how far JavaScript has come in recent years, and what exactly React does for us.

Article Series:

  1. Pure Functional Style
  2. Class Based Components (You are here!)

From functions to classes

Let’s continue using the same example we used in the first post: a blog. Our functional BlogPost component looked like this:

var blogPostData = {
  author: 'Brandon Smith',
  title: 'A CSS Trick',
  body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};

function BlogPost(postData) {
  return `<div class="post">
            <h1>${postData.title}</h1>
            <h3>By ${postData.author}</h3>
            <p>${postData.body}</p>
          </div>`;
}

document.querySelector('body').innerHTML = BlogPost(blogPostData);

In class-based components, we’ll still need that same rendering function, but we’ll incorporate it as a method of a class. Instances of the class will hold their own BlogPost data and know how to render themselves.

var blogPostData = {
  author: 'Brandon Smith',
  title: 'A CSS Trick',
  body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};

class BlogPost {

  constructor(props) {
    this.state = {
      author: props.author,
      title: props.title,
      body: props.body
    }
  }

  render() {
    return `<div class="post">
              <h1>${this.state.title}</h1>
              <h3>By ${this.state.author}</h3>
              <p>${this.state.body}</p>
            </div>`;
  }

}

var blogPostComponent = new BlogPost(blogPostData);

document.querySelector('body').innerHTML = blogPostComponent.render();

Modifying state

The advantage of a class-based (object oriented) coding style is that it allows for encapsulation of state. Let’s imagine that our blog site allows admin users to edit their blog posts right on the same page readers view them on. Instances of the BlogPost component would be able to maintain their own state, separate from the outside page and/or other instances of BlogPost. We can change the state through a method:

class BlogPost {

  constructor(props) {
    this.state = {
      author: props.author,
      title: props.title,
      body: props.body
    }
  }

  render() {
    return `<div class="post">
              <h1>${this.state.title}</h1>
              <h3>By ${this.state.author}</h3>
              <p>${this.state.body}</p>
            </div>`;
  }

  setBody(newBody) {
    this.state.body = newBody;
  }

}

However, in any real-world scenario, this state change would have to be triggered by either a network request or a DOM event. Let’s explore what the latter would look like since it’s the most common case.

Handling events

Normally, listening for DOM events is straightforward – just use element.addEventListener() – but the fact that our components only evaluate to strings, and not actual DOM elements, makes it trickier. We don’t have an element to bind to, and just putting a function call inside onchange isn’t enough, because it won’t be bound to our component instance. We have to somehow reference our component from the global scope, which is where the snippet will be evaluated. Here’s my solution:

document.componentRegistry = { };
document.nextId = 0;

class Component {
  constructor() {
    this._id = ++document.nextId;
    document.componentRegistry[this._id] = this;
  }
}

class BlogPost extends Component {

  constructor(props) {
    super();

    this.state = {
      author: props.author,
      title: props.title,
      body: props.body
    }
  }

  render() {
    return `<div class="post">
              <h1>${this.state.title}</h1>
              <h3>By ${this.state.author}</h3>
              <textarea onchange="document.componentRegistry[${this._id}].setBody(this.value)">
                ${this.state.body}
              </textarea>
            </div>`;
  }

  setBody(newBody) {
    this.state.body = newBody;
  }

}

Okay, there’s quite a bit going on here.

Referencing the component instance

First, we had to get a reference, from within the HTML string, to the present instance of the component. React is able to do this more easily because JSX actually converts to a series of function calls instead of an HTML string. This allows the code to pass this straight in, and the reference to the JavaScript object is preserved. We, on the other hand, have to serialize a string of JavaScript to insert within our string of HTML. Therefore, the reference to our component instance has to somehow be represented as a string. To accomplish this, we assign each component instance a unique ID at construction time. You don’t have to put this behavior in a parent class, but it’s a good use of inheritance. Essentially what happens is, whenever a BlogPost instance is constructed, it creates a new ID, stores it as a property on itself, and registers itself in document.componentRegistry under that ID. Now, any JavaScript code anywhere can retrieve our object if it has that ID. Other components we might write could also extend the Component class and automatically get unique ID’s of their own.

Calling the method

So we can retrieve the component instance from any arbitrary JavaScript string. Next we need to call the method on it when our event fires (onchange). Let’s isolate the following snippet and step through what’s happening:

<textarea onchange="document.componentRegistry[${this._id}].setBody(this.value)">
  ${this.state.body}
</textarea>

You’re probably familiar with hooking up event listeners by putting code inside on_______ HTML attributes. The code inside will get evaluated and run when the event triggers.

document.componentRegistry[${this._id}] looks in the component registry and gets the component instance by its ID. Remember, all of this is inside a template string, so ${this._id} evaluates to the current component’s ID. The resulting HTML will look like this:

<textarea onchange="document.componentRegistry[0].setBody(this.value)">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</textarea>

We call the method on that object, passing this.value (where this is the element the event is happening on; in our case, <textarea>) as newBody.

Updating in response to state changes

Our JavaScript variable’s value gets changed, but we need to actually perform a re-render to see its value reflected across the page. In our previous article, we re-rendered like this:

function update() {
  document.querySelector('body').innerHTML = BlogPost(blogPostData);
}

This is another place where we’ll have to make some adjustments for class-style components. We don’t want to throw away and rebuild our component instances every time we re-render; we only want to rebuild the HTML string. The internal state needs to be preserved. So, our objects will exist separately, and we’ll just call render() again:

var blogPost = new BlogPost(blogPostData);

function update() {
  document.querySelector('body').innerHTML = blogPost.render();
}

We then have to call update() whenever we modify state. This is one more thing React does transparently for us; its setState() function modifies the state, and also triggers a re-render for that component. We have to do that manually:

// ...
setBody(newBody) {
  this.state.body = newBody;
  update();
}
// ...

Note that even when we have a complex nested structure of components, there will only ever be one update() function, and it will always apply to the root component.

Child components

React (along with virtually all other JavaScript frameworks) distinguishes between elements and components that comprise a component and those that are its children. Children can be passed in from the outside, allowing us to write custom components that are containers of other arbitrary content. We can do this too.

class BlogPost extends Component {

  constructor(props, children) {
    super();

    this.children = children;
    this.state = {
      author: props.author,
      title: props.title,
      body: props.body
    }
  }

  render() {
    return `<div class="post">
              <h1>${this.state.title}</h1>
              <h3>By ${this.state.author}</h3>
              <textarea onchange="document.componentRegistry[${this._id}].setBody(this.value)">
                ${this.state.body}
              </textarea>
              <div>
                ${this.children.map((child) => child.render()).join('')}
              </div>
            </div>`;
  }

  setBody(newBody) {
    this.state.body = newBody;
    update();
  }

}

This allows us to write usage code like the following:

var adComponents = ...;
var blogPost = new BlogPost(blogPostData, adComponents);

Which will insert the components into the designated location in the markup.

Concluding thoughts

React seems simple, but it does a lot of subtle things to make our lives much easier. The most obvious thing is performance; only rendering the components whose state updates and drastically minimizing the DOM operations that get performed. But some of the less obvious things are important too.

One of these is that by making granular DOM changes instead of rebuilding the DOM entirely, React preserves some natural DOM state that gets lost when using our technique. Things like CSS transitions, user-resized textareas, focus, and cursor position in an input all get lost when we scrap the DOM and reconstruct it. For our use case, that’s workable. But in a lot of situations, it might not be. Of course, we could make DOM modifications ourselves, but then we’re back to square one, and we lose our declarative, functional syntax.

React gives us the advantages of DOM modification while allowing us to write our code in a more maintainable, declarative style. We’ve shown that vanilla JavaScript can do either, but it can’t get the best of both worlds.

Article Series:

  1. Pure Functional Style
  2. Class Based Components (You are here!)

Reactive UI’s with VanillaJS – Part 2: Class Based Components is a post from CSS-Tricks

Naming Things is Only Getting Harder

Post pobrano z: Naming Things is Only Getting Harder

I was working with CSS Grid and came to the grid-column and grid-row properties. I paused for a moment.

They’re not overly complicated. They are shorthand properties for expressing where an element should start and end on a grids defined columns and rows.

What caught me was the fact that I can name these lines. It’s not a requirement (you can use numbers), but the ability to name the grid lines is something we can do here. In fact, naming lines can be open up neat CSS tricks.

Grid lines are another item in a long list of examples where front end developers have the power to name things. Class names and IDs have always been things we need to name in CSS, but consider a few of the more historically recent things where naming is important when it comes to styling:

  • Variables: Naming values for context, such as re-usable colors or numeric values whether in preprocessors or new CSS variables.
  • Data attributes: Selecting elements based on their HTML attributes rather than a class name.
  • Components: Like what we’re seeing in React and future CSS features like Web Components.
  • CSS files: Organizational methods like Atomic Design have accentuated the importance of naming our files, including preprocessor partials.
  • Media queries: We know naming them after devices is futile, so that has to make sense as well.

It’s not that naming things is ridiculously hard in and of itself. It’s more that there is a sense of power that comes with the ability to name things. And is always said: with power comes great responsibility. In this case, naming has an impact on everything from how code is written and organized to its overall performance and maintainability. Poorly named elements is smelly by nature and often indicative of the overall quality of the code. It can lead to the wariness of a growing code base.

Let’s just say I’ve spent more time naming some CSS classes than I spent naming my own two kids. I’m embarrassed to say that, but it’s the truth.

Naming grid lines is just another item in the growing cascade of things we are responsible for as front-enders. It’s not a bad thing or even an annoying one, but yet another reminder of how front end development is development, design and architecture all in one.

Related Reads


Naming Things is Only Getting Harder is a post from CSS-Tricks

What Does a Well-Documented CSS Codebase Look Like?

Post pobrano z: What Does a Well-Documented CSS Codebase Look Like?

In the front-end community, there is a lot of attention related to documenting JavaScript. That’s not so much the case with CSS. Often times I feel like lost when I join a project with minimal or no CSS documentation.

Even though CSS is relatively easy to write, it can be quite hard to maintain. The specificity, the global scope of everything, and the lack of guidance can easily lead to inconsistency, code duplication, and over-complication.

I’ve long been curious what a really well-documented CSS codebase looks like. Here, I’ll share my experience, along with the expectations I have towards my vision of well-documented stylesheets.

It surprises me where I hear people say that commenting CSS is not that important. I imagine none of them have had to deal with 10,000+ line stylesheets! Often I’ve struggled with what HTML results in what specific style. Without having a solid context about the development decisions taken, debugging efforts increase. WTFs per minute increase exponentially too.

Many times I’ve spent hours to figure out what the developer intended, why she didn’t do it the another way, why is this layout seemingly so complex. There is much pain buried in these „why” questions.

So, here we go! Let’s examine the 4 big signs of a well-documented CSS codebase.

1) CSS Tech Stack & Toolchain

There are likely things as part of our CSS code base like third-party libraries, mixins, or other tools. Looking in the package manager’s dependencies list doesn’t give a lot of context why the decisions were made to add these things, what they do exactly, and how we’re using them.

It would be good for everyone to know why a certain library or tool was introduced. Imagine, for example, that a third-party library was introduced only to solve what has become an obsolete CSS issue. If we had context like that, we could make more informed decisions.

There sometimes can be quite a few third-party libraries in a project. Have you ever spent a bunch of time on web searching each one figuring out what it even is? It can be quite a challenge to know or to keep track of what each exactly does.

A well-documented codebase would include a description for each dependency. Perhaps you could the comment tweet-length (140 characters) explaining why it is there. That would give anyone else in the code base a head start on why something is there.

I like adding these descriptions right in the place where I @import them.

2) CSS Conventions

Good coding conventions result in consistent, readable, and unambiguous source code. They standardize the structure and coding style of an application so that you and others can easily read and understand the code.

It’s important to know if there are any project-specific naming conventions or methodologies in place (like BEM, OOCSS, SMACSS, or ACSS). I’ve seen cases where a certain methodologies principles are applied but the actual rules followed are modified based on the preferences of the developers involved. So an indication how strictly we must follow the methodology principles would be good to leave in a well-documented code base.

This brings up the larger issue of CSS style guides. A naming convention is just one choice as part of a complete styling strategy. Other parts might be:

All this makes up a complete CSS style guide. Having a shared vocabulary like this I’d consider a strong plus towards consistency.

3) CSS Architecture

Most scalable projects follow some type of architecture in terms of ordering styles. In a well-documented codebase, the fundamental principles that the project follows when structuring and sectioning styles should be mentioned.

I was first inspired to explore CSS architecture by watching Harry Roberts’s talk about managing CSS projects. Here’s Harry:

CSS architecture seems to be somewhat in vogue right now. It’s something you’ve no doubt heard mentioned numerous times over the past year or so, and with good reason: UIs (and the teams that build them) are getting bigger and more complicated than ever before.

There are a number of aspects of CSS which make it troublesome. It’s declarative, meaning there is no logic or control flow to tell other developers much about the state or construction of the project. It operates in a global namespace, meaning we get collisions, leaking styles and inadvertent regressions. It utilizes inheritance, making everything somewhat interdependent and brittle. Finally, the unavoidable specificity model can cause problems when selectors fight each other for prominence.

Therefore, he introduces a concept for architecting CSS called ITCSS. If you are working on a project of reasonable scale, chances are someone already defined similar principles or ideas that aim to resolve these problems. So in a well-documented codebase, I would expect to see them written somewhere.

One could tell if the architecture is explained well enough if you can answer the following question: Where should new styles or stylesheets be added?

4) CSS Component Descriptions and Examples

A common pattern is to separate the logical modules into CSS components (or „blocks” according to BEM). Some of them might be re-usable, some may not, but the important thing is that they are the building blocks of our project. Therefore, describing what they are should be a top priority in a well-documented codebase.

Ideally, you should arrange and group them, name them, and establish rules between them to generate an overview of all components. A well-described CSS component doesn’t only include information about what the component does but also has other valuable intel like example HTML markup and the context in which it’s meant to be used. Going one step further brings up the issue of Pattern Libraries. A pattern library is a collection of reusable components that can be used together to create a website. With modular, component-based architecture becoming a trend, they can bring huge value.

The goal of a pattern library is to show what can be built with existing patterns (components). But let’s take a look at what additional information can be displayed alongside each pattern also. Vitaly Friedman shared a good summary on how taking the pattern library to the next level looks like. He states that focusing on components isn’t good enough:

One of the main problems with pattern libraries is that, while they provide an overview of components, they often leave a lot open to interpretation. Components can be combined in a variety of ways, consistently and inconsistently. It’s great to be able to see what button variants and iconography are available and what kinds of tables and pricing tags one may use, but what if you need to design or build an interface that contains all of these components at once — and perhaps another that doesn’t yet exist in the library?

A list of modules alone wouldn’t convey any context or any specifics on how the modules should (and should not) be used.

Based on Vitaly’s post and Brad Frost’s anatomy of a pattern in a pattern library, here are a few ideas I can imagine each of our patterns (components) could have, despite the usual unique name, code sample and a description of the component’s purpose. Basic (fundamental):

  • Tags or categories: The assigned tags or categories for the component. Developers could tag their components with „in use”, „needs refactoring” tags and etc.
  • Responsive preview: A real-life, resizable preview of the component, using the actual snippet of code being used in production. Alternatively, just a screenshot.
  • Versioning and legacy, team members involved or responsible: In a bigger team, the ownership of the (family of) components and which team members have been actively developing them could be really helpful for maintenance and further development.

… and here are a few more advanced:

  • Performance impact: Sometimes CSS could be heavy too. An indicator of performance or a „warning signs” section, outlining not only performance impact but also any common mishaps when the pattern is used incorrectly.
  • Accessibility implications: Indicator of accessibility requirements. Some components might require more work to maintain accessibility, especially if they interact with other components.
  • Related patterns: A quick overview of related components or the family of components that a given component belongs to. Could use an explanation of when to use a component, when not to, and why.
  • Fallback and print previews.

… the list goes on and on to whatever makes sense for your specific use-case.

Conclusion

A well-documented CSS codebase enforces consistency, boosts maintainability, and helps the team to build a shared vocabulary. It is a prerequisite for efficient CSS design and development. Moreover, based on my experience, it inevitably leads to better performance. I strongly believe that these are the signs of the professional execution of a project.

If you have thoughts, please feel free to add them in the comments below, so together we can come closer to better documentation practices.


What Does a Well-Documented CSS Codebase Look Like? is a post from CSS-Tricks

Connect: behind the front-end experience

Post pobrano z: Connect: behind the front-end experience

Some fantastic behind-the-scenes stuff about Stripe’s design work by Benjamin De Cock. Absolutely everything is clever and using very modern techniques.

Plus one I’d never seen before:

Connect’s landing page uses the new Intersection Observer API which provides a much more robust and performant way to detect the visibility of an element … The observeScroll helper simplifies our detection behavior (i.e. when an element is fully visible, the callback is triggered once) without executing anything on the main thread.

Direct Link to Article — Permalink


Connect: behind the front-end experience is a post from CSS-Tricks

An Introduction to the `fr` CSS unit

Post pobrano z: An Introduction to the `fr` CSS unit

With all the excitement around CSS Grid, I haven’t seen as much talk about the new fr CSS length unit (here’s the spec). And now that browser support is rapidly improving for this feature, I think this is the time to explore how it can be used in conjunction with our fancy new layout engine because there are a number of benefits when using it; more legible and maintainable code being the primary reasons for making the switch.

To get started, let’s take a look at how we’d typically think of building a grid in CSS. In the example below, we’re creating a four column grid where each column has an equal width:

<div class="grid">
  <div class="column"></div>
  <div class="column"></div>
  <div class="column"></div>
  <div class="column"></div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(4, 25%);
  grid-column-gap: 10px;
}

See the Pen CSS-Tricks: Grid Example 1 by Robin Rendle (@robinrendle) on CodePen.

If you’ve never seen that repeat() function after the grid-template-columns property then let me introduce you to one of the neatest features of CSS Grid! It’s a shorthand, essentially, allow us to more succinctly describe repeating values. We could have written grid-template-columns: 25% 25% 25% 25%; instead, but it’s cleaner using repeat(), particularly when you have more verbose widths (like a minmax() expression).

The syntax is essentially this:

repeat(number of columns/rows, the column width we want);

There are actually a couple of issues with what we’ve done so far, though.

First, in order to use this neat CSS function, we had to do a tiny bit of math. We had to think to ourselves what is the total width of the grid (100%) divided by the number of columns we want (4), which brings us to 25%. In this instance, the math is pretty darn easy so we don’t have to worry about it but in more complex examples we can completely avoid doing the math and let the browser figure that out for us. We do have calc() available to us, so we could have done repeat(4, calc(100% / 4), but even that’s a little weird, and there is another problem anyway…

The second issue is a problem with overflow. Because we’ve set each column to 25% and a grid-column-gap to 10px then that pushes grid element wider than 100%. It isn’t how you’d expect things to work from just looking at the code above but that’s how percentages work. What we’re really saying with the code above is „set each column to 25% the width of the viewport and have a 10px gap between them.” It’s a subtle difference, but it causes a big issue with layout.

We’ve inadvertently caused some horizontal scrolling here:

See the Pen CSS-Tricks: Grid Example 1 by Robin Rendle (@robinrendle) on CodePen.

This is where the fr unit can help us.

The fr unit (a „fraction”) can be used when defining grids like any other CSS length such as %, px or em. Let’s quickly refactor the code above to use this peculiar new value:

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
}

See the Pen CSS-Tricks: Grid Example 1b by Robin Rendle (@robinrendle) on CodePen.

That will look just the same as the example above because in this instance we’re setting each of our four columns to one fraction (which happens to be 1/4 or 25%). But! There’s no overflow on the x-axis anymore because setting each column to 1fr takes that 10px into account automatically and subtracts it from the total width available for each column.

Why the heck should I learn how to use this fancy new CSS length if I can mostly stick to the units like percent or pixels, you wonder? Well, let’s dig into a more complex CSS Grid example to explain why fr is a better alternative. In a new example, let’s say we want our navigation on the left followed by a twelve column grid which should look like this:

This is a pretty typical scenario for a lot of UIs and so using the fr unit prevents us from either making a separate grid div or fumbling about with calc. Because if we didn’t use fr in the example above then we’d somehow have to figure out the following:

the width of each column = ((width of viewport - width of nav) / number of columns) * 1%

That’s possible for sure, it’s just awfully painful to read, and if we changed the width of the nav then we’d have to do that dumb calculation all over again. Instead, the fr unit tidies all of that up into a super readable line of code:

.grid {
  display: grid;
  grid-template-columns: 250px repeat(12, 1fr);
  grid-column-gap: 10px;
}

See the Pen CSS-Tricks: Grid Example 2 by Robin Rendle (@robinrendle) on CodePen.

What we’re doing here is setting a fixed width in pixels for the first column and then creating twelve separate columns which are set at one „fraction of the free space” (literally how the spec phrases it). But there’s no crazy calculations or anything! It’s super readable and if the width of that left nav changes then the width of our columns on the right will adjust themselves automatically.

With just a little bit of legwork we’ve made our interface more maintainable for the future and we’ve ensured that our code is more legible for the next developers that are coming up behind us.

Information from other folks

Some of the fun and power of the fr unit comes from mixing it with other units. Imagine a fixed sidebar and main content area that takes up the rest of the space: grid-template-columns: 200px 1fr; easy!

Here’s an example from Alligator.io showing mixed units nicely:


Rachel Andrew has a video specifically about fr:


Anna Monus has a very good article on fr.


Yay for the fr unit!


An Introduction to the `fr` CSS unit is a post from CSS-Tricks

A Little Example of Data Massaging

Post pobrano z: A Little Example of Data Massaging

I’m not sure if „data massaging” is a real thing, but that’s how I think of what I’m about to describe.

Dave and I were thinking about a bit of a redesign for ShopTalk Show. Fresh coat of paint kinda thing. Always nice to do that from time to time. But we wanted to start from the inside out this time. It didn’t sound very appealing to design around the data that we had. We wanted to work with cleaner data. We needed to massage the data that we had, so that it would open up more design possibilities.

We had fallen into the classic WordPress trap

Which is… just dumping everything into the default content area:

We used Markdown, which I think is smart, but still was a pile of rather unstructured content. An example:

If that content was structured entirely differently every time (like a blog post probably would be), that would be fine. But it wasn’t. Each show has that same structure.

It’s not WordPress’ fault

We just didn’t structure the data correctly. You can mess that up in any CMS.

To be fair, it probably took quite a while to fall into a steady structure. It’s hard to set up data from day one when you don’t know what that structure is going to be. Speaking of which…

The structure we needed

This is what one podcast episode needs as far as structured data:

  • Title of episode
  • Description of episode
  • Featured image of episode
  • MP3
    • URL
    • Running Time
    • Size in Bytes
  • A list of topics in the show with time stamps
  • A list of links
  • Optional: Guest(s)
    • Guest Name
    • Guest URL
    • Guest Twitter
    • Guest Bio
    • Guest Photo
  • Optional: Advertiser(s)
    • Advertiser Name
    • Advertiser URL
    • Advertiser Text
    • Advertiser Timestamp
  • Optional: Job Mention(s)
    • Job Company
    • Job Title
    • Job URL
    • Job Description
  • Optional: Transcript

Even that’s not perfect

For example: we hand-number the episodes as part of the title, which means when we need that number individually we’re doing string manipulation in the templates, which feels a bit janky.

Another example: guests aren’t a programmatic construct to themselves. A guest isn’t its own database record with an ID. Which means if a guest appears on multiple shows, that’s duplicated data. Plus, it doesn’t give us the ability to „display all shows with Rebecca Murphey” very easily, which is something we discussed wanting. There is probably some way to program out way out of this in the future, we’re thinking.

Fortunately, that structure is easy to express in Advanced Custom Fields

Once you know what you need, ACF makes it pretty easy to build that out and apply it to whatever kind of page type you need to.

I’m aware that other CMS’s encourage this kind of structuring by default. Cool. I think that’s smart. You should be very proud of yourself for choosing YourFavoriteCMS.

In ACF, our „Field Group” ended up like this:

We needed „Repeater” fields for data like guests, where there is a structure that needs to repeat any number of times. That’s a PRO feature of ACF, which seems like a genius move on their part.

Let the data massaging begin

Unfortunately, now that we had the correct structure, it doesn’t mean that all the old data just instantly popped into place. There are a couple of ways we could have gone about this…

We could have split the design of show pages by date. If it was an old show, dump out the content like we always have. If it’s a new show, use the nice data format. That feels like an even bigger mess than what we had, though.

We could have tried to program our way out of it. Perhaps some scripts we could run that would parse the old data, make intelligent guesses about what content should be ported to the new structure, and run it. Definitely, a non-trivial thing to write. Even if we could have written it, it may have taken more time than just moving the data by hand.

Or… we could move the data by hand. So that’s what we ended up doing. Or rather, we hired someone to move the data for us. Thanks Max! Max Kohler was our data massager.

Hand moving really seemed like the way to go. It’s essentially data entry work, but required a little thought and decision making (hence „massaging”), so it’s the perfect sort of job to either do yourself or find someone who could use some extra hours.

Design is a lot easier with clean and structured data

With all the data nicely cleaned up, I was able to spit it out in a much more consistent and structured way in the design itself:

This latest design of ShopTalk Show is no masterpiece, but now that all this structural work is done, the next design we should be able to focus more on aesthetics and, perhaps, the more fun parts of visual design.


A Little Example of Data Massaging is a post from CSS-Tricks

CSS-Tricks Chronicle XXXI

Post pobrano z: CSS-Tricks Chronicle XXXI

All the latest happenings! As I like to do, I round up a bunch of things that have happened in the past few months around here on this site, over at CodePen and ShopTalk, and other sites where I got to be a guest or was involved somehow. There has been some big releases, some redesigns, and a bunch of guest podcasts.


I got to be a guest on Relative Paths with Mark Phoenix and Ben Hutchings. It was episode 47 and the topic was dogmatism, a topic I weighed in on earlier with my post My Increasing Wariness of Dogmatism.


The biggest release ever on CodePen is CodePen Projects. It hasn’t even been out three months yet! As opposed to Pens on CodePen, Projects gives you an editor that is more of a full-on IDE with your own file system.


I was a guest on Eric Siu’s podcast Growth Everywhere, Episode 196 where we talk numbers and growth stuff. (Fair warning on the link: it’s pretty pop-up heavy.)


I also had a lot of fun on the Email Design Podcast, Episode 60, where I got to chat with Kevin Mandeville and Jason Rodriguez specifically about email stuff. That’s not something I get to talk about much, but I actually find myself doing quite a bit lately with email, and it’s a very weird world that somehow feels completely different than „normal” front-end development.


I have moved back home to Milwaukee, after spending the last 7 months in Miami. Bittersweet! Farewell, friends old and new in Miami. Hello, friends old and new in Milwaukee.


We’re less than a month away from the 10 year anniversary of CSS-Tricks! We’ll definitely do something. No rooftop party or anything, but definitely come see what we got on July 4th.


I redesigned my personal site. It’s nothing special to look at, but I think it’s going to serve my needs very well. The new site needed to clearly show: this is who I am, this is what I do, this is where I exist other places on the web, and most importantly, these are the things I want you to do.

The most fun little bit is the radio buttons by the bio area, which allow you to customize the length, first person or third, and what format it’s in.


ShopTalk also has a brand new website. Also designed and implemented by me, so, brace yourselves for utilitarian. This one was driven by backend data. I think I’ll write about that soon.

We recently did a podcast called On Podcasting where I got to chat with Chris Enns about podcasting equipment. I figured it was about time to get some advice and update my gear. I bet if you factor in all the ShopTalk, CodePen Radio, guest appearances, and videos I’ve recorded, I’m around 1,000 episodes of stuff. Probably about time I have some decent gear. I pulled the trigger on the major upgrade. I’ll have to post about that soon as well.


My public speaking schedule for the rest of the year is:


CSS-Tricks Chronicle XXXI is a post from CSS-Tricks

CSS Animations vs Web Animations API

Post pobrano z: CSS Animations vs Web Animations API

There is a native API for animation in JavaScript known as the Web Animations API. We’ll call it WAAPI in this post. MDN has good documentation on it, and Dan Wilson has a great article series.

In this article, we’ll compare WAAPI and animations done in CSS.

A note on browser support

WAAPI has a comprehensive and robust polyfill, making it usable in production today, even while browser support is limited.

As ever, you can check Can I Use for browser support data. However, that doesn’t provide very good info on support of all the sub features of WAAPI. Here’s a checker for that:

See the Pen WAAPI Browser Support Test by Dan Wilson (@danwilson) on CodePen.

To experiment with all features without a polyfill, use Firefox Nightly.

The basics of WAAPI

If you’ve ever used jQuery’s .animate(), the basic syntax of WAAPI should look pretty familiar. 

var element = document.querySelector('.animate-me');
element.animate(keyframes, 1000);

The animate method accepts two parameters: keyframes and duration. In contrast to jQuery, not only does it have the benefit of being built into the browser, it’s also more performant.

The first argument, the keyframes, should be an array of objects. Each object is a keyframe in our animation. Here’s a simple example:

var keyframes = [
  { opacity: 0 },
  { opacity: 1 }
];

The second argument, the duration, is how long we want the animation to last . In the example above it is 1000 milliseconds. Let’s look at a more exciting example.

Recreating an animista CSS animation with WAAPI

Here’s some CSS code I yanked from the awesome animista for something calling itself the „slide-in-blurred-top” entrance animation. It looks pretty sweet. 

The actual perf is much better than this GIF.

Here’s those keyframes in CSS:

0% {
  transform: translateY(-1000px) scaleY(2.5) scaleX(.2);
  transform-origin: 50% 0;
  filter: blur(40px);
  opacity: 0;
}
100% {
  transform: translateY(0) scaleY(1) scaleX(1);
  transform-origin: 50% 50%;
  filter: blur(0);
  opacity: 1;
}

Here’s the same code in WAAPI:

var keyframes = [
  { 
    transform: 'translateY(-1000px) scaleY(2.5) scaleX(.2)', 
    transformOrigin: '50% 0', filter: 'blur(40px)', opacity: 0 
  },
  { 
    transform: 'translateY(0) scaleY(1) scaleX(1)',
    transformOrigin: '50% 50%',
    filter: 'blur(0)',
    opacity: 1 
  }
];

We’ve already seen how easy it is to apply the keyframes to whichever element we want to animate:

element.animate(keyframes, 700);

To keep the example simple, I’ve only specified the duration. However, we can use this second parameter to pass in far more options. At the very least, we should also specify an easing. Here’s the full list of available options with some example values:

var options = {
  iterations: Infinity,
  iterationStart: 0,
  delay: 0,
  endDelay: 0,
  direction: 'alternate',
  duration: 700,
  fill: 'forwards',
  easing: 'ease-out',
}
element.animate(keyframes, options);

With these options, our animation will start at the beginning with no delay and loop forever alternating between playing forwards and in reverse.

See the Pen motion blur waapi circle by CSS GRID (@cssgrid) on CodePen.

Annoyingly, for those of us familiar with CSS animations, some of the terminologies varies from what we’re used to. Although on the plus side, things are a lot quicker to type!

  • It’s easing rather than animation-timing-function
  • Rather than animation-iteration-count it’s iterations. If we want the animation to repeat forever it’s Infinity rather than infinite. Somewhat confusingly, Infinity isn’t in quotes. Infinity is a JavaScript keyword, whereas the other values are strings.
  • We use milliseconds instead of seconds, which should be familiar to anyone who’s written much JavaScript before. (You can use milliseconds in CSS animations as well, but few people do.)

Let’s take a closer look at one of the options: iterationStart. 

I was stumped when I first came across iterationStart. Why would you want to start on a specified iteration rather than just decreasing the number of iterations? This option is mostly useful when you use a decimal number. For example, you could set it to .5, and the animation would start half way through. It takes two halves to make a whole, so if your iteration count is set to one and your iterationStart is set to .5, the animation will play from halfway through until the end of the animation, then start at the beginning of the animation and end in the middle! 

It is worth noting that you can also set the total number of iterations to less than one. For example:

var option = {
  iterations: .5,
  iterationStart: .5
}

This would play the animation from the middle until the end. 
endDelay: endDelay is useful if you want to string multiple animations after each other, but want there to be a gap between the end of one animation and the start of any subsequent ones. Here’s a useful video to explain from Patrick Brosset.

Easing

Easing is one of the most important elements in any animation. WAAPI offers us two different ways to set easing — within our keyframes array or within our options object.
In CSS, if you applied animation-timing-function: ease-in-out you might assume that the start of your animation would ease in, and the end of your animation would ease out. In fact, the easing applies between keyframes, not over the entire animation. This can give fine-grained control over the feel of an animation. WAAPI also offers this ability.

var keyframes = [
  { opacity: 0, easing: 'ease-in' }, 
  { opacity: 0.5, easing: 'ease-out' }, 
  { opacity: 1 }
]

It’s worth noting that in both CSS and WAAPI, you shouldn’t pass in an easing value for the last frame, as this will have no effect. This is a mistake a lot of people make.
Sometimes it’s a lot more intuitive to add easing over an entire animation. This is not possible with CSS, but can now be achieved with WAAPI.

var options = {
  duration: 1000,
  easing: 'ease-in-out',
}

You can see the difference between these two kinds of easing in this Pen:

See the Pen Same animation, different easing by CSS GRID (@cssgrid) on CodePen.

Ease vs Linear

It’s worth noting another difference between CSS animation and WAAPI: the default of CSS is ease, while the default of WAAPI is linear. Ease is actually a version of ease-in-out and is a pretty nice option if you’re feeling lazy. Meanwhile, linear is deadly dull and lifeless — a consistent speed that looks mechanical and unnatural. It was probably chosen as the default as it is the most neutral option. However, it makes it even more important to apply an easing when working with WAAPI than when working with CSS, lest your animation look tedious and robotic.

Performance

WAAPI provides the same performance improvements as CSS animations, although that doesn’t mean a smooth animation is inevitable. 

I had hoped that the performance optimizations of this API would mean we could escape the use of will-change and the totally hacky translateZ  —  and eventually, it might. However, at least in the current browser implementations, these properties can still be helpful and necessary in dealing with jank issues.

However, at least if you have a delay on your animation, you don’t need to worry about using will-change. The primary author of the web animations spec had some interesting advice over on the Animation for Work Slack community, which hopefully he won’t mind me repeating here: 

If you have a positive delay, you don’t need will-change since the browser will layerize at the start of the delay and when the animation starts it will be ready to go.

WAAPI Versus CSS Animations?

WAAPI gives us a syntax to do in JavaScript what we could already achieve in a stylesheet. Yet, they shouldn’t be seen as rivals. If we decide to stick to CSS for our animations and transitions, we can interact with those animations with WAAPI.
 

Animation Object

The .animate() method doesn’t just animate our element,  it also returns something. 

var myAnimation = element.animate(keyframes, options);
Animation object viewed in a console

If we take a look at the return value in the console, we’ll see its an animation object. This offers us all sorts of functionality, some of which is pretty self-explanatory, like myAnimation.pause(). We could already achieve a similar result with CSS animations by changing the animation-play-state property, but the WAAPI syntax is somewhat terser than element.style.animationPlayState = "paused". We also have the power to easily reverse our animation with myAnimation.reverse(), which again, is only a slight improvement over changing the animation-direction CSS property with our script.

However, up until now, manipulating @keyframes with JavaScript hasn’t been the easiest thing in the world. Even something as simple as restarting an animation takes a bit of know-how, as Chris Coyier has previously written about. Using WAAPI we can simply use myAnimation.play() to replay the animation from the beginning if it had previously completed, or to play it from mid-iteration if we had paused it.

We can even change the speed of an animation with complete ease.

myAnimation.playbackRate = 2; // speed it up
myAnimation.playbackRate = .4; // use a number less than one to slow it down

getAnimations()

This method will return an array of any animation objects for any animations we’ve defined with WAAPI, as well as for any CSS transitions or animations.

element.getAnimations() // returns any animations or transitions applied to our element using CSS or WAAPI

If you feel comfortable and content using CSS for defining and applying your animations, getAnimations() allows you to use the API in conjunction with @keyframes. It’s possible to continue to use CSS for the bulk of your animation work and still get the benefit of the API when you need it. Let’s see how easy that is.

Even if a DOM element only has one animation applied to it, getAnimations() will always return an array. Let’s grab that single animation object to work with.

var h2 = document.querySelector("h2");
var myCSSAnimation = h2.getAnimations()[0];

Now we can use the web animation API on our CSS animation 🙂

myCSSAnimation.playbackRate = 4;
myCSSAnimation.reverse();

Promises and Events

We already have a variety of events triggered by CSS that we can utilise in our JavaScript code :  animationstart, animationend, animationiteration and transitionend. I often need to listen for the end of an animation or transition in order to then remove the element it was applied to from the DOM.

The equivalent of using animationend or transitionend for such a purpose in WAAPI would again make use of the animation object:

myAnimation.onfinish = function() {
  element.remove();
}

WAAPI offers us the choice of working with both events and promises. The .finished property of our animation object will return a promise that will resolve at the end of the animation. Here’s what the example above would look like using a promise:

myAnimation.finished.then(() =>
  element.remove())

Let’s look at a slightly more involved example yanked from the Mozilla Developer Network. Promise.all expects an array of promises and will only run our callback function once all of those promises have resolved. As we’ve already seen, element.getAnimations() returns an array of animation objects. We can map over all the animation objects in the array calling .finished on each of them, giving us the needed array of promises.

In this example, it’s only after all the animations on the page have finished that our function will run.

Promise.all(document.getAnimations().map(animation => 
  animation.finished)).then(function() {           
    // do something cool 
  })

The Future

The features mentioned in this article are just the beginning. The current spec and implementation look to be the start of something great.


CSS Animations vs Web Animations API is a post from CSS-Tricks