Infinite Scroll v4 released

11 Jan 2021 · by David DeSandro

Infinite Scroll v4 screenshot

This week, I released the new major version of Infinite Scroll, v4. New features include:

Give Infinite Scroll v4 a look right here.

Infinite Scroll v4 is largely backwards compatible with v3. Upgrading to v4 is no sweat. Breaking changes include:

  • replaced responseType option with responseBody. This effects loading JSON.
  • Internet Explorer and Android 4 support dropped.
  • Removed RequireJS support and AMD export.

A lot of work went into improving the infrastructure around around the plugin. JS code is linted with ESLint. Testing is now done via command line with Puppeteer. Both these improvements allow for automated testing with GitHub Actions, allowing for integrated testing on commits and Pull Requests (take a look at the workflows/nodejs.yml).

Infinite Scroll is the oldest piece of software I support, dating back to Paul Irish’s original release in 2008. Not many software companies can boast that kind of longevity. I’m proud to be able to keep it going all these years.

I chose to upgrade Infinite Scroll as it is less popular, making it a good testing ground for new development. I’ve laid the groundwork to start tackling the bigger plugins next: Isotope & Flickity.

Can't mix-in ES6 class expressions

22 Dec 2020 · by David DeSandro

Here's a quick JavaScript bug story. I'm working on Infinite Scroll v4, updating older ES5 code to ES2018.

If you create a class using the traditional function class definition, you can use mix it in to another class' prototype with Object.assign(). I use this pattern with EvEmitter and my plugins.

// function class definition
function EvEmitter() {}

// prototype methods
EvEmitter.prototype.emit = function() {};
EvEmitter.prototype.on = function() {};
EvEmitter.prototype.off = function() {};

// plugin function class
function InfiniteScroll() {}

// mixin EvEmitter prototype into Infinite Scroll
Object.assign( InfiniteScroll.prototype, EvEmitter.prototype );

// now InfiniteScroll can use EvEmitter methods
InfiniteScroll.prototype.create = function() {
  this.emit( 'load', function() {} );
  this.on( 'request', function() {} );
};

But, if you use ES6 classes expressions, you can no longer use the Object.assign() mix-in pattern.

// class expression
class EvEmitter {
  // prototype methods
  emit() {}
  on() {}
  off() {}
}

function InfiniteScroll() {}

// mixin
Object.assign( InfiniteScroll.prototype, EvEmitter.prototype );

InfiniteScroll.prototype.create = function() {
  // Uncaught TypeError: this.emit is not a function
  this.emit( 'load', function() {} );
  this.on( 'request', function() {} );
};

Whaaa? The core issue is that class methods are non-enumerable. If you try iterating over Class.prototype that was set with a class expression, you'll get nothing.

class EvEmitter {
  emit() {}
  on() {}
  off() {}
}

console.log( Object.keys( EvEmitter.prototype ) );
// => []
// empty!

I suppose this is an improvement

That’s good, because if we for..in over an object, we usually don’t want its class methods.

Except I've been iterating over prototype for years.

The obvious solution is to define the inherited class with a class expression as well, using extend to inherit the superclass.

// okay, this works
class InfiniteScroll extends EvEmitter {
  create() {
    this.emit( 'load', function() {} );
    this.on( 'request', function() {} );
  }
}

But it's a bummer that I lose a feature by opting-in to the new syntax. EvEmitter really is a mix-in and I would like to be able to use it like one. Read Angus Croll about why mixins are a good JavaScript pattern.. There is an ES6 approach for mix-ins and class expressions, but I'm not a fan.

So I reverted using class and switched back to the original function expression & prototype setting.

function EvEmitter() {}

EvEmitter.prototype.emit = function() {};
EvEmitter.prototype.on = function() {};
EvEmitter.prototype.off = function() {};

YAY back in business.

Full-time fizzy finish

19 Mar 2019 · by David DeSandro

New job at Compass

After four years of being my full-time gig, Metafizzy is reverting back to a side-business. This week I start a new full-time job at Compass.

For my personal career and well-being, the new job is a huge win. I'll be working on a bigger endeavor, with world-class colleagues, producing a reliable income with great benefits. I'm excited for this next chapter.

For Metafizzy, it's a bittersweet coda. Over the past two years, revenue had plateaued. Being a father and mortgage-owner, the risk of staying independent was too high. I welcome the stability of joining a thriving company and being adequately compensated for my effort.

My four years full-time on Metafizzy is the longest tenure with a single employer of my entire career. I feel lucky to have gotten this far, but also a bit heart-broken that it's over. I think of all the things I never got to do: hiring teammates, championing a business model, shipping more products. There is much left undone.

But there's also so much left that still works. Metafizzy, its plugins, and its brand remains completely in my possession. Metafizzy never took outside funding. I have no lingering debt that requires a hard exit. Everything continues to live on.

In practical terms, that means plugins will continue to be supported. The plugins' code bases have long been stable for years. (Isotope, for example, hasn't required a minor version update since 2015.) I do have plans for the next major version updates, dropping IE11 and fully adopting ES6, but that's still further down the road.

Outside of the plugins, everything else can be considered on hiatus. That covers freelance logo design and front-end development, Logo Pizza, and Fizzy School. I may dip back into these projects, but don't hold your breath.

I still feel there is so much money to be made in independent front-end development. Even though our practice has largely been free to learn and free to use, the value that front-end developers drive is enormous. The Metafizzy model was on to something and that something is still out there.

Fade with Flickity v2.2.0

31 Jan 2019 · by David DeSandro

Flickity v2.2.0 has been released with all-new fade feature. The fade option allows you to fade between transitioning slides instead of moving.

Flickity fade

I built out this feature as separate add-on package flickity-fade. Read more about Flickity's modular architecture here. Fade works with dragging, groupCells, wrapAround, imagesLoaded, and everything else in the Flickity feature-set.

To use fade, add flickity-fade.css to your stylesheets, flickity-fade.js to your scripts, and then enable fade in your Flickity options.

$('.carousel').flickity({
  fade: true,
});

Flickity fade was four years in the making. I held off for so long because dragging & moving is both obvious and what makes Flickity special. But after 4 years of requests, I relented. Lords of UX, forgive me.


Flickity v2.2.0 also comes with other smaller features and bug fixes:

  • Set the initial selected cell that matches a selector string with initialIndex: '.selector'
  • Better accessibility support with aria-hidden
  • The tap-listener package was removed as a dependency, shedding some code weight
  • Fixed triggering events after destroy
  • Fixed iOS 9 dragging bug

Most of these improvements originated from open-source contributions. View the v2.2.0 release notes for the original GitHub issues and Pull Requests.


Flickity turns 4 years old next month. It's been great to see Flickity continue to grow and be used out in the wild. Fading was definitely not my cup of tea, but I was convinced to pursue it after witnessing sustained interest over years. People didn't just want fading, they wanted all of Flickity's features plus fading. My heart swells.

Slack logo armchair redesign

24 Jan 2019 · by David DeSandro

Slack has a new logo. It hits its marks!

Previous and new Slack logo

Slack's new logo is successful because it resolves all of the issues the previous logo had.

  • Too many colors
  • Problematic on dark and photo backgrounds
  • Required multiple variations for various applications
  • Problematic rotation

As the Slack team put it, "It was extremely easy to get wrong."

The new design fixes all these problems with a distinct iconic logo. It works on light, dark, photo backgrounds. It can be rendered with multiple colors or just one. The new logo makes it easy to get it right.

Slack logo backgrounds


That said, I miss the plaid. John Gruber elaborates:

Unique among technology companies, [Slack] owned plaid. ... To such a degree that Slack company socks — which simply used colors and plaid — became coveted swag.

I saw this opportunity as a worthwhile exercise for my logo design chops — to design a new logo that addressed Slack's original concerns while also keeping the plaid.

Here's my armchair-proposed design.

Slack armchair design

Slack armchair design variations

The octothorp emblem is rendered with four rounded rectangles. The overlapping squares are all colored the same dark purple (aubergine). Technically, this is not how multiply blends work. But visually, unifying those four squares simplifies the design. The aubergine color and rounded corners are then brought over into the wordmark, tying the two elements together.

Keeping the plaid means that the multi-color problems persist. To address these, I created several design variations. For solid dark backgrounds, aubergine is swapped for white. For photo backgrounds, the octothorp stripes are rendered with 50% transparency, trickily rendering the plaid with a single color. Finally, there's a one-solid-color variation as a last-resort option.

The plaid is preserved, but it comes at the cost of complexity. Like the original logo, this design still requires multiple variations. It's not as easy to get right in application, but it maintains Slack's previous unique visual identity. It's a trade-off.

So, that's how I would approach this project. I'm still not feeling 100% with my design. It feels a bit too generic, like it needs another couple iterations to achieve its final form. But I'm putting my pencil down for now as it shows how plaid can work.

.•*•.• Plaid can work .•*•.•

BenCodeZen dragon mascot

4 Jan 2019 · by David DeSandro

BenCodeZen dragon mascot

DC area buddy Ben Hong has been pumping out front-end dev wisdom like wild. He pinged me about a logo for his personal brand BenCodeZen and I DELIVERED. Introducing Destinio!

Initial concepts were around dragons, Zen, and monograms.

BenCodeZen logo concepts

I was about to ship the Cute dragon design, but something was feeling off. It was looking a bit dopey.

BenCodeZen dragon mascot revision

The big change was bringing the outer circular shape up around its chest to its head. This did two things.

  1. It changed the position of head & neck so it was more up and back, giving it a more confident posture.
  2. It allowed the underbelly color to connect to the head, thus removing the need for an outline.

These changes made the dragon look more active and ready-to-rumble. It was a solid improvement, making for a simpler composition and a more iconic emblem.

BenCodeZen site