Tech veganism

Hand draw picture of a computer with vegetables on the screen

A year ago I wrote a blog post about living with an open-source phone. A commenter on Reddit described this as “tech veganism,” and I thought it was a great metaphor.

For the past few years I’ve swum in a lot of “tech veganism” circles (mostly thanks to Mastodon), so I think I have a good definition now:

  • a preference for open-source software over proprietary software
  • a suspicion of big tech companies
  • a high bar for privacy and security

The parallel with veganism is a good one for several reasons. First off, a lot of people find vegans annoying. “What, you think you’re better than me?” It’s a lot easier to eat animal products if you don’t think about where they come from, and vegans are an uncomfortable reminder of food’s icky origins. Plus, it’s never pleasant to think that someone might be silently judging you for your personal lifestyle choices.

Now imagine someone telling you they don’t use Google, Facebook, etc. “What, you think you’re better than me?”

Second, people don’t typically choose tech veganism because it’s a better user experience. Even though some vegans may swear that their black bean burger tastes just as good as your Angus beef, the honest ones will acknowledge that it’s more about principle than palate.

Similarly, there are plenty of tech vegans who will claim that OpenStreetMap is a great replacement for Google Maps, or that DuckDuckGo provides better search results than Google. But if they’re being honest with themselves, they’ll admit that they’re more motivated by principle than quality or convenience.

Third, tech veganism is a good way to alienate people. Talk about it enough, and you may get accused of being overly dour, negative, cynical, etc. Can’t you just eat a burger and enjoy it like a normal person? Why do you have to bring up factory farms all the time, and ruin my meal? Similarly: why can’t you just use Google like a normal person? Why do you have to drone on and on about LibreOffice and OpenBSD?

Tech veganism can even cost you friends. In the same way that having one vegan in the group severely limits your restaurant choices, being the one tech vegan among your friends can really narrow down the options for communication apps. Sure, you can ask them to use Signal. Or email. But most likely, the group chat will just happen without you, and you won’t be getting any Facebook invites.

Fourth, in some cases tech veganism is difficult if not downright impossible. If you’ve ever actually tried to go vegan (note: I have), you’ll find it’s a constant battle of reading ingredient lists to find the hidden references to milk, eggs, fish, etc. (Some surprising things that aren’t vegan: Worcestershire sauce, kimchi, even sugar.) And once you travel to a foreign country, you might find yourself surviving on bread and water, or else giving up entirely and grabbing a croque-monsieur.

Similarly, it’s almost impossible to avoid proprietary software or the tech giants. Consider this FOSDEM talk, where the executive director of the Software Freedom Conservancy admits to having proprietary software embedded inside her body, because that was the only option for a defibrillator. She advocates open-source software, and yet despite her best efforts, she’s a closed-source cyborg!

Try to avoid Google or Amazon and you may find yourself in a similar boat. There’s a great series of posts from Kashmir Hill where she shows that it’s nearly impossible to quit the tech giants because of how enmeshed they are in every app, website, and network request. It’s easier to find something vegan at a Brazilian barbecue than it is to eliminate big tech from your internet diet.

Another similarity: just as there are more vegetarians in India, tech veganism can be surprisingly region-specific. In particular, Europeans have more reason than Americans to embrace tech veganism, because the non-Chinese tech giants – Google, Apple, Facebook, Amazon, Microsoft, the dreaded GAFAM – are all American.

The dominance of American tech platforms in Europe, and especially all the data from European citizens being siphoned back to Silicon Valley, can feel like an issue of national sovereignty. Hence we have France opting for the open-source Matrix project for government communications, or organizations like Framasoft depicting themselves as a tiny Astérix-like village holding off foreign invaders. And the invaders really are foreign!

One place where the veganism metaphor breaks down is that, although nearly anyone can be a vegan, tech veganism is mostly practiced by those who are expert enough or privileged enough to learn the elaborate workarounds to avoid the GAFAMs of the world. Setting up an Ubuntu laptop, a LineageOS phone, a Fastmail account, and wiring it all together so that you actually get calendar notifications is no easy feat. You will probably have to get your hands dirty on the command line.

I find that there’s a bit of a “let them eat cake” attitude among tech vegan boosters, because they often discount the sheer difficulty of all this stuff. (“Let them use Linux” could be a fitting refrain.) After all, they figured it out, so why can’t you? What, doesn’t everyone have a computer science degree and six years experience as a sysadmin?

To be a vegan, all you have to do is stop eating animal products. To be a tech vegan, you have to join an elite guild of tech wizards and master their secret arts. And even then, you’re probably sneaking a forbidden bite of Google or Apple every now and then.

So where does that leave tech veganism? Well, for the near term, it’s probably going to remain the province of geeks and specialists due to the difficulties described above. Ironically, that means that it’ll mostly involve tech workers building products that other tech workers refuse to use. (Imagine if veganism were only practiced by employees of meat companies.)

I also suspect that tech veganism will begin to shift, if it hasn’t already. I think the focus will become less about open source vs closed source (the battle of the last decade) and more about digital well-being, especially in regards to privacy, addiction, and safety. So in this way, it may be less about switching from Windows to Linux and more about switching from Android to iOS, or from Facebook to more private channels like Discord and WhatsApp.

Generation Z has grown up with smartphones and app stores as an inescapable fact of their lives. Does anyone under 21 actually care whether the code on their phone is open-source and whether, Stallman-style, they can dive into an Objective-C file and change something? Probably not many. Does anyone in that demographic care about their phone’s impact on their anxiety, their quality time with friends and family, and their safety from harassment and abuse? Probably a lot more.

In my opinion, this change is a good thing. You shouldn’t have to enter an elite tech priesthood just to preserve your privacy, security, and safety online. Tech veganism should be as easy as regular veganism – it should just be an option on the menu. That doesn’t mean that it won’t suffer from many of the same problems as regular veganism, but at least it will be democratized.

Get off of Twitter

Twitter logo with a red "no" sign over it

Stop complaining about Twitter on Twitter. Deny them your attention, your time, and your data. Get off of Twitter.

The more time you spend on Twitter, the more money you make for Twitter. Get off of Twitter.

You at-mention @jack and call him out for the harassment and disinformation on his platform. You get a few hundred likes and retweets, each one sending your brain a little boost of serotonin. Twitter learns that you are interested in people who criticize @jack and starts to recommend you their tweets. You end up spending more time on Twitter, and advertisers learn a little bit more about you. You make @jack more money.

Get off of Twitter.

You can’t criticize Twitter on Twitter. It just doesn’t work. The medium is the message.

There’s an old joke where one fish says to the other, “How’s the water today?” And the fish responds, “What’s water?” On Twitter, you might ask, “How’s the outrage today?” (The answer, of course, is “I hate it! I’m so outraged about it!”)

Get off of Twitter.

Write blog posts. Use RSS. Use micro.blog. Use Mastodon. Use Pleroma. Use whatever you want, as long as it isn’t manipulating you with algorithms or selling access to your data to advertisers.

You’re worried about losing your influence. How about using your influence for something good? How about using it to stick it to Twitter, if you really dislike Twitter so much? Maybe if you do it, and your friends do it, then it will cause a sea change. After all, who was ever “influential” by following the crowd?

As Gandhi said (in paraphrase), “Be the change you want to see in the world.” Or as another influencer put it: “I’m starting with the man in the mirror.” Or if you prefer: “Practice what you preach.”

Get off of Twitter.

In defense of the Right Thing

It has come to my attention that many people believe the Wrong Thing. I find this to be an intolerable state of affairs, so this is a blog post defending what is Right.

How do I know there are so many people who believe the Wrong Thing? Well because, like everyone, I use Twitter. And holy moly! My feed is chock-full of Wrong Thinkers.

Sometimes it feels like everyone in the world believes the Wrong Thing, and I’m the last lonely person clinging to what’s Right. There must be a global epidemic of Wrongness. Why else would Twitter fill my feed with so many of these dunces and ninnies and halfwits?

I don’t even follow these people. Why should they be in my timeline, unless the whole world is full of Wrong people?

Every time I see their Wrong tweets, I seethe with rage and eagerly click to read the full thread. I might spend hours this way, thumbing through Wrong tweets. “How can so many people be so Wrong?” I’ll say to myself, shaking my head as I continue to scroll.

Sometimes when I find a really Wrong tweet, I’ll quote it and tweet it out with the perfect devastating repartee. That way, more people who agree with me are exposed to these Wrong views. That’ll teach ’em!

I do have to commend the others who proudly rise in defense of what is Right. On Twitter, I often see them caught in an epic battle with the Wrongers – “34 people are talking about this!” Well, here comes a 35th, joining the fray to fight the good fight.

To be honest, I sometimes get tired of feeling angry all the time. But how can I not be, when the world is full of people who are so very Wrong?

Curiously, the Wrongers seem to come from all sides of any issue, and they are legion. People who use margarine instead of butter, people who peel the banana from the top instead of the bottom, people who crack a boiled egg from the big end rather than the small end. These are exactly the things that drive me nuts, and somehow my feed is full of people who believe the opposite of me on precisely those issues! Sometimes I feel utterly embroiled, helpless, a tiny voice of reason shouting against an angry mob of Wrong Thinkers.

But sadly, this is just how the world is these days. The world is full of people arguing, calling each other out, or watching a fight unfold with the horrified glee of a driver craning their neck to get a good look at a car wreck.

I know this is how the world is, because I see it on Twitter. And Twitter is an utterly unbiased mirror of the world, with no algorithms that subtly push the discussion in one direction or the other, regardless of whether it is good for discourse or compassion or human well-being but only whether it is good for Twitter.

2018 book review

In the spirit of last year’s blog post, this is an extremely belated round-up of books I read in 2018.

I read a lot of books last year. I chalk this up to many things, but quitting Twitter was probably a big one. Without Twitter, I actually run out of things to read on the internet. At some point the internet gets boring, and it’s nice to have a few books around to pick up the slack.

A photo of books on a bookshelf

A completely unstaged photo of my remarkably tidy bookshelf

To keep things simple, I’ll focus on the books I actually enjoyed, rather than the ones I thought were duds. Who wants to read about boring books, anyway?

So without further ado:

Quick links

Fiction

Non-fiction

Fiction

Life’s too short not to enjoy good fiction. I don’t read it often enough, but when I do find a good novel, it’s like a breath of fresh air. I can immerse myself in another world for a while, and try to empathize with its characters.

This year I didn’t read a lot of fiction, but what I did read was very good.

Theory of Bastards by Audrey Schulman (2018)

What a remarkable book. I read it because I got a sudden hankering for post-apocalyptic fiction last year, plus there was a review in The Economist.

This book definitely doesn’t disappoint on the post-apocalyptic front, but it’s also just a great piece of pop-science drama. It’s clear that the author did their research (about bonobos in this case) and developed the characters with a lot of care. Strongly recommended.

Three Weeks in December by Audrey Schulman (2012)

This book is a bit harder to find, but I found it’s every bit as good as Schulman’s other book. Some well-researched science, a bit of colonial history, and once again Schulman’s keen eye for character development (even if her protagonist bears a resemblance to the one from Bastards). I may just have to read everything Schulman’s ever written.

Blindness by José Saramago (1995)

Continuing the post-apocalyptic trend, this is a tightly-written drama that captures what’s best about science fiction: an understanding of how humans react when put into unfamiliar situations, for good and for evil. Also it’s written in one of the most unique styles I’ve ever read – breathless, using mostly commas, with hardly a period to stop the flow of action.

Apparently there’s a movie, but the reviews were bad so I didn’t watch it. The book is great.

A Canticle for Leibowitz by Walter M. Miller Jr. (1959)

I promise I didn’t just read post-apocalyptic fiction this year. In any case, this book is considered a classic, but I found it to be three thinly-connected novellas where only the first one is worth reading. If you get bored during the second one, I’d say skip it.

What’s great about this book is its understanding for how humans behave during a dark age. Knowledge gets lost or deliberately destroyed, history becomes myth, cult becomes religion. It’s chilling to imagine how that may happen to our own civilization.

Never Let Me Go by Kazuo Ishiguro (2010)

Last post-apocalyptic fiction, I promise. This one is pretty good, although you’re better off not reading any reviews or synopses so as to not spoil the premise.

Also, if you’re expecting something like The Remains of the Day, then you should know that Never Let Me Go is not only very different thematically, but I also found it didn’t linger in my mind as much as Remains did. Still, it’s worth reading.

Once again, there’s a movie, but I haven’t seen it. I have no idea how you would adapt a book like this into a movie, but I guess that doesn’t stop people from trying.

A Tale for the Time Being by Ruth Ozeki (2013)

Marvelous book. Maybe as someone who’s studied French and Japanese, and who lives in the Pacific Northwest, and who has developed a middling interest in Buddhism, the book also seemed to speak to me in a eerily precise way.

If you’re a fan of wordplay, inventive storytelling, and Murakami-style magic realism, this is a great book to pick up.

Cherry by Nico Walker (2018)

A strange, haunting, disturbing book, but also a page-turner. Apparently this is Walker’s first book, and it’s really a virtuoso performance. I’ll be interested to see what he comes up with next.

The New York Trilogy by Paul Auster (1987)

A bizarre book. You get the impression that Paul Auster had one story to tell, but he couldn’t decide how to do it, so he wrote the same story three ways. Somewhat like Canticle, you’re probably better off just reading the first one and skipping the others.

Still, it’s worth it, especially if you’re a fan of hard-boiled detective fiction and surrealism.

Non-fiction

As usual for me, I read a lot of non-fiction last year. For the purposes of this list, though, I’m skipping about half the books I read, because a lot of them didn’t have much new to say, or didn’t really stick in my mind.

So this list contains only books I would recommend. (Note: that doesn’t mean I agree with every sentence that the author has ever uttered. Which should be obvious, but hey, on the internet, you’re rarely given the benefit of the doubt these days.)

Sapiens (2014), Homo Deus (2017), and 21 Lessons for the 21st Century (2018) by Yuval Noah Harari

I first came across Harari in this excellent Atlantic article, and I quickly devoured all three of his books. I’m not really sure what to say, except that he’s one of the most clever, funny, and innovative thinkers writing today. Sapiens in particular is a masterpiece of history, anthropology, and political science.

Harari has upset my thinking on a lot of things – in particular, how technology interacts with democracy and citizenship to potentially upend the relationship between the individual and the state in the 21st century. I also found his portrayal of factory farming as one of the biggest moral failures in modern human history to be very compelling (and not just because I’ve been an on-again off-again pescetarian for years).

But probably the best thing I can say about these books is that they’re all page-turners, despite the dense subject matter. Also, Harari isn’t afraid to veer into controversy, but he’s always clear about where he gets the facts that inform his opinions. (His conclusion in Sapiens that, scientifically, we just don’t know why humans are a patriarchal species was refreshingly honest.)

Some of the best non-fiction I’ve read in my life, and definitely worth picking up.

The Mechanical Horse by Margaret Guroff (2016)

A joyous book, a celebration of the bicycle and its impact on American society. Even if you’re not a cyclist, you may find this book interesting, just to see how much a simple two-wheeled vehicle has reshaped our culture.

If you want a preview, you can take a look at this excerpt on how bicycles did, in Susan B. Anthony’s words, “more to emancipate women than any one thing in the world.”

Enlightenment Now by Steven Pinker (2018)

Everyone’s already reviewed, rebutted, and counter-rebutted this book to death during 2018, but I’ll toss my hat in the ring as well.

This is maybe the most important book I read last year.

In terms of non-fiction, I’ve spent the last few years mostly reading what my wife calls “tech is destroying the world” books. So my non-fiction diet is generally very dire and gloomy and focused on all the problems in the world (and, as a techie, how I’m partially complicit in it). Maybe it’s no surprise then that I tend to be pretty pessimistic in my outlook.

This book aims to destroy that mindset with cold-hard data. And the thing is, I can’t argue with most of his points. The world really has gotten better over the past few centuries, unless you want to refute dozens of meticulously-researched charts and graphs.

I’ve read some of the rebuttals, and most of them pick one or two points and try to skewer them to death, as if that invalidates the entire book. But the book is over 400 pages; you can’t take exception with one or two pages and then pretend that it invalidates the main sweep of his argument.

I still retain some skepticism that mankind can effectively tackle climate change, the transition away from fossil fuels, the drug epidemic (Pinker’s one graph that doesn’t slope in the good direction), or the decline of liberal values, but Pinker gives about a hundred reasons for optimism. So for that, I’m grateful.

Why Liberalism Failed by Patrick Deneen (2018)

Now here’s a truly radical book, and one that might serve as a good contrast to Pinker’s. Deneen’s argument is basically that liberalism (in the sense of “Western liberalism,” or “the Washington consensus,” or whatever you want to call it) has become a victim of its own success. It works so well to elevate the individual – as a consumer, as a liberated sexual being, etc. – that it rips apart families and communities in the process.

Deneen might look at Pinker’s book and say, “Okay, so we’ve got all the material comfort we could possibly want, but maybe the human soul needs something more than that?”

One thought that this book helped crystallize in my head, along with Identity by Francis Fukuyama (which I read and thought was just okay) and Why Buddhism is True by Robert Wright (which I started but didn’t finish) is that there’s a lot of wisdom to the Buddhist idea that suffering is caused by desire, and you can’t really address your suffering without addressing your desire.

Here’s Deneen:

“[H]uman appetite is insatiable and the world is limited. For both of these reasons, we cannot be truly free in the modern sense. We can never attain satiation, and will be eternally driven by our desires rather than satisfied by their attainment. And in pursuit of the satisfaction of our limitless desires, we will very quickly exhaust the planet.” (p125, hardcover)

Some of these arguments you may even call environmentalist. Others, like his critique of free markets, you might call anticapitalist. Despite broadly coming across as something like “radical reactionary paleo-conservative,” Deneen is hard to pin down.

I can’t really do this book justice by summarizing it here, as Deneen is such an original thinker that it’s best to let him explain his arguments himself. I don’t agree with him on everything, but I think if you want to understand the recent decline in liberal values, this book (as well as Edward Luce’s The Retreat of Western Liberalism, which I reviewed last year) would be a good place to start.

Thinking, Fast and Slow by Daniel Kahneman (2011)

This might be the second most important book I read last year (after Pinker’s). It’s a good overview of all the ways that our brains can fool us, and how statistical thinking can help reshape your perception of the world.

One part that stood out to me was the story of the Israeli flight instructor who would always criticize his students after a bad flight, and praise them after a good flight. And since a bad flight is usually followed by a better one, but a good flight is usually followed by a worse one, he concluded that criticism works, but praise doesn’t.

Kahneman points out that this is really just an expression of regression to the mean. If he had been berating his students on how high of a dice roll they got (“You got a six, stupendous!” or “You got a one, try harder!”) he would get exactly the same effect. The widespread belief in things like “streaks” and “hot hands,” though, shows how far most folks are from internalizing this basic statistical concept.

I’m sure this book hasn’t totally cured me of my monkey-brain misconceptions, but hopefully I’ll be able to catch a few more of them now.

Ten Arguments for Deleting Your Social Media Accounts Right Now by Jaron Lanier (2018)

Despite the snippy title, this is a well-thought-out and sobering book that puts a lot of recent social media controversies into perspective. I like how Lanier draws a line from Twitter and Facebook all the way back to old-school message boards.

This book has made me more skeptical of social media in general (even after deleting my Twitter account). If nothing else, reading this book is a good way to reflect on one own’s social media usage, and whether or not it’s a healthy relationship.

“Briefly I was one of the HuffPost’s top bloggers, always on the front page. But I found myself falling into that old problem again whenever I read the comments, and I could not get myself to ignore them. I would feel this weird low-level boiling rage inside me. Or I’d feel this absurd glow when people liked what I wrote, even if what they said didn’t indicate that they had paid much attention to it. Comment authors were mostly seeking attention for themselves.

We were all in the same stew, manipulating each other, inflating ourselves. (pp42-43, hardcover)

Atrocities by Matthew White (2011)

The funniest book about war, genocide, and famine that you’ll ever read. If it doesn’t sound like “funniest” belongs in the same sentence with those words, it’s best to pick up the book yourself to understand what I mean.

This book is not only well-researched and educational; it’s also a masterpiece of black humor that will make you gape and shake your head at the depths of human stupidity.

On Genghis Khan:

“Keep in mind that even with 16 million [living] descendants, Genghis Khan hasn’t replaced the number of people he killed.” (p115, 2013 edition)

On the Time of Troubles:

  • Location: Russia
  • Number of Dmitris: 4
  • Lesson learned: Always insist on seeing a photo ID before you proclaim someone emperor. (p207, 2013 edition)

There’s more, but I’d hate to spoil it by quoting it at length. In any case, it’s a hard book to put down, and a good conversation-starter to leave on a coffee table.

The Stranger in the Woods by Michael Finkel (2017)

A “strange but true” story about a guy who lived alone in the woods for 27 years. Pretty fascinating story, and a good meditation on what it means to live with other people, and why some might try to escape it.

The Blank Slate by Steven Pinker (2002)

I was intrigued by Pinker’s Enlightenment Now, so I picked this one up. It’s a bit older, but its core argument is still relevant. It does a great job of unmasking a kind of lazy thinking that denies any evidence from biology that might be politically inconvenient. (On both the left and the right, but I think Pinker focuses on the left because that’s his target audience.)

Something this book helped me realize is that, if I have a core political belief, it’s that evidence and facts matter. Unfortunately there’s a growing strain of thought across the political spectrum that emphasizes lived experiences, feelings, and political expediency at the expense of evidence and a shared set of facts. It argues that science is a tool of oppression, and “facts” are only useful for information warfare.

I can appreciate the anti-elitism and distrust of authority that motivates a lot of this thinking, but I also think it’s inherently dangerous. Science, reason, and liberalism have lifted a large chunk of humanity out of poverty and misery, and we abandon them at our own risk.

The Curse of Bigness by Tim Wu (2018)

In a year conspicuously absent of “tech is destroying the world” books on my bookshelf (or at least, on this list), this one stands out. It’s short, it’s sweet, and it captures our present tech moment very well by identifying the main problem as being a political one, rather than an economic or a technical one.

Essentially, this is a history of antitrust and anti-antitrust thinking. Wu’s other books (The Master Switch and The Attention Merchants) did a great job of tying together present trends with a history lesson, and this book offers more of the same. Well worth a read.

Living with Tinnitus by Laura Cole (2017)

This is a very personal inclusion on this list, but I’ll put it here anyway.

Last year I developed tinnitus, which means that I constantly hear a low, high-pitched buzzing in my ears. It affects a large number of people (10-15% of the population according to Wikipedia), but surprisingly few talk about it.

How did I get it? Probably from listening to too many podcasts on the bus without noise-canceling headphones. Or maybe an ear infection. To be honest, I’m not sure.

When it first developed, it was scary and frustrating. I went to an audiologist, but they just ran some tests, told me my hearing was fine, and sent me on my way with a short pamphlet on tinnitus. For several months it affected my sleep, my mood, and my social life, but I wasn’t really sure what to do about it.

Almost a year later, I can say that my tinnitus doesn’t really bother me at all, and I rarely think about it, even though it’s the first thing I hear in the morning and the last thing I hear at night. This book was one of the things that helped with that.

As it turns out, tinnitus doesn’t have a lot of research. Reading internet forums can just make you more scared, as the symptoms and severity can vary wildly. This book acknowledges the lack of evidence, but offers a wide range of potential solutions, mitigations, and coping mechanisms. The author is also very clear about which ones have strong evidence and which ones don’t.

If you or one of your loved ones has tinnitus, I’d strongly recommend this book.

Building a modern carousel with CSS scroll snap, smooth scrolling, and pinch-zoom

Recently I had some fun implementing an image carousel for Pinafore. The requirements were pretty simple: users should be able to swipe horizontally through up to 4 images, and also pinch-zoom to get a closer look.

The finished product looks like this:

 

Often when you’re building something like this, it’s tempting to use an off-the-shelf solution. The problem is that this often adds a large dependency size, or the code is inflexible, or it’s framework-specific (React, Vue, etc.), or it may not be optimized for performance and accessibility.

Come on, it’s 2019. Isn’t there a decent way to build a carousel with native browser APIs?

As it turns out, there is. My carousel implementation uses a few simple building blocks:

  1. CSS scroll snap
  2. scrollTo() with smooth behavior
  3. The <pinch-zoom> custom element

CSS scroll snap

Let’s start off with CSS scroll snap. This is what makes the scrollable element “snap” to a certain position as you scroll it.

The browser support is pretty good. The only trick is that you have to write one implementation for the modern scroll snap API (supported by Chrome and Safari), and another for the older scroll snap points API (supported by Firefox[1]).

You can detect support using @supports (scroll-snap-align: start). As usual for iOS Safari, you’ll also need to add -webkit-overflow-scrolling: touch to make the element scrollable.

But lo and behold, we now have the world’s simplest carousel implementation. It doesn’t even require JavaScript – just HTML and CSS!

Note: for best results, you may want to view the above pen in full mode.

The benefit of having all this “snapping” logic inside of CSS rather than JavaScript is that the browser is doing the heavy lifting. We don’t have to use touchmove listeners or requestAnimationFrame to try to get the pixel-perfect snapping behavior with the right animation curve – the browser handles all of it for us, in native code.

And unlike touchmove, this scroll-snapping works for any method of scrolling – touchpad, touchscreen, scrollbar, you name it.

scrollTo() with smooth scrolling

The next piece of the puzzle is that most carousels have little indicator buttons that let you navigate between the items in the list.

Screenshot of a carousel containing an image of a cat with indicator buttons below showing 1 filled circle and 3 unfilled circles

For this, we will need a little bit of JavaScript. We can use the scrollTo() API with {behavior: 'smooth'}, which tells the browser to smoothly scroll to a given offset:

function scrollToItem(itemPosition, numItems, scroller) {
  scroller.scrollTo({
    scrollLeft: Math.floor(
      scroller.scrollWidth * (itemPosition / numItems)
    ),
    behavior: 'smooth'
  })
}

The only trick here is that Safari doesn’t support smooth scroll behavior and Edge doesn’t support scrollTo() at all. But we can detect support and fall back to a JavaScript implementation, such as this one.

Here is my technique for detecting native smooth scrolling:

function testSupportsSmoothScroll () {
  var supports = false
  try {
    var div = document.createElement('div')
    div.scrollTo({
      top: 0,
      get behavior () {
        supports = true
        return 'smooth'
      }
    })
  } catch (err) {}
  return supports
}

Being careful to set aria-labels and aria-pressed states for the buttons, and adding a debounced scroll listener to update the pressed state as the user scrolls, we end up with something like this:

View in full mode

You can also add generic “go left” and “go right” buttons; the principle is the same.

Hiding the scrollbar (optional)

Now, the next piece of the puzzle is that most carousels don’t have a scrollbar, and depending on the browser and OS, you might not like how the scrollbar appears.

Also, our carousel already includes all the buttons needed to scroll left and right, so it effectively has its own scrollbar. So we can consider removing the native one.

To accomplish this, we can start with overflow-x: auto rather than overflow-x: scroll, which ensures that at least if there’s only one image (and thus no possibility of scrolling left or right), the scrollbar doesn’t show.

Beyond that, we may be tempted to add overflow-x: hidden, but this actually makes the list entirely unscrollable. Bummer.

So we can use a little hack instead. Here is some CSS to remove the scrollbar, which works in Chrome, Edge, Firefox, and Safari:

.scroll {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.scroll::-webkit-scrollbar {
  display: none;
}

And it works! The scrollbar is gone:

View in full mode

Admittedly, though, this is a bit icky. The only standards-based CSS here is scrollbar-width, which is currently only supported by Firefox. The -webkit-scrollbar hack is for Chrome and Safari, and the -ms-overflow-style hack is for Edge/IE.

So if you don’t like vendor-specific CSS, or if you think scrollbars are better for accessibility, then you can just keep the scrollbar around. Follow your heart!

Pinch-zoom

For pinch-zooming, this is one case where I allowed myself an indulgence: I use the <pinch-zoom> element from Google Chrome Labs.

I like it because it’s extremely small (5.2kB minified) and it uses Pointer Events under the hood, meaning it supports mobile touchscreens, touchpads, touchscreen laptops, and any device that supports pinch-zooming.

However, this element isn’t totally compatible with a scrollable list, because dragging your finger left and right causes the image to move left and right, rather than scroll left and right.

 

I thought this was actually a nice touch, though, since it allows you to choose which part of the image to zoom in on. So I decided to keep it.

To make this work inside a scrollable carousel, though, I decided to add a separate mode for zooming. You have to tap the magnifying glass to enable zooming, at which point dragging your finger moves the image itself rather than the carousel.

Toggling the pinch-zoom mode was as simple as removing or adding the <pinch-zoom> element to toggle it [2]. I also decided to add some explicit “zoom in” and “zoom out” buttons for the benefit of users who don’t have a device that supports pinch-zooming.

 

Of course, I could have implemented this myself using raw Pointer Events, but <pinch-zoom> offers a small footprint, a nice API, and good browser compatibility (e.g. on iOS Safari, where Pointer Events are not supported). So it felt like a worthy addition.

Intrinsic sizing

The last piece of the puzzle (I promise!) is a way to keep the images from doing a re-layout when they load. This can lead to janky-looking reflows, especially on slow connections.

 

Assuming we know the dimensions of the images in advance, we can fix this by using the intrinsicsize attribute. Unfortunately this isn’t supported in any browser yet, but it’s coming soon to Chrome! And it’s way easier than any other (hacky) solution you may think of.

Here it is in Chrome 72 with the “experimental web platform features” flag enabled:

 

Notice that the buttons don’t jump around while the image loads. Much nicer!

Accessibility check

Looking over the WAI Carousel Concepts document, there are a few good things to keep in mind when implementing this carousel:

  1. To make the carousel more keyboard-navigable, you may add keyboard shortcuts, for instance and to navigate left and right. (Note though that a scrollable horizontal list can already be focused and scrolled with the keyboard.)
  2. Use <ul> and <li> elements instead of <div>s, so that a screen reader announces it as a list.
  3. The smooth-scrolling can be distracting or nausea-inducing for some folks, so respect prefers-reduced-motion or provide an option to turn it off.
  4. As mentioned previously, use aria-label and aria-pressed for the indicator buttons.

Compatibility check

But what about IE support? I can hear your boss screaming at you already.

If you’re one of the unfortunate souls who still has to maintain IE11 support, rest assured: a scroll-snap carousel is just a normal horizontal-scrolling list on IE. It doesn’t work exactly the same, but hey, does it need to? IE11 users probably don’t expect the best anymore.

Conclusion

So that’s it! I decided not to publish this as a library, and I’m leaving the pinch-zooming and intrinsic sizing as an exercise for the reader. I think the core building blocks are simple enough that folks really ought to just take the native APIs and run with them.

Any decisions I could bake into a library would only limit the flexibility of the carousel, and leave its users high-and-dry when they need to tweak something, because I’ve taught them how to use my library instead of the native browser API.

At some point, it’s just better to go native.

Footnotes

1. For whatever reason, I couldn’t get the old scroll snap points spec to work in Edge. Sarah Drasner apparently ran into the same issue. On the bright side, though, a horizontally scrolling list without snap points is just a regular horizontally scrolling list!

2. The first version of this blog post recommended using pointer-events: none to toggle the zoom mode on or off. It turns out that this breaks right-clicking to download an image. So it seems better to just remove or add the <pinch-zoom> element to toggle it.

Things I’ve been wrong about, things I’ve been right about

The end of the year is a good time for reflection, and this year I’m going to do something a bit different. I’d like to list some of the calls I’ve made over the years, and how well those predictions have turned out.

So without further ado, here’s a list of things I’ve been wrong about or right about over the years.

Quick links:

Wrong: web workers will take over the world

Around 2015, I got really excited by web workers. I gave talks, I wrote a blog post, and I wrote an app that got a fair amount of attention. Unfortunately it turned out web workers were not going to take over the world in the way I imagined.

My enthusiasm for web workers mostly came from my experience with Android development. In Android development, if you don’t want your app to be slow, you move work to a background thread. After I became a web developer, I discovered it was suddenly very hard to make apps that weren’t janky. Oh, the web browser only has one thread? Well, there’s your problem.

What I didn’t know at the time, though, was that browsers already had a lot of tricks for moving work off the main thread; they’re just not necessarily very obvious, or directly exposed to web developers. You can see my ignorance in this video, where I’m purportedly showing the performance advantages of my worker-powered Pokémon app by scrolling the screen on mobile Chrome.

As I learned later, though, scrolling runs off-main-thread in modern browsers (and more importantly, composited). So the only thing that’s going to make this scrolling smoother is to not block it with unnecessary touchstart/touchmove listeners, or for the Chrome team to improve their scrolling implementation (as in fact, they have been doing). There are also differences between subscrollers and main-document scrollers, as I learned later.

All of these things are non-obvious to web developers, because they’re not directly exposed in an API. So in my ignorance, I pointed to the one case where threading is exposed in a web API, i.e. web workers.

While it is true, though, that blocking the main thread is a major cause of slowdowns in web pages, web workers aren’t the panacea I imagined. The reasons are laid out very succinctly by Evan You in this talk, but to summarize his points: moving work from the main thread to a background worker is very difficult, and the payoff is not so great.

The main reason it’s difficult is that you always have to come back to the main thread to do work on the DOM anyway. This is what libraries like worker-dom do. Also, some APIs can only be invoked synchronously on the main thread, such as getBoundingClientRect. Furthermore, as pointed out by Pete Hunt, web workers cannot handle preventDefault or stopPropagation (e.g. in a click handler), because those must be handled synchronously.

So on the one hand, you can’t just take existing web code and port it to a web worker; there are some things that have to be tweaked, and other things that are just impossible. Then on the other hand, moving things to a worker creates its own costs. The cost of cloning data between threads can be expensive (note: to be fair, Chrome has improved their cloning performance since I wrote that post). There is also a built-in latency when sending messages between the two threads, so you don’t necessarily want to pay that round-trip cost for every interaction. Also, some work has to be done on the main thread anyway, and it’s not guaranteed that those costs are the small ones.

Since then, I’ve come to believe that the best way to avoid the cost of main thread work (such as virtual DOM diffing in a library like React) is not by moving it to a background thread, but rather by skipping it entirely. SvelteJS does this, as explained in this talk by Rich Harris. Also, you can use APIs like requestIdleCallback to delay work on the main thread. Future APIs like hasPendingUserInput may help as well.

Of course, I’m not saying that web workers should never be used. For long-running computations that don’t rely on the DOM, they’re definitely useful. And perhaps sometime in the future it will become more viable to run your “entire app” in a worker thread, as sketched out here by Jason Miller. APIs like SharedArrayBuffer, blöcks, and some kind of asynchronous preventDefault/stopPropagation may tip the balance in web workers’ favor. But for now I’ll say that I was wrong on this call.

Wrong: Safari is the new IE

“Safari is the new IE” is probably my most-read post of all time, since it got picked up by Ars Technica. Unfortunately I’ve learned a lot about how the browser industry works since I wrote it, and nowadays I regard it with a bit of embarrassment.

As it turns out, Safari is not really the new IE. At the time I wrote that post (2015), the WebKit team was dragging their feet a bit, but since then they’ve really picked up the pace. If you look at metrics like HTML5Test, CanIUse, or ES2015+ compatibility tables, you’ll see they’ve made a lot of progress since 2015. They’re still behind Chrome and Firefox, but they’re giving Edge a run for its money (although Edge is now switching to Chromium, so that’s less relevant).

Also, the WebKit team does a lot of work that is less obvious to web developers, but which they still deserve credit for. Safari is a beast when it comes to performance, and they often set the standard that other engines aim to beat. It’s no surprise that the Speedometer benchmark came from the WebKit team (with Safari originally winning), and quickly became a point of focus for Chrome, Edge, and Firefox. The MotionMark and JetStream benchmarks also originally came from WebKit.

The WebKit team also does some interesting privacy work, including intelligent tracking protection and double-keying of cross-origin storage. (I.e. if example.com stores data in an iframe inside of another website, that data will not be shared with example.com itself or other example.com iframes on other websites. This limits this ability of sites to do third-party tracking.)

To be clear, though, I don’t regret writing that blog post. It was a cry of anger from a guy who was tired of dealing with a lot of IndexedDB bugs, which the WebKit team eventually got around to fixing. Heck, I’ve been told that my blog post may have even motivated Apple to make those fixes, and to release excellent developer-facing features like Safari Technology Preview. So kudos, WebKit team: you proved me wrong!

In any case, it’s unlikely that we’ll ever have a situation like IE6 again, with one browser taking up 95% of all usage. The best contender for that title is currently Chrome, and although it ticks some of the IE6 boxes (outsized influence on the ecosystem, de-facto standardization of implementation details), it doesn’t tick some other ones (lack of investment from the company building it, falling behind on web standards). The state of browser diversity is certainly worrying, though, which makes it all the more important to support non-Chromium browsers like Safari and Firefox, and give them credit for the good work they’re doing.

So in that regard, I am sorry for creating a meme that still seems to stick to this day.

Right: developer experience is trumping user experience

This blog post didn’t get a lot of attention when I published it in early 2016, but I think I tapped into something that was happening in the web community: web developers were starting to focus on obscure developer-facing features of frontend frameworks rather than tangible benefits for end-users.

Since then, this point has been articulated particularly well by folks on the Chrome team and at Google, such as Malte Ubl (“Developer experience and user experience,” 2017) and Alex Russell (“The developer experience bait-and-switch,” 2018). Paul Lewis also touched on it a bit in late 2015 in “The cost of frameworks”.

Developer experience (DX) vs user experience (UX) is now a topic of hot debate among web developers, and although I may not have put my finger on the problem very well, I did start writing about it in early 2016. So I’ll chalk this up as something I was right about.

Right: I’m better off without a Twitter account

I deleted my Twitter account a little over a year ago, and I have no regrets about that.

Twitter has made some good moves in the past year, such as as bringing back the chronological timeline, but overall it’s still a cesspool of negativity, preening, and distractions. Also, I don’t believe any one company should have a monopoly on microblogging, so I’m putting my money where my mouth is by denying them my attention and ad revenue.

These days I use Mastodon and RSS, and I’m much happier. Mastodon in particular has served as a kind of nicotine patch for my Twitter addiction, and for that I’m grateful.

The fediverse does have some of the same negative characteristics as Twitter (brigading, self-righteousness, lack of nuance), but overall it’s much smaller and quieter than Twitter, and more importantly less addictive, so I use social media less these days than I used to. I tend to spend more time on my hobbies instead, one of which is (ironically) building a Mastodon client!

Right: the cost of small modules

“The cost of small modules” was one of my most-read posts of 2016, and in terms of the overall conclusions, I was right. JavaScript compilation and initial execution are expensive, as has been covered quite well by Addy Osmani in “The cost of JavaScript”.

Furthermore, a lot of the bloat was coming from the bundlers themselves. In the post, I identified Browserify and Webpack as the main offenders, with Closure Compiler and Rollup showing how to do it right. Since I wrote that post, though, Webpack and Browserify have stepped up their game, and now module concatenation is a standard practice for JavaScript bundlers.

One thing I didn’t understand at the time was why JavaScript compilation was so expensive for the “function-wrapping” format of bundlers like Webpack and Browserify. I only realized it later when researching some quirks about how JavaScript engines parse function bodies. The conclusions from that research were interesting, but the larger takeaway of “only include the code you need” was the important one.

Mixed: progressive enhancement isn’t dead, but it smells funny

For better or worse, progressive enhancement doesn’t seem to be doing very well these days. In retrospect, this blog post was more about Twitter shaming (see above for my thoughts on Twitter), but I think the larger point about progressive enhancement losing its cachet is right.

As we slowly enter a world where there is one major browser engine (Chromium), which is frequently updated and leading on web standards, supporting old or weird browsers just becomes less important. Developers have already voted with their feet to target mostly Chrome and Chrome derivatives, putting pressure on other browsers to either adopt Chromium themselves or else bleed users (and therefore relevance). It’s a self-perpetuating cycle – the less developers care about progressive enhancement, the less it matters.

I also believe the term “progressive enhancement” has been somewhat co-opted by the Chrome devrel team as as euphemism for giving the best experience to Chrome and a poorer experience to “older browsers” (aka non-Chrome browsers). It’s a brilliant re-branding that feeds into web developers’ deepest wish, which is to live in a Chrome-only world where they only have to focus on Chrome.

That’s not to say progressive enhancement is without its virtues. Insofar as it encourages people to actually think about accessibility, performance, and web standards, it’s a good thing. But these days it’s becoming less about “build with HTML, layer on CSS, sprinkle on JavaScript” and more about “support a slightly older version of Chrome, target the latest version of Chrome.”

The other point I made in that blog post, which was about JavaScript-heavy webapps being better for the “next billion” Internet users, may turn out to be wrong. I’m not sure. Static websites are certainly easier on the user’s battery, and with a Service Worker they can still have the benefits of offline capabilities.

Perhaps with the new Portals proposal, we won’t even need to build SPAs to have fancy transitions between pages. I have a hunch that SPAs are being overused these days, and that user experience is suffering as a consequence, but that’s another bet that will have to be evaluated at a later date.

Conclusions

So that’s all for my roundup of bad takes, good takes, and the stuff in between. Hope you found it interesting, and happy 2019!

Scrolling the main document is better for performance, accessibility, and usability

When I first wrote Pinafore, I thought pretty deeply about some aspects of the scrolling, but not enough about others.

For instance, I implemented a custom virtual list in Svelte.js, as well as an infinite scroll to add more content as you scroll the timeline. When it came to where to put the scrollable element, though, I didn’t think too hard about it.

Screenshot of Pinafore UI showing a top nav with a scrollable content below

A fixed-position nav plus a scrollable section below. Seems simple, right? I went with what seemed to me like an obvious solution: an absolute-position element below the nav bar, which could be scrolled up and down.

Then Sorin Davidoi opened this issue, pointing out that using the entire document (i.e. the <body>) as the scrolling element would allow mobile browsers to hide the address bar while scrolling down. I wasn’t aware of this, so I went ahead and implemented it.

This indeed allowed the URL bar to gracefully shrink or hide, across a wide range of mobile browsers. Here’s Safari for iOS:

And Chrome for Android:

And Firefox for Android:

As it turned out, though, this fix solved more than just the address bar problem – it also improved the framerate of scrolling in Chrome for Android. This is a longstanding issue in Pinafore that had puzzled me up till now. But with the “document as scroller” change, the framerate is magically improved:

Of course, as the person who wrote one of the more comprehensive analyses of cross-browser scrolling performance, this really shouldn’t have surprised me. My own analysis showed that some browsers (notably Chrome) hadn’t optimized subscrolling to nearly the same degree as main-document scrolling. Somehow, though, I didn’t put two-and-two together and realize that this is why Pinafore’s scrolling was janky in Chrome for Android. (It was fine in Firefox for Android and Safari for iOS, which is also perhaps why I didn’t feel pressed to fix it.)

In retrospect, the Chrome Dev Tools’s “scrolling performance issues” tool should have been enough to tip me off, but I wasn’t sure what to do when it says “repaints on scroll.” Nor did I know that moving the scrolling element to the main document would do the trick. Most of the advice online suggests using will-change: transform, but in this case it didn’t help. (Although in the past, I have found that will-change can improve mobile Chrome’s scrolling in some cases.)

Screenshot of Pinafore with a blue overlay saying "repaints on scroll."

The “repaints on scroll” warning. This is gone now that the scrollable element is the document body.

As if the mobile UI and performance improvements weren’t enough, this change also improved accessibility. When users first open Pinafore, they often want to start scrolling by tapping the “down” or “PageDown” key on the keyboard. However, this doesn’t work if you’re using a subscroller, because unlike the main document, the subscroller isn’t focused by default. So we had to add custom behavior to focus the scrollable element when the page first loads. Once I got rid of the subscroller, though, this code could be removed.

Another nice fix was that it’s no longer necessary to add -webkit-overflow-scrolling: touch so that iOS Safari will use smooth scrolling. The main document already scrolls smoothly on iOS.

This subscroller fix may be obvious to more experienced web devs, but to me it was a bit surprising. From a design standpoint, the two options seemed roughly equivalent, and it didn’t occur to me that one or the other would have such a big impact, especially on mobile browsers. Given the difference in performance, accessibility, and usability though, I’ll definitely think harder in the future about exactly which element I want to be the scrollable one.

Note that what I’m not saying in this blog post is that you should avoid subscrollers at all costs. There are some cases where the design absolutely calls for a subscroller, and the fact that Chrome hasn’t optimized for this scenario (whereas other browsers like Firefox, Edge, and Safari have) is a real bug, and I hope they’ll fix it.

However, if the visual design of the page calls for the entire document to be scrollable, then by all means, make the entire document scrollable! And check out document.scrollingElement for a good cross-browser API for managing the scrollTop and scrollHeight.

Update: Steve Genoud points out that there’s an additional benefit to scrolling the main document on iOS: you can tap the status bar to scroll back up to the top. Another usability win!

Update: Michael Howell notes that this technique can cause problems for fragment navigation, e.g. index.html#fragment, because the fixed nav could cover up the target element. Amusingly, I’ve noticed this problem in WordPress.com (where my blog is hosted) if you navigate to a fragment while logged in. I also ran into this in Pinafore in the case of element.scrollIntoView(), which I worked around by updating the scrollTop to account for the nav height right after calling scrollIntoView(true). Good to be aware of!