Aaron Gustafson's Blog, page 2

December 15, 2023

Sharing in the Age of 3p Cookie-mageddon

Over a decade ago, I wrote up detailed instructions on how to enable users to share your content on social media without allowing them to be tracked by every social media site via cookies. In a few short weeks ���third party��� cookies will get the boot in Chromium-based browsers. If you���re still relying on third party share widgets on your site, your users may start seeing problems. Now is a good time to replace them with code that Just Works���. Here���s how���

# Sharing, the Old-fashioned Way

When it comes to sharing, there are myriad ways to do it. If you���re at all familiar with my work, it should come as no surprise that I always start with a universally-useable and accessible baseline and then progressively enhance things from there. Thankfully, every social media site I commonly use (with the exception of the Fediverse) makes this pretty easy by providing a form that accepts inbound content via the query string.1 For example, here is LinkedIn���s: https://www.linkedin.com/cws/share. Adding a url to the query string lets you share that link in automatically. You can try it by clicking this link.

Each service is a little different, but all function similarly. I support the following ones in this site:

Social Media Sites and Their Sharing URLsSiteDestinationURLOptional ParamsTwitter / Xhttps://twitter.com/intent/tweeturlHacker Newshttps://news.ycombinator.com/submitlinkut = the title you want to share Facebookhttp://www.facebook.com/sharer.phpuLinkedInhttps://www.linkedin.com/cws/shareurlPinteresthttp://pinterest.com/pin/create/button/urlmedia = an image to share
description = the text you want to share

Using this information, I created a partial template for use on any page in this site (though I mainly use it on blog posts right now). Each link includes useful text content (e.g., ���Share on ______���) and a local SVG of the service���s icon. Here���s a simplified overview of the markup I use:

<ulclass=���social-links social-links���share���>
<liclass=���social-links__item���>
<ahref=���{{ SHARE URL }}���class=���social-link���rel=���nofollow���>
<svg>{{ SERVICE ICON }}svg>
<bclass=���social-link__text���>Share on {{ SERVICE NAME }}b>
a>
li>
ul>

You can check out the baseline experience on this very page by disabling JavaScript.

My baseline sharing component is a list of icon links.

It���s worth noting that I have chosen not to enforce opening these links in a new tab. You can do that if you like, but on mobile devices I���d prefer the user just navigate to the share page directly. You may have a different preference, but if you decide to spawn a new tab, be sure your link text lets folks know that���s what will happen. I do include a rel="nofollow" on the link, however, to prevent search spiders from indexing the share forms.

If you test out these links, you���ll notice many of the target forms will pick up a ton of information from your page automatically. By and large, this info is grabbed from your page���s Open Graph data (stored in meta tags) or Linked Data (as JSON-LD). You can write that info to your page by hand or use a plugin to generate it for you automatically. There are a ton of options out there if you choose to go the later route (which I���d recommend).

# Enhancement Level 1: Popup Share

If you played around with any of the various share forms, you probably noticed that they are, by and large, designed as discrete interactions best-suited to a narrow window (e.g., mobile) or popup. To provide that experience, I���ve long-relied on a little bit of JavaScript to launch them in a new, appropriately-sized window:

functionpopup(e){
var $link = e.target;
while( $link.nodeName.toLowerCase()!=���a���){
$link = $link.parentNode;
}
e.preventDefault();
var popup = window.open( $link.href,���share���,
���height=500,width=600,status=no,toolbar=no,popup���
);
try{
popup.focus();
e.preventDefault();
}catch(e){}
}

var screen_width =���visualViewport���in window ?
window.visualViewport.width : window.innerWidth,
$links = document.querySelectorAll(
���.social-links���share a���
),
count = $links.length;

if( screen_width >600){
while( count���){
$links[count].addEventListener(���click���, popup,false);
$links[count].querySelector(
���.social-link__text���
).innerHTML +=" (in a popup)";
}
}

The first chunk defines a new function called popup() that will act as the event listener. It takes the event (e) as an argument and then finds the associated link (bubbling up through the DOM as necessary in that while loop). Once it finds the link, the function opens a new popup window (using window.open()). Then, to check if the popup was blocked, it attempts (within the try���catch) to focus it. If the focus succeeds, which means the popup wasn���t blocked, the script prevents the link from navigating the user to the href (which is the default behavior, hence e.preventDefault()).

The second block defines a couple of variables we���ll need. First, it captures the current screen_width using either the window���s visualViewport (if available) or its innerWidth (which is more old school). Next it grabs the social links ($links) and counts them for looping purposes (count).

The final block is a conditional that checks to see if the screen_width is wider than 600px (an arbitrary width that just feels right��� your mileage may vary). If the screen is wider than that threshold, it loops through the links,2 adds the click handler, and adds some text to the link label to let folks know it will open a popup.

And with that, the first layer of enhancement is complete: Users with JavaScript support who also happen to be using a wider browser window will get the popup share form if the popup is allowed. If the popup isn���t allowed, they���ll default to the baseline experience.

# Enhancement Level 2: OS Share

A few years back, browsers began participating in OS-level share activities. On one side, this allowed websites to share some data���URLs, text, files���to other apps on the device via navigator.share(). On the other side of the equation, Progressive Web Apps could advertise themselves���via the Manifest���s share_target member���as being able to receive content shared in this way.

Sharing a URL and text is really well supported. That said, it���s only been around a few years at this point and some browsers require an additional permission to use the API.3 For these reasons, it���s best to use the API as a progressive enhancement. Thankfully, it���s easy to test for support:

if(���share���in navigator ){
// all good!
}

For my particular implementation, I���ve decided to swap out the individual links for a single button that, when clicked, will proffer the page���s details over to the OS���s share widget. Here���s the code I use to do that:

var $links = document.querySelector(���.social-links���share���),
$parent = $links.parentNode,
$button = document.createElement(���button���),
title = document.querySelector(���h1.p-name,title���).innerText,
$description = document.querySelector(
���meta[name=���og:description���],meta[name=���description���]���
),
text = $description ? $description.getAttribute(���content���)
:������,
url = window.location.href;

$button.innerHTML =���Share ������;
$button.addEventListener(���click���,function(e){
navigator.share({ title, text, url });
});

$parent.insertBefore($button, $links);
$links.remove();

The first block sets up my variables:

$links - A reference to the list (ul) of sharing links;$parent - the parent container of that list;$button - the button I���m going to swap in for the links;title - The page title (either from the page���s h1 or title element);$description - A reference to a meta description element;text - The text content of that description, if one is found; andurl - The URL to be shared.

The second block sets up the button by inserting the text ���Share��� and an SVG share icon and setting an event listener on it that will pass the collected info to navigator.share().

The third and final block swaps out the link list for the button.

# Putting It All Together

The final step to putting this all together involves setting up the conditional that determines which enhancement is offered. To keep everything a bit cleaner, I���m also moving each of the enhancements into its own function:

!(function(window, document, navigator){

functionprepForPopup(){
// popup code
}
functionpopup(){
// popup event handler
}
functionswapForShareAPI(){
// share button code
}

if(���share���in navigator ){
swapForShareAPI();
}else{
prepForPopup();
}

})(this,this.document,this.navigator);

With this setup in place, I can provide the optimal experience in browsers that support the web share API and a pretty decent fallback experience to browsers that don���t. And if none of these enhancements can be applied, users can still share my content to the places I���ve identified��� no cookies or third-party widgets required.

You can see (and play with) an isolated demo of this interface over on Codepen.

Footnotes

Interesting side-note: If you own a form like this on your site, it makes a great share target. ������

Why a reverse while loop? Well, the order of execution doesn���t matter and decrementing while loops are faster in some instances. It���s a micro-optimization that boosts perf on older browsers and lower-end chipsets. ������

Like many modern APIs, it also requires a secure connection (HTTPS). ������

 •  0 comments  •  flag
Share on Twitter
Published on December 15, 2023 10:28

October 9, 2023

Widgets!

It was a long time coming, but I finally had a chance to put the work I did on a widgets proposal for PWAs into practice on my own site. I���m pretty excited about it!

# Where it all started

I had the original idea for ���projections��� way back in 2019. Inspired by OS X���s Dashboard Widgets and Adobe AIR, I���d begun to wonder if it might be possible to project a component from a website into those kinds of surfaces. Rather than building a bespoke widget that connected to an API, I thought it made sense to leverage an installed PWA to manage those ���projections.��� I shared the idea at TPAC that year and got some interest from a broad range of folks, but didn���t have much time to work on the details until a few years later.

In the intervening time, I kept working through the concept in my head. I mean in an ideal world, the widget would just be a responsive web page, right? But if that were the case, what happens when every widget loads the entirety of React to render their stock ticker? That seemed like a performance nightmare.

In my gut, I felt like the right way to build things would be to have a standard library of widget templates and to enable devs to flow data into them via a Service Worker. Alex Russell suggested I model the APIs on how Notifications are handled (since they serve a similar function) and I was off to the races.

I drafted a substantial proposal for my vision of how PWA widgets should work. Key aspects included:

A declarative way to define and configure a widget from within the Web App Manifest;A progressively enhanced pathway for devs to design a widget that adapts to its host environment, from using predefined templates to using custom templates to full-blown web-based widgets (with rendering akin to an iframe);A collection of recommended stock templates that implementors should offer to support most widget types;Extensibility to support custom templates using any of a variety of templating languages; andA complete suite of tools for managing widgets and any associated business logic within a Service Worker.# Widgets became a reality

After continuing to gently push on this idea with colleagues across Microsoft (and beyond), I discovered that the Windows 11 team was looking to open up the new Widget Dashboard to third-party applications. I saw this as an opportunity to turn my idea into a reality. After working my way into the conversation, I made a solid case for why PWAs needed to be a part of that story and��� it worked! (It no doubt helped that companies including Meta, Twitter, and Hulu were all invested in PWA as a means of delivering apps for Windows.)

While the timeline for implementation didn���t allow us to tackle the entirety of my proposal, we did carve out the pieces that made for a compelling MVP. This allowed us to show what���s possible, see how folks use it, and plan for future investment in the space.

Sadly, it meant tabling two features I really loved:

Stock/predefined templates. A library of lightly theme-able, consistent, cross-platform templates based on common data structures (e.g., RSS/Atom, iCal) would make it incredibly simple for devs to build a widget. If implemented well, devs might not even need to write a single line of business logic in their Service Worker as the browser could pick up all of the configuration details from the Manifest.Configurable widget instances. Instead of singleton widgets, these would allow you to define a single widget type and replicate it for different use cases. For example, a widget to follow a social media user���s profile could be defined once and the individual instances could be configured with the specific account to be followed.

I���m sincerely hopeful these two features eventually make their way to us as I think they truly unlock the power of the widget platform. Perhaps, with enough uptake on the current implementation, we can revisit these in the not-too-distant future.

To test things out, I decided to build two widgets for this site:

Latest postsLatest links

Both are largely the same in terms of their setup: They display a list of linked titles from this site.

# Designing my widget templates

Given that they were going to be largely identical, I made a single ���feed��� template for use in both widgets. The templating tech I used is called Adaptive Cards, which is what Windows 11 uses for rendering.

Adaptive Card templates are relatively straightforward JSON:

{
���type���:���AdaptiveCard���,
���$schema���:���http://adaptivecards.io/schemas/adaptive-card.json���,
���version���:���1.6���,
���body���:[
{
���$data���:���${take(items,5)}���,
���type���:���Container���,
���items���:[
{
���type���:���TextBlock���,
���text���:���${title}���,
���wrap���:true,
���weight���:���Bolder���,
���spacing���:���Padding���,
���height���:���stretch���
}
],
���height���:���stretch���
}
],
���backgroundImage���:{
���url���:���https://www.aaron-gustafson.com/i/background-logo.png���,
���verticalAlignment���:���Bottom���,
���horizontalAlignment���:���Center���
}
}

What this structure does is:

Create a container into which I will place the content;Extract the first five items from the data being fed into the template (more on that in a moment);Loop through each item andcreate a text block,populate its content with Markdown to generate a linked title (using the title and url keys from the item object)Set some basic styles to make the text bold, separate the titles a little and make them grow to fill the container; then, finallySet a background on the widget.

The way Adaptive Cards work is that they flow JSON data into a template and render that. The variable names in the template map directly to the incoming data structure, so are totally up to you to define. As these particular widgets are feed-driven and this site already supports JSONFeed, I set up the widgets to flow the appropriate feed into each and used the keys that were already there. For reference, here���s a sample JSONFeed item:

{
���id���:���������,
���title���:���������,
���summary���:���������,
���content_html���:���������,
���url���:���������,
���tags���:[],
���date_published���:���������
}

If you want to tinker with Adaptive Cards and make your own, you can do so with their Designer tool.

# Defining the widgets in the Manifest

With a basic template created, the next step was to set up the two widgets in my Manifest. As they both function largely the same, I���ll just focus on the definition for one of them.

First off, defining widgets in the Manifest is done via the widgets member, which is an array (much like icons and shortcuts). Each widget is represented as an object in that array. Here is the definition for the ���latest posts��� widget:

{
���name���:���Latest Posts���,
���short_name���:���Posts���,
���tag���:���feed-posts���,
���description���:���The latest posts from Aaron Gustafson���s blog���,
���template���:���feed���,
���ms_ac_template���:���/w/feed.ac.json���,
���data���:���/feeds/latest-posts.json���,
���type���:���application/json���,
���auth���:false,
���update���:21600,
���icons���:[
{
���src���:���/i/icons/webicon-rss.png���,
���type���:���image/png���,
���sizes���:���120x120���
}
],
���screenshots���:[
{
���src���:���/i/screenshots/widget-posts.png���,
���sizes���:���387x387���,
���label���:���The latest posts widget���
}
]
}

Breaking this down:

name and short_name act much like these keys in the root of the Manifest as well as in shortcuts: The name value is used as the name for the widget unless there���s not enough room, in which case short_name is used.You can think of tag as analogous to class in HTML sense. It���s a way of labeling a widget so you can easily reference it later. Each widget instance will have a unique id created by the widget service, but that instance (or all instances, if the widget supports multiple instances) can be accessed via the tag. But more on that later.The description key is used for marketing the widget within a host OS or digital storefront. It should accurately (and briefly) describe what the widget does.The template key is not currently used in the Windows 11 implementation but refers to the expected standard library widget template provided by the system. As a template library is not currently available, the ms_ac_template value is used to provide a URL to get the custom Adaptive Card (hence ���ac���) template. The ���ms_��� prefix is there because it���s expected that this would be a Microsoft-proprietary property. It follows the guidance for extending the Manifest.The data and type keys define the path to the data that should be fed into the template for rendering by the widget host and the MIME of the data format it���s in. The Windows 11 implementation currently only accepts JSON data, but the design of widgets is set up to allow for this to eventually extend to other standardized formats like RSS, iCal, vCard, and such.update is an optional configuration member allowing you to set how often you���d like the widget to update, in seconds. Developers currently need to add the logic for implementing this into their Service Worker, but this setup allows the configuration to remain independent of the JavaScript code, making it easier to maintain.Finally, icons and screenshots allow us to define how the widget shows up in the widget host and how it is promoted for install.

When someone installs my site as a PWA, the information about the available widgets gets ingested by the browser. The browser then determines, based on the provided values and its knowledge of the available widget service(s) on the device, which widgets should be offered. On Windows 11, this information is routed into the AppXManifest that governs how apps are represented in Windows. The Windows 11 widget service can then read in the details about the available widgets and offer them for users to install.

An animated capture of Windows 11���s widget promotion surface, showing 2 widgets available from this site���s PWA.# Adding widget support to my Service Worker

As I mentioned earlier, all of the plumbing for widgets is done within a Service Worker and is modeled on the Notifications API. I���m not going to exhaustively detail how it all works, but I���ll give you enough detail to get you started.

First off, widgets are exposed via the self.widgets interface. Most importantly, this interface lets you access and update any instances of a widget connected to your PWA.

# Installing a widget

When a user chooses to install a widget, that emits a ���widgetinstall��� event in your Service Worker. You use that to kickoff the widget lifecycle by gathering the template and data needed to instantiate the widget:

self.addEventListener(���widgetinstall���,event=>{
console.log(Installing ${event.widget.tag});
event.waitUntil(
initializeWidget( event.widget )
);
});

The event argument comes in with details of the specific widget being instantiated (as event.widget). In the code above, you can see I���ve logged the widget���s tag value to the console. I pass the widget information over to my initializeWidget() function and it updates the widget with the latest data and, if necessary, sets up a Periodic Background Sync:

asyncfunctioninitializeWidget(widget){
awaitupdateWidget( widget );
awaitregisterPeriodicSync( widget );
return;
}

The code for my updateWidget() function is as follows:

asyncfunctionupdateWidget(widget){
const template =await(
awaitfetch(
widget.definition.msAcTemplate
)
).text();
const data =await(
awaitfetch(
widget.definition.data
)
).text();

try{
await self.widgets.updateByTag(
widget.definition.tag,
{ template, data }
);
}
catch(e){
console.log(
Couldn���t update the widget ${tag},
e
);
}
return;
}

This function does the following:

Get the template for this widgetGet the data to flow into the templateUse the self.widgets.updateByTag() method to push the template and data to the widget service to update any widget instances connected to the widget���s tag.

As I mentioned, I also have code in place to take advantage of Periodic Background Sync if/when it���s available and the browser allows my site to do it:

asyncfunctionregisterPeriodicSync(widget)
{
let tag = widget.definition.tag;
if(���update���in widget.definition ){
registration.periodicSync.getTags()
.then(tags=>{
// only one registration per tag
if(! tags.includes( tag )){
periodicSync.register( tag,{
minInterval: widget.definition.update
});
}
});
}
return;
}

This function also receives the widget details and:

Looks to see if the widget definition (from the Manifest) includes an update member. If it has one, it���Checks to see if there���s already a Periodic Background Sync that is registered for this tag. If none exists, it���Registers a new Periodic Background Sync using the tag value and a minimum interval equal to the update requested.

The update member, as you may recall, is the frequency (in seconds) you���d ideally like the widget to be updated. In reality, you���re at the mercy of the browser as to when (or even if) your sync will run, but that���s totally cool as there are other ways to update widgets as well.1

# Uninstalling a widget

When a user uninstalls a widget, your Service Worker will receive a ���widgetuninstall��� event. Much like the ���widgetinstall��� event, the argument contains details about that widget which you can use to clean up after yourself:

self.addEventListener(���widgetuninstall���,event=>{
console.log(Uninstalling ${event.widget.tag});
event.waitUntil(
uninstallWidget( event.widget )
);
});

Your application may have different cleanup needs, but this is a great time to clean up any unneeded Periodic Sync registrations. Just be sure to check the length of the widget���s instances array (widget.instances) to make sure you���re dealing with the last instance of a given widget before you unregister the sync:

asyncfunctionuninstallWidget(widget){
if( widget.instances.length ===1
&&���update���in widget.definition ){
await self.registration.periodicSync
.unregister( widget.definition.tag );
}
return;
}# Refreshing your widgets

Widget platforms may periodically freeze your widget(s) to save resources. For example, they may do this when widgets are not visible. To keep your widgets up to date, they will periodically issue a ���widgetresume��� event. If you���ve modeled your approach on the one I���ve outlined above, you can route this event right through to your updateWidget() function:

self.addEventListener(���widgetresume���,event=>{
console.log(Resuming ${event.widget.tag});
event.waitUntil(
updateWidget( event.widget )
);
});# Actions

While I don���t want to get too into the weeds here, I do want to mention that widgets can have predefined user actions as well. These actions result in ���widget click��� events being sent back to the Service Worker so you can respond to them:

self.addEventListener(���widgetclick���,event=>{
const widget = event.widget;
const action = event.action;
switch( action ){
// Custom Actions
case���refresh���:
event.waitUntil(
updateWidget( widget )
);
break;
}
});

For a great example of how a widget can integrate actions, you should check out the demo PWAmp project. Their Service Worker widget code is worth a read.

# Result!

With all of these pieces in place, I was excited to see my site showing up in the Widget Dashboard in Windows 11.

A screenshot of Windows 11 showing the Widget Dashboard overlaying the desktop with this site installed as a PWA to the right. The ���latest posts��� and ���latest links��� widgets are shown.

You can view the full source code on GitHub:

���Feed��� Adaptive Card TemplateWidget definitions in the ManifestWidgets code in my Service Worker

I���m quite hopeful this will be the first of many places PWA-driven widgets will appear. If you���s like to see them supported elsewhere, be sure to tell your browser and OS vendor(s) of choice. The more they hear from their user base that this feature is needed, the more likely we are to see it get implemented in more places.

# Addendum: Gotchas

In wiring this all up, I ran into a few current bugs I wanted to flag so you can avoid them:

The icons member won���t accept SVG images. This should eventually be fixed, but it was keeping my widgets from appearing as installable.The screenshots members can���t be incredibly large. I���m told you should provide square screenshots no larger than 500px ��500px.

Have you checked out Server Events? ������

 •  0 comments  •  flag
Share on Twitter
Published on October 09, 2023 15:38

September 8, 2023

Remembering Molly

We lost a seminal figure in the world of web design this week. And I lost a good friend and mentor. Molly Holzschlag cared deeply for the web and those of us who till its soils.

This is a tough post to write, to be honest. It���s difficult to articulate just how influential Molly has been on my own work, my philosophical approach to web design, and my career.

# Molly was warm and welcoming

Molly and Patrick Haney saying cheers with their mini smoothies at the W3C���s 2007 TPAC conference in Cambridge, MA. She���d invited me, Patrick, Steph Troeth, and Matt Oliphant to give the W3C an outsider���s perspective of their organization.

Molly was there when I gave my first talk. 2003. COMDEX. I���d been invited out by the World Organization of Webmasters to give a talk on XHTML. The talk was solid. My delivery was atrocious. Molly was quick to come up after and congratulate me. I was floored.

I told her how excited I was to see her and Eric Meyer give a talk on CSS later in the day. She told me Eric had had to cancel his trip last minute and asked me if I would be interested in giving the talk with her. Just like that. I don���t know that she had any idea who I was (I���d only just published my first piece in A List Apart a few months earlier). But that was how Molly rolled. She saw my passion for web standards and somehow knew I���d be able to step up.

That one welcoming gesture was huge for me. And it was the start of a long collaboration and friendship. After that talk, we met up in Vegas again in 2004 and then went on a speaking tour the U.S. together in 2005, running web standards workshops where we taught people the fundamentals of HTML, CSS, JavaScript, and accessibility. I learned so much from her during that time and bore witness, over and over, to her immense capacity for welcoming people, bringing them together, breaking bread, building her tribe��� she was the very embodiment of the word hospitable.

And gregarious. Her boisterous laugh was infectious and memorable. I can still hear it echoing in my ears.

# Molly was generous with her time

Me and Molly presenting at TechEd in 2005. We���re at the front of a darkened conference room and someone in front of us is looking at the World Organization of Webmasters��� website on a CRT monitor.

This was Molly and I presenting at TechEd Pasadena, CA in 2005. One of many stops we made on our tour that year.

I don���t know that I���ve ever met someone who gave as much of herself as Molly did. She always, always put others first, sometimes to her own detriment.

When I first met Molly, she was leading the Web Standards Project (WaSP). She poured her heart and soul into that organization and the cause of web standards. I lost count of how many events she spoke at, often on her own dime. She invited educators into her home to teach them how to properly teach the next generation of web designers and developers��� for free.

She always put her advocacy for the cause first��� a double edged sword we���ve since named advocacy fatigue. It took a toll on her���mentally, physically, and spiritually���and she took the occasional break from it, but she never gave up on the fight for a more egalitarian web.

# Molly created opportunities for others

In this photo Molly is lying on her stomach on a hotel bed with two laptops open. She���s working on our slide deck.

While on tour, Molly and I spent nearly every waking moment together, working on our slides, hatching plans, and generally having a ball. She was the big sister I���d never had.

Another aspect of Molly���s giving nature was her insistence on opening doors for people, career-wise. I witnessed her pass along amazing opportunities that found their way into her inbox with an incredible amount of joy. Like doling out incredible gifts for a holiday.

One such gift she handed me was the opportunity to do some work with Adaptive Path. Through her introduction, I got the chance to work with an amazing team on several projects��� all from my living room thousands of miles from their San Francisco offices. That was the kind of sway she pulled.

That work led to a part-time role (and health insurance) at Bolt|Peters, where I worked on Ethnio. That role gave me the freedom to quit my day job at an ad agency and begin building my own consulting business, which I launched a few months later and ran for over a decade.

All because of the doors Molly opened.

In a separate path, she invited me to join WaSP, where I worked on a lot of JavaScript-focused efforts. That led to me working with Microsoft on improvements to IE7 and IE8 and���years later���to me eventually joining Microsoft as a web standards advocate.

All because of the doors Molly opened.

And I was not alone. Wherever and whenever Molly saw an opportunity to help someone on their career journey, she would help them. Book contracts. Speaking engagements. Networking. Freelance work. If Molly saw any way she could help you, she did. No ego. No expectations. Selfless.

Her example is what inspired me to build my mentoring program. I don���t know that I can ever do as much good as she did for people, but she made me want to try.

# Molly wanted the web to win

In this photo Molly is teaching people about the CSS box model. The screen behind her shows a dissection of the different parts that affect an element���s dimensions and layout.

So much of my presentation style and skills were learned from watching Molly work her magic.

If you know Molly���s name, this is probably why. She was a staunch���and loud���advocate for web standards and accessibility. A veteran of the browser wars (and subsequent skirmishes), she knew the landscape and she knew how imperative it was for standards to emerge and for browsers to implement them consistently.

I wasn���t there for the meeting, but she told me Bill Gates tried to tell her the web was ���done��� ���round about the IE6 days and she yelled at him. While she wasn���t one to shy away from the occasional embellishment, she was just as unlikely to shy away from a confrontation over the viability and future of the web��� so it would not surprise me at all to hear that she���d yelled at him.

Molly was a lioness���nurturing and maternal to the web and its denizens and a fierce protector when they were threatened. She saw the potential of the web as a great equalizer and bristled when folks would try to wall it off or exclude people���especially disempowered people���from accessing it.

That passionate support for the open web never wavered, even when Molly became ill. In fact we���d been talking about whether it might make sense to re-launch WaSP this year, a decade after we���d shuttered it because we thought the work was done���it wasn���t.

# Molly will live on in our memories and our craft

In this photo Molly is presenting on some topic or another. She is isolated against a white wall with a strong shadow behind her from the spotlights.

Knowing Molly affected me. Deeply. Her kindness, thoughtfulness, generosity, and passion live on in everyone her life and work touched. Including me.

I don���t know what to make of a world without Molly, but I hate that we���re living in one. She truly was a force of nature and, as such, has left an indelible mark on this industry.

I���m so thankful to have known her. To have received her mentorship. To have called her a friend.

Goodnight Mols. I love you.

Looks like you can���t play this audio file. Try downloading it.

Molly was also a talented songwriter, singer, and musician. This is a recording of ���Love���s Immortal Fountain,��� which she also wrote.
 •  0 comments  •  flag
Share on Twitter
Published on September 08, 2023 11:14

August 21, 2023

Please size your inline SVGs

While it is a bit of an edge case, every now and then I���ll hit a site���yes, even a high profile one���and the CSS will fail to load for some reason. When this happens, inevitably every inline SVG resource on the page will grow to fill the entire width of my viewport, making for a really awkward experience.

# What���s the issue?

Not to pick on anyone in particular, but consider this example from a recent talk I gave:

The U.S. Transportation Safety Administration���s TSA PreCheck�� landing page, with CSS applied.

When CSS fails to load, however, check out what happens:

The U.S. Transportation Safety Administration���s TSA PreCheck�� landing page, without CSS applied. Note the huge SVG.

Yeah, that���s an inline SVG. You see, without any explicit dimensions set, the SVG will naturally grow to become as large as possible. Chances are you���re constraining that growth in CSS somewhere, but when your CSS fails to apply for any reason, every inline SVG on your site will swell like Violet Beauregarde after eating Willy Wonka���s ���three-course dinner��� chewing gum.

# How do we solve this?

Thankfully, this is a pretty easy situation to avoid: just set an explicit width and height. To use an example from this site, instead of saying

<svgviewBox=���0 0 38 48���
version=���1.1���
xmlns=���http://www.w3.org/2000/svg���>

You can explicitly set the width and height in the svg element like this:

<svgwidth=���38���height=���48���
viewBox=���0 0 38 48���
version=���1.1���
xmlns=���http://www.w3.org/2000/svg���>

What you set these values to will likely vary depending on how the icon is being used. In a pinch, you could also pull the values directly from the viewbox value. And using that value, you could even make the inline values dynamic within your template, reading in the viewbox values and tweaking them to a ratio specific to the context.

Setting the SVG���s dimensions inline like this doesn���t restrict their flexibility either. You can still use CSS to override these inline values and set the SVG to whatever size you wish:

svg{
inline-size: 200px;
block-size: 200px;
}

I���ve thrown together a quick comparison over on CodePen so you can see the three different states:

See the Pen

And now that you know, please, please, please take a few minutes to make this small, simple change to your websites. While not a catastrophic issue, taking care to control how your sites render in the worst of circumstances goes a long way to demonstrating thoughtful consideration of your users.

 •  0 comments  •  flag
Share on Twitter
Published on August 21, 2023 14:11

July 18, 2023

Design for Developers

One of my favorite web designers, Stephanie Stimac, asked me to write the foreword for her amazing new book, Design for Developers. With her permission, and Manning���s, I���m reprinting it here.


I���ve worked on the web for a long time. When I say a long time, I mean a long time. As in my first browser was on the command line old. As in my first back-end development was a CGI script old. With my nearly three decades of building dozens upon dozens of projects for the web, the one skill I���ve found most valuable is the ability to bridge the gaps between the worlds of design, user experience, and development.


Each of these fields attract practitioners from different education and/or hobbyist backgrounds. This can be a point of tension, as folks in each camp tend to see their own field as having the greatest influence on a web project���s success. The reality is that web exists in the nexus of these fields, relying equally on what each of these practices bring to the table. I have found that the most valuable people in any web project are those that understand enough of each field to be able to operate in that nexus, ensuring each team is communicating effectively with the other teams and that everyone is working together toward a shared goal.


Which brings me to Stephanie Stimac���s Design for Developers. This book is an invaluable resource for developers looking to level up in their understanding of what it takes to build for the web today. It provides a crash course in design and user experience in a way that will both improve your fluency with these topics and give you the necessary skills to become productive in these spaces as well. Beyond that superficial perspective, however, this book provides the foundation for leveling up your career and becoming the person who thrives in the space between design, user experience, and development.


Stephanie is the perfect person to provide you with these insights as well. Not only is she an excellent communicator, she also has years of working experience as a designer, developer, user experience practitioner, and an educator. She���s even worked behind the scenes on web browsers and the web standards they implement, giving her an incredible depth of understanding when it comes to the web and the tools we rely on to build it.


Whether you���re a longtime developer looking to grow a new branch on your skill tree or you���re starting out and looking to get a solid foundation in what it takes to build for the web, Design for Developers is sure to provide you with a wealth of knowledge to help you on your way.


 •  0 comments  •  flag
Share on Twitter
Published on July 18, 2023 09:19

June 9, 2023

Opportunities for AI in Accessibility

In reading through Joe Dolson���s recent piece on the intersection of AI and accessibility, I absolutely appreciated the skepticism he has for AI in general as well as the ways in which many have been using it. In fact, I am very skeptical of AI myself, despite my role at Microsoft being that of an Accessibility Innovation Strategist helping run the AI for Accessibility grant program. As with any tool, AI can be used in very constructive, inclusive, and accessible ways and it can used in destructive, exclusive, and harmful ones. And there are a ton of uses somewhere in the mediocre middle as well.

I���d like you to consider this a ���yes��� and��� piece to compliment Joe���s post. I don���t seek to refute any of what he���s saying, but rather provide some visibility to projects and opportunities where AI can make a meaningful difference for people with disabilities (PwD) across the globe. To be clear, I am not saying there aren���t real risks and pressing issues with AI that need to be addressed���there are, and we needed to address them like yesterday���but I want to take a little time to talk about what���s possible, in hopes we���ll get there one day.

# Alternative text

Joe���s piece spends a lot of time talking about computer vision models generating alternative text. He highlights a ton of valid issues with the current state of things. And while computer vision models continue to improve in terms of the quality and richness of detail in their descriptions, the results are not great. As he rightly points out, the current state of image analysis is pretty poor���especially for certain image types���and the current systems examine images in isolation rather than within the context in which they sit (a consequence of having separate foundation models for text analysis and image analysis).

These models are also not currently trained to distinguish an image that is contextually relevant (for which there should probably be a description) from one that is purely decorative. Of course this is something we humans struggle with as well��� the right answer is often somewhere between the author���s intent and the user���s needs/preferences.

All of that said, there is potential in this space.

As Joe mentions, human-in-the-loop authoring of alt text should absolutely be a thing. And if AI can pop in to offer a starting point���even if that starting point is prompting you to say What is this B.S.? That���s not right at all��� let me fix it���I think that���s a win.

Taking things a step further, if we can specifically train a model to analyze image usage in context, it could help us more quickly identify which ones are likely to be presentational and which ones likely require a description. That will help reinforce the importance of descriptions in the appropriate context and improve the efficiency with which authors can make their pages more accessible.

While complex images���graphs, charts, etc.���are challenging to describe in any sort of succinct way (even for humans), the image example shared in the GPT4 announcement points to an interesting opportunity here as well. Let���s say the description of a chart was simply the title of the chart and the kind of visualization it was. For example: Pie chart comparing smartphone usage to feature phone usage among U.S. households making under $30,000 a year. If the browser knows it���s a pie chart (because an onboard model verified this), imagine a world where a user could ask questions about the graphic.

Do more people use smartphones or feature phones?How many more?Is there a group of people that don���t fall into either of these buckets?How many is that?

Setting aside the realities of Large Language Model (LLM) hallucinations for a moment, the opportunity to interface with image data in this way could be revolutionary for blind and low-vision folks as well as people with various forms of color blindness, cognitive disabilities, and so on. It could also be useful in an educational context to teach people who can see the chart, as authored, to read a pie chart.

Taking things a step further, what if you could ask your browser to simplify a complex chart, perhaps isolating a single line on a line graph? What if you could ask the browser to transpose the colors of the different lines to work better for the specific form of color blindness you have? What if you could swap colors for patterns? Given the chat-based interface and our ability to manipulate existing images in currently available AI tools, that certainly seems like a possible future.

Now imagine a purpose-built model that could extract the information from that chart and convert it to another format. For example, it could turn that pie chart (or better yet, a series of them) into a more accessible (and useful) format like a spreadsheet. That would be amazing!

# Matching Algorithms

Safiya Umoja Noble absolutely hit the nail on the head with the title of her book Algorithms of Oppression. While it was focused on search engines reinforcing racism, all computer models have the potential to amplify conflict, bias, and intolerance. Whether it���s Twitter always showing you the latest tweet from a bored billionaire, YouTube sending us into a Q-hole, or Instagram warping our idea of what a natural body looks like, we know poorly authored and maintained algorithms are incredibly harmful. A lot of this stems from a lack of diversity among the people who shape and/or build them. When built inclusively, however, there is real potential for algorithm development to benefit people with disabilities.

Take Mentra, for example. They are an employment network for neurodivergent people. They employ an algorithm to match job seekers with potential employers, based on over 75 different data points. On the job seeker side of things, it takes into account the candidate���s strengths, necessary workplace accommodations (and preferred ones), environmental sensitivities, and so on. On the employer side, it takes into account the work environment, communication factors related to the job, and the like. As a company run by neurodivergent folks, Mentra made the decision to flip the script when it comes to typical employment sites. They use their algorithm to propose available candidates to the companies, who can then connect with job seekers they are interested in; reducing the emotional and physical labor on the job seeker side of things.

When more people with disabilities are involved in the creation of algorithms, there is a lessened likelihood that these algorithms will be used to inflict harm on their communities. This is why diverse teams are so important.

Imagine if a social media company���s recommendation engine was tuned to analyze who you���re currently following and prioritized recommending that you follow people who talked about similar things, but who were different in some key way from your existing sphere of influence. For example, if you follow a bunch of non-disabled white male academics who talk about AI, it could suggest you follow academics who are disabled or aren���t white or aren���t male who also talk about AI. If you took its recommendations, you���d likely get a much more holistic and nuanced understanding of what is happening in the AI field.

# Other Ways AI Helps PwD

If I weren���t trying to put this together between other tasks, I���m sure I could go on, ad infinitum, providing all kinds of examples of how AI can be used to the benefit of people with disabilities, but I���m going to make this last section into a bit of a lightning round. In no particular order:

Voice preservation. You may have seen the VALL-E paper or Apple���s GAAD announcement or you may be familiar with offerings from Microsoft, Acapela, and others. It is possible to train an AI model to replicate your voice, which is tremendous for people who have ALS/MDN and other medical conditions that lead to dysarthria. This is, of course, the same tech that can be used to create audio deepfakes, so it���s something we need to approach responsibly , but the tech has truly transformative potential.Voice recognition. Researchers like those in the Speech Accessibility Project are paying people with disabilities for their assistance in collecting recordings of people with atypical speech. As I type, they are actively recruiting people with Parkinson���s and related conditions and they have plans to expand this to other etiologies as the project progresses. This research will result in more inclusive data sets that will enable more people with disabilities to use voice assistants, dictation software, and voice response services as well as control their computers and other devices more easily, using only their voice.Text transformation. The current generation of LLMs is quite capable of making adjustments to existing text content without injecting hallucinations. This is hugely empowering for people with cognitive disabilities who may benefit from a text summary or the text being simplified or even from it being prepped for bionic reading.# The Importance of Diverse Teams and Data

Of course to do things like this, we need to recognize that differences do matter. Our lived experiences are influenced by the intersections of identity in which we exist. Those lived experiences���with all of their complexity (and joy and pain)���are valuable inputs to the software, services, and societies we shape. They need to be represented in the data we use to train new models and the folks who contribute that valuable information need to be compensated for sharing it with us. Inclusive data sets yield more robust models that enable more equitable outcomes.

Want a model that doesn���t demean or patronize or objectify people with disabilities? Make sure content about disability, authored by people with a range of disabilities is well-represented in the training data.

Want a model that doesn���t use ableist language? Use existing data sets to build a filter that can intercept and remediate ableist language before it reaches an end user.

Want a coding co-pilot that gives you accessible recommendations from the jump? Train it on code that is known to be accessible.

I have no doubt that AI can and will harm people��� today, tomorrow, and well into the future. However, I also believe that we can acknowledge that and, with an eye towards accessibility (and, more broadly, inclusion), make thoughtful, considerate, intentional changes in our approaches to AI that will reduce harm over time as well. Today, tomorrow, and well into the future.

 •  0 comments  •  flag
Share on Twitter
Published on June 09, 2023 14:57

April 21, 2023

Considering content warnings in HTML

One of the features I really love about Mastodon is their first-class Content Warning feature. With one additional step, you can add any warning of your choice to your post and it will be hidden by default, showing only the content warning text. It���s a super-simple idea, but so powerful when it comes to reducing potential the likelihood of causing our readers to experience the kinds of trauma that could have severe consequences.

Earlier today, the idea of a ���spoiler / content warning��� element popped onto my radar through the Web We Want inbox. It referenced a discussion over on the WICG and I was intrigued but the potential of this kind of feature for HTML. Some folks suggested progressive disclosures like details/summary was the way to go, but that approach is limited to flow content (and fraught with a host of issues).

# Markup possibilities

I wasn���t sold on the idea of a spoiler element either, as that���s a pretty specific use case of a content warning. And so I wondered, what if instead of an element, we introduced an attribute that could take the kind of content warning as its value. For example, consider the following:

<articlecontent-warning=���child abuse���>
��� article contents ���
article>

This would identify the entire article as discussing child abuse. Obscuring that behind a warning would probably be a good idea.

Or perhaps the content warning should apply to an image:

<imgcontent-warning=���violence gore������>

Or, to return to the original idea of a spoiler, it could also be applied inline:

I thoroughly enjoyed the film, especially
when it was revealed that
<bcontent-warning=���spoiler���>Taye Diggs
had been the bad guy all alongb>.# Necessary behaviors

When considering how content behind a warning should be handled, there are a few things that jump immediately to mind:

Indicated content should be obscured by default.Users must choose to reveal the content.Content should not be included in the ���find in page��� index.Images should not be downloaded until they are requested (or there is a good chance they will be needed).

There���s also an interesting opportunity for browsers to offer user preferences around this approach as well. For example, I may never want to be shown content that deals with rape, so I could configure that in my preferences and the browser could take additional steps to hide that content from me or at least make sure I actually want to reveal it by requiring a second step for final approval (i.e., Are you actually sure you want to see this?).

# Demo

I threw together a quick & dirty demo of what the experience could be like on Codepen if you���d like to take a look:

See the Pen

It���s still a work-in-progress, but it���s a starting point. Ideally the browser would handle all of this directly, rather than us having to author CSS and/or JavaScript to implement the feature ourselves. (Though maybe we could get access to style parts of the overlay.)

# Thoughts?

What do you think? Is this something you���d like to see on the web? I���d love to hear your thoughts, which you can share by Webmention-ing this post or referencing it on Mastodon.

 •  0 comments  •  flag
Share on Twitter
Published on April 21, 2023 15:15

March 16, 2023

Accessibility Beyond Code Compliance

I had the great pleasure of delivering a talk about career opportunities for accessibility devs at axe-con earlier today. You can view the slides or watch the recording of this talk, but what follows is an approximation my talk���s content, taken from my notes and slides.

Good morning, good afternoon, and good evening to you, wherever you are in the world. My name is Aaron Gustafson. My pronouns he, him, and his. I am a middle-aged white man with long, wavy hair, glasses, and a red and grey beard my wife refers to as ���salt & paprika.��� I am speaking to you from Seattle, WA on the unceded lands of the Coast Salish peoples, most notably the Duwamish, whose longhouse is not too far from my home.

Some of you may be familiar with my work. I���ve been a web designer and developer since the mid ���90s. In that time I���ve authored dozens of articles and a few books and given over a hundred talks on web development. In fact, if my math is correct, I believe this is my 150th talk.

Over the years I���ve been best known for my work in progressive enhancement and accessibility, but I also led the Web Standards Project back in the day and am the Editor in Chief of A List Apart.

I have deep roots in the web dev community, particularly in the accessibility space, but that���s not why I���m here today. I���m here today because about 9 months ago I decided to change things up and use my accessibility skills in other ways.

In my case, I joined the Microsoft Accessibility Innovation team to lead our investments through the AI for Accessibility grant program.But I���m not here to talk about AI, I���m here to talk about how you can put your accessibility skills to work, beyond finding and remediating accessibility bugs.

# Cruel irony: accessibility devs face barriers too

In my career, I���ve found it���s really easy to get typecast or pigeon-holed when you���re a developer whose focus is accessibility. This is a bit of a cruel irony as many of us are driven by a desire to tear down the barriers to access for others.

Our companies, organizations, and sometimes even our colleagues put us in a box. They don���t seem to realize that knowledge of how to make products accessible has huge value beyond compliance (and avoiding lawsuits). In our careers, we might be able to level up from a junior to senior role or even make it to principal, based on our performance, but growth beyond that is often limited to moving into people management, which is a wholly different skill set. And maybe that���s your aspiration��� that���s totally cool if it is, but what if you want to grow as an independent contributor?

When our organizations put us in a box, they make it really difficult to grow our scope and increase the impact we can have for both the organization and the people we serve.

Don���t get me wrong, I love compliance work. I���m not here to disparage it in any way; it���s critically important and means so much to our customers. But after years in this industry, I also see the downsides of life in the ���accessibility dev��� box. Perhaps you relate to a few of these:

Colleagues don���t understand (or value) what I do.I need like three (or more) of me to handle the workload.Teams are resistant to changing the way they do things.Progress feels glacially slow and some days I feel I���m going backwards.I feel isolated on the team or the company

Again, I am not trying to cast code compliance work in a bad light, and I���m not trying to get you down on it. What I want to do is build you up.

# You���ve got so much more to offer

I believe you, as a developer interested in accessibility, have so much to offer your organizations, your customers, and this industry. That���s what I am here to talk to you about today.

I���m here to talk to you about opportunity!

When I was doing this work on the regular, I struggled to see how I could grow my impact. In the intervening years, however, I���ve discovered a bunch of ways we can bring our knowledge and passion for accessibility to other areas of both web development and the tech industry overall.

As I mentioned, I���ve been in this industry and held a lot of different roles since the mid ���90s. I���ve held just about every web-related role you could name. I���ve been an educator, publisher, spec editor at the W3C. I���ve worked in Developer Relations and strategic roles. I���ve worn an awful lot of hats (which is totally fine with me as my hair is thinning in the back).

All of this is to say that I���ve seen and experienced a lot of ways you can be valuable to your current employer or, perhaps, a future one.I am going to share 5 of them with you today:

Design SystemsProduct DesignData ScienceAI Research & EthicsDiversity & Inclusion

These are by no means your only options and, as I mentioned, if you���re happy with what you���re doing, please don���t consider this talk a nudge to get you to change things up. I just want to make you aware of the value you can bring to other kinds of roles, some of which you may not have considered before.

Also: I want to make it clear that I am not advocating that you take on any of these responsibilities in addition to your current work. Far too often, organizations ask those of us with accessibility skills to do things beyond our job description without any additional compensation for that work. Please don���t fall into that trap as it will lead to burnout.

# Design Systems & Strategies: Codify coding best practices

If you���re really interested in software development, an area that keeps you in that area is working on design systems.

I���m not going to go deep on design systems���there are a bunch of talks and even whole conferences focused on that topic���but I will give you the Cliffs Notes if you���re unfamiliar: Design systems (and pattern libraries within them) codify your organization���s design and coding guidelines in such a way that the software you produce is consistent and the teams working on delivering that software are able to be more efficient because they aren���t having to design and build every interface from scratch.Having a design system that is accessible enables teams to avoid introducing new accessibility bugs in the process of creating bespoke interfaces. It also means finding and fixing an accessibility bug in the design system should fix it in all of the products using that design system. (That last part isn���t always perfect, but I don���t have time to get into that today.)

If you work in a small organization, it���s possible that you aren���t working with a design system yet. Knowing what you do about their accessibility benefits, you could advocate for the creation of one and for its creating, care & maintenance to be your job.

In this role, you can:

Work directly with other engineers to create system components.Audit the system regularly for compliance issues (paying special attention to how combinations of components can create issues).Provide in-house accessibility training to the design & engineering folks to help them level-up their own skills.Provide design system training and implementation guidance to the folks implementing the design system and new hires as they come in.Celebrate the successes of teams using the design system, particularly when it comes to their accessibility wins; you could do this in-person, in online meetings, or via email depending on the size and distribution of your team.

If you���re in a larger organization that already has a design system, you could be a bit more strategic in your approach:

Being the accessibility advocate within the design system as well as in the context of all software development practices within your organization.Be the conduit to your organization���s senior management as well as individual product owners to ensure accessibility is top of mind for them and baked into their roadmaps. Part of that is also advocating for the necessary funding to achieve your accessibility goals (and alleviating the issue we often face on not being appropriately-resourced).Provide guidance and create structure within your organization to ensure your accessibility goals are met.Educate and mentor folks from across your organization on accessibility.And again, celebrate the heck out of any and all accessibility wins, no matter how small. We���ve already discussed some of the challenges we face ad accessibility devs, and getting publicly recognized for our accomplishments can really boost morale.

As an accessibility dev, your unique perspective and skills will help build greater alignment on accessibility among teams and improve morale by speeding up development & reducing bugs!

# Product Design: Shape what you build

As I mentioned, the role in larger orgs can be more strategic. Another strategic role is shaping the products that we build, as a product designer, product owner, product manager, or similar. (Different companies have different titles for this kind of work.)

In this kind of a role, we can put the ���shift left��� credo we advocate for regularly into practice. It involves

Embedding yourself with feature teams to understand what motivates them. Understanding their vision in goals will help you frame your recommendations in a way that they will be welcomed and embraced. Being embedded with a team also means you can discover potential hazards early and eliminate them; you can educate them as to the issue and how to avoid it which makes it less likely they will run into it again.Asking questions and offering to up-skill the team, helping them learn to build products that will reach and be usable by more customers.Making sure people with disabilities are included (and paid for their contributions) in all research, co-creation, and testing so the team has a better understanding of their needs.

All of this work has huge business value for your organization:

It saves your engineering and quality assurance teams a ton of time, and time is money.You reduce the legal risk to your company for lack of compliance, which also saves money in legal fees (not to mention settlements).You will build products that work better for more people, leading to better overall customer satisfaction and reduced churn.You���ll also create new revenue opportunities by increasing the number of folks you can serve.

On that last point, I often point to WhatsApp as a perfect example of this. When they launched, there were nearly 8,000 chat apps in the iOS App Store. If they���d only offered their app to that audience, they would not have found the level of success they did because the competition was so high. They expanded their potential customer base by supporting OSes others were ignoring: older Android versions, Blackberry, Symbian, Nokia Series 40, Windows Phone. Some of those weren���t even smartphone OSes! When WhatsApp sold to Facebook for $19B, they had over 600M users worldwide because they made their product accessible���in a broader sense���to more people.

By considering accessibility in the same way as WhatsApp considered OS support, we can grow���or to think about it another way, stop artificially suppressing���our customer base and succeed where our competition fails.

As an accessibility dev, your unique perspective and skills will ensure your company ships higher quality products, with fewer bugs, for less money!

# Data Science: Measure the right things

Moving a bit further afield, I want to talk about how much we need your skills in the world of data science. As part of a data science team, you could bring attention to accessibility in our product metrics by

Ensuring key business metrics include data from people with disabilities.Adding new product metrics that reflect the experience of different disability communities.Measuring the time necessary to complete key tasks when using different AT and track improvements & regressions for them over time.

Apart from products, you could also have a profound impact on your organizations��� internal processes, especially around how compliance work is done and tracked:

Capture automated testing passes and track compliance over time.Highlight accessibility bug activityHow many new?How many remediated?How many outstanding?How many marked ���won���t fix���?Average age of outstanding bugsInclude this data in top-level product reports

And if you wanted to keep working in the UI space, you could put your skills to work improving the quality of the dashboards and tools used by your company:

Ensure all analysis tools are accessible.Ensure charts are accessible.Provide access to raw data tables.Enable API access to data to enable colleagues to create additional tooling that works better for them.

This is incredibly necessary work as we often neglect the accessibility of our own internal tools.

As an accessibility dev, your unique perspective and skills can help your company make decisions that result in more inclusive and accessible products that provide a better user experience (and may even increase revenue).

# AI Research & Ethics: Protect us from ���the machines���

The fourth area desperately in need of your skills and perspective is AI research and ethics. AI is a hot topic right now, for sure, and it absolutely has the potential to meaningfully improve people���s lives, including those of people with disabilities, but to get there, organizations need your help!

You have the knowledge and connections in this space to harness the power of AI in service of people with disabilities.

As part of an AI research team you can���

Observe how people with disabilities interact with the world today and consider how AI canincrease their independence;make certain actions easier, more intuitive, or efficient; andincrease the richness of experiences for them.Co-design with folks from a range of disability communities; but remember not to assume everyone from a given community wants the same thing.

This is the space I���m very grateful to be in right now. As part of the Accessibility Innovation team at Microsoft, I get to identify and fund projects that are using AI to improve the lives of people with disabilities.

For example: the ORBIT project. There���s been lots of work in the object detection space, but there is a lot of focus on labelling ���high-quality��� images. This doesn���t really help folks in the real world. A blind person, for instance, is likely to have a hard time providing the image recognizer a with a perfectly-framed, perfectly focused capture of an object they need identified.

The Orbit project, from the City University of London, worked to enable ���few-shot learning��� of novel objects by training the model on brief videos taken by blind & low vision collectors. These videos are ���imperfect��� in that they are likely to be poorly framed, blurry, and so on.This increases the noise-to-signal ratio, which is actually a good thing in training a machine learning model. Enabling AI systems to recognize objects captured in imprecise ways makes for a more robust recognizer that is capable of identifying objects in less than ideal contexts.That, in turn, improves the overall quality of these systems for everyone.

Another example is Mentra, who has been using AI to help pair neurodivergent folks with employers who recognize the profound contributions they can make in their companies. Mentra���s platform collects holistic data on job seekers:

cognitive strengths,aptitudes,environmental sensitivities,and necessary accommodations.

It takes these into account when matching individuals to available positions (which also include comparable information).

Mentra takes care not to ���screen out��� individuals with non-traditional backgrounds. It also works in a ���reverse job fair��� model, where applicants only fill in one profile, letting Mentra���s AI recommend them for jobs that are a good fit. Employers indicate their interest and invite job seekers to interview, lessening the stress level on the job seeker.

Mentra���s straightforward approach also reduces the need for job seekers to ���cover��� in a new role as they���ve made it clear what accommodations they need in order to be successful.

The third project I���ll share with you is iWill, who are working in the mental health space.

There are tons of cognitive behavioral therapy (CBT) chatbots out there, but we were really intrigued by work being undertaken by iWill in India. First of all, there is a profound scarcity of mental health professionals in India. Training and deploying enough professionals to meet the mental health needs of the population is not feasible in the near term, which is why chat bots are a compelling stop-gap.

Most CBT chatbots are trained in English. We are funding them to train a CBT model end-to-end in Hindi as we believe it���s the only way to avoid potential problems inherent in translation (Hindi to English for the ML then back again) and biases that would be inherent from the involvement of English.

I could spend hours talking about all of the good AI can do in the world, but I also recognize that AI can also perpetuate or exacerbate exclusion.

AI teams need your skills to help them address bias toward and exclusion of people with disabilities. They also need you to be there protecting the privacy of people with disabilities.

You would bring a lot to an AI team in this regard:

Identify bias (or potential bias) in datasets.Promote representation of people with disabilities in datasets.Ensure people with disabilities are not exploited by datasets.Ensure all interfaces to the AI tools are accessible.Ensure the products created by AI are accessible.Validate that the products of AI are not directly biased or exclusionary and they they cannot be used to perpetuate bias or exclusion.

As an accessibility dev, your unique perspective and skills can help can ensure advancements in AI/ML are beneficial (and not harmful) to people with disabilities!

# Diversity & Inclusion: Build & grow inclusive teams

The last role I���ll talk about is probably the furthest afield from development, but it also has the most profound impact on the teams that do the work and that���s D&I. I don���t imagine I need to spend a ton of time making a case to this audience for why diversity matters, but here���s a quick run-down just in case:

Diverse teams bring with them diverse perspectives & lived experiences.If valued, that knowledge can make it easier to identify potential barriers (and opportunities) earlier in a project.Diverse teams are more likely to exhibit empathy toward all users, including those with disabilities.Diverse teams are more innovative.Diverse teams make better decisions

For more on those last two points, you should read this piece in the Harvard Business Review.

As someone who is keenly aware of the importance of having diverse teams to build inclusive products, you can do a lot to ensure your organization embraces diversity in its recruiting efforts. Fixing leaks in ���the pipeline,��� if you will.

A lot of it starts with asking important questions:

Do we have a disability hiring policy?Are our recruiters ���screening in��� people with disabilities?Where are we posting jobs? Are theyreaching people with disabilities?Is the language of our job postings exclusionary?Is our interview process inclusive and accommodating of people���s disabilities?

It���s also important to actively solicit disabled talent for roles in your company.

Some of this is actually work you could do without being part of any official D&I team, if you wanted, but if it is something you want to focus on, you might consider a job in recruiting.

A lot of folks focus on the pipeline, but in my experience that���s not where the bulk of the problems lie. If we want diverse teams, we need to ensure we have an environment and culture that values and supports them. Diverse talent will flee an unwelcoming environment and employee churn is expensive.

In order to retain diverse talent, we need to make sure the teams they join recognize the value they bring to an organization. This is where D&I training and coaching comes in.

You can influence team culture to improve retention by framing diversity in the context of your business goals and organizational success:

Lack of diversity creates knowledge gaps.Diverse hiring helps to fill those gaps.Diverse colleagues��� knowledge & livedexperiences have value.

Once the framing has been established, be sure to ���call in��� non-inclusive/biased behaviors. Leading with curiosity can help you understand where someone is coming from so you can help them grapple with concepts like privilege and bias. Don���t burn yourself out trying to change the mind of folks who are openly antagonistic to this message, but you���ll often be surprised at how a non-confrontational, nonjudgmental conversation can both diffuse a tense situation and help to shift someone���s perspectives.

Another step you can take to improve retention include examining the inclusiveness (or lack thereof) of your team���s processes, built environments, and such. Are your hybrid meetings being monopolized by folks in the physical meeting space, alienating people on the call? Are your team morale events all scheduled in the evenings, making it hard for parents or caregivers on the team? Are they being held in bars, which makes it uncomfortable for folks who don���t drink alcohol, or in inaccessible venues?

Finally, it can be really beneficial to normalize disability in everyday interactions, especially if you are someone with privilege in your workplace as you can create space for others to acknowledge their own disabilities.

I was thankful that my last role enabled me to make this kind of D&I work a formal third of my core responsibilities. With my management���s backing, I was able to lead D&I trainings and events across the company while still being able to do the other work I love.

Many companies have formal D&I teams (some in HR, some not) for whom this is their whole job, so there are certainly opportunities there. That said, those teams often rely on advocacy from elsewhere in the company for their efforts to be successful, so you might also be able to formally support their efforts from outside that organization, as I did.

If there is no room for diverse talent to grow in their careers, many will leave. As I mentioned, churn is expensive. And just as not feeling respected & valued will likely result in a diverse employee leaving, the same goes for not having the same career advancement opportunities enjoyed by people from more privileged groups. Depending on where you are in your organization, you can help address this problem in different ways:

Write recommendations for colleagues, prioritizing them for colleagues whose diversity needs to be seen as an asset.Observe promotions and ask questions of management if you don���t see diverse representation.Mentor and reverse-mentor colleagues with a goal of growing the careers of people with disabilities.

This work is especially important to undertake if you are from a privileged group in your organization as your advocacy carries more weight. Treat your privilege as a currency and spend it on your colleagues.

Finally, and in perhaps the most formal way, working full-time in D&I you can shape company policies & trainings:

Suggest edits to existing company policies.Draft new policies.Suggest freely-available accessibility and D&I trainings to colleagues.Create (or co-create) workshops & trainings for your company or team.Push for your company to mandate accessibility and D&I training; be sure to include additional training specifically for people managers as they have more to consider in this regard.Advocate for diverse representation and the modeling of inclusive behavior in all in-house trainings.

As an accessibility dev, your unique perspective and skills can help increase the inclusiveness of your company for fellow employees, which will lead to the creation of more inclusive products and services!

# These are just five areas that need you

In this talk, I introduced five areas desperately in need of your skills and perspectives: Design Systems, Product Design, Data Science, AI Research & Ethics, and Diversity & Inclusion.

There are way more (I only have so much time).

If you���re feeling stuck, hopefully this gives you some idea of the kinds of opportunities that are out there for you. And if you only come away from this session with one thing, let it be this:

You are more valuable than you realize.

You are change maker.

Thank you!

 •  0 comments  •  flag
Share on Twitter
Published on March 16, 2023 10:50

March 6, 2023

A Tab Interface Before Its Time

I finally got around to reading the CSS Tricks piece on ���Spicy Sections��� and it���s cool how closely what the OpenUI folks are talking about aligns with work I was doing in the mid-to-late oughts.

Back in 2007, I built a little standalone JavaScript called TabInterface.js. I built it to generate tabbed interfaces using the natural document outline (h1-h6) to inform the UI. It only required that the author add a single wrapper to indicate the content could be converted into a tabbed interface. For example, given the following HTML:

<divid=���recipe���class=���tabbed���>
<h2>Overviewh2>
���
<h2>Ingredientsh2>
���
<h2>Directionsh2>
���
<h2>Nutritionh2>
���
div>

You would use JavaScript to update the code to turn it into a tabbed interface:

window.addEventListener(���domready���,function(){
document.querySelectorAll(���.tabbed���)
.forEach(function(item, i){
newTabInterface( item, i );
})
},false);

What I always loved about this approach was that it was the best of both worlds:

Semantic, strucutred content as the no-JS and print experience. This is great because JS isn���t a given and you really don���t want to have an interface look like tabs without behaving like them too.Tabbed content when JS was available. The ideal experience, at least on desktop screens, but more on that in a moment.

I think the first talk I gave that included this was ���Fundamental Progressive Enhancement,��� which I delivered at Web Builder 2.0 in October of 2008. I also wrote about the approach in a 2-part article for Net Magazine (Part 1, Part 2) the following year.

Of course, that was all before media queries and responsive design. By the time that rolled around, I had begun recommending that folks only convert the interface to tabs when there was room for it and to un-tab if needed (like when a device is rotated).

Over the years, my approach continued to evolve to include

Testing to see if the tabs would even fit horizontally, considering the viewport width and length of the headings (TabInterface does support alternate, shorter markup-driven headings too).Adapting to provide an accordion when horizontal space was scarce.This could use details & summary, if supported ordiv elements if not.

Anyway, it���s wild to see the idea finally beginning to get some traction in a broader sense. Clearly TabInterface was an idea before its time.

 •  0 comments  •  flag
Share on Twitter
Published on March 06, 2023 15:22

February 3, 2023

Rebuilding a PHP App using Isomorphic JavaScript with Eleventy & Netlify

Back in the early days of the iPhone, I created Tipr, a tip calculator that always produces a palindrome total.1 This is an overview of the minimal work I did to make it a modern web app that can run without a traditional back-end.

# What I had to work with

The previous iteration of Tipr was built in my hotel room while I was on site doing some consulting for a certain Silicon Valley company. I was rocking a Palm Treo 650 at the time and that day a few of my colleagues had lined up to wait for the release of the very first iPhone. At the time, web apps were the only way to get an ���app��� on the iPhone as there was no SDK or even an App Store.

Tipr on the 1st generation iPhone, in the hands of Micah Alpern, June 2007.

I did a lot of PHP development back in the day, so armed with all of the mobile web development best practices of the day, I set about building the site and making it speedy. Some of the notable features of Tipr included:

Inlining CSS & JS file contents into the HTML.Using PHP output buffers to compress the HTML on the server before sending it over the wire.Server side processing in PHP.Client side processing via XHR to a PHP-driven API.

At the time, most of these approaches were very new. As an industry, we weren���t doing a whole lot to ensure peak performance on mobile because most people���s mobile browsers were pretty crappy. This was the heyday of Usablenet���s ���mobile friendly��� bolt-on and WAP. Then came Mobile Safari.

Tipr in the original Apple App Store, back when web apps were first class citizens on iPhone OS.# A lot has changed since 2007

The Tipr site has remained largely untouched since I built it in the Summer of 2007. That October, I added a theme switcher that made the site pink for October (Breast Cancer Awareness Month). I added a free text message-based interface using the then-free TextMarks service and a Twitter bot as well. But as far as the web interface went, it remained largely untouched.

Here are a handful of things that have come to the web in the intervening years:

HTML5 Form Validation APISVG supportCSS3Media QueriesWeb App ManifestService Worker (and its precursor the AppCache)FlexboxCSS Grid

Phew, that���s a lot! While I haven���t made upgrades in all these areas, I did sprinkle in a few, mainly to make it a true PWA and boost performance.

# Moving from PHP to a ���static��� site

Much of my work over the last few years has been in the world of static site generators (e.g., Jekyll, Eleventy). I���m quite enamored of Eleventy, having used it for a number of projects at this point. Since I know it really well, it made sense to use it for this project too. The installation steps are minimal and I already had a library of configuration options, plugins, and filters to roll with.

While in the process of migrating to Eleventy, I also took the opportunity to

Swap raster graphics for SVGs,Set up a Web App Manifest,Add a Service Worker, andUpdate the site���s meta info to reflect current best practices.

I also swapped out the PHP logic that governed the pink color theme for a simple script in the head of the every page. Since the color change is an enhancement, rather than a necessity, I didn���t feel like it was something I needed to manage another way.

The greatest challenge in moving Tipr over to a static site was setting up the tip calculation engine, which had been in PHP to ensure it would work even if JavaScript wasn���t available.

# Migrating the core logic to isomorphic JavaScript

When I originally built Tipr, JavaScript on the back-end wasn���t a thing. That���s why the core tip calculation engine was built in PHP. At the time, even XHR was in its infancy, so the fact that I could use PHP to do the calculations for both the server-side���for when JavaScript wasn���t available���and client-side���when it was���was pretty amazing.

Today, JavaScript is ubiquitous across the whole stack, which made it the logical choice for building out the revised tip calculator. As with the original, I needed the calculation to work on the client side if it could���saving a round trip to the server���but to also have the ability to fall back to a traditional form submission if the client-side approach wasn���t feasible. That would be possible by having client-side JavaScript for the form itself, with the server-side piece handled by Netlify���s Edge Functions (integrated through Eleventy���s Edge plugin).

From an architectural standpoint, I really didn���t want to have my logic duplicated in each place, so I began to play around with ensconcing the calculation logic in a JavaScript include, so I could import it into the form page itself and a JavaScript module that the Edge Function could use.

You can view Tipr���s source on GitHub, but here���s a basic rundown of the relevant directories and files:

netlify
edge-functions
tipr.js
src
_includes
js
tipr.js
j
process.njk
index.html
netlify.toml#src/_includes/js/tipr.js

This file contains the central logic of the tip calculator. It���s written in vanilla JavaScript with the intent that it would be understandable by the widest possible assortment of browsers out there.

#src/index.html

The homepage of the site is also home to the tip calculation form. Below the form is an embedded script element containing the logic for interacting with the DOM for the client-side version of the tip calculator. I include the logic at the top of that script:

<script>
{%include���js/tipr.js���%}

//TherestoftheJavaScriptlogic
</script>#src/j/process.njk

This file exists solely to export the JavaScript logic from the include in a way that it can be consumed by the Edge Function. It will render a new JavaScript file called ���process.js��� and turns the central processing logic into a JavaScript module that Deno can use (Deno powers Netlify���s Edge Functions):

---
layout:false
permalink:/j/process.js
---

{%include���js/tipr.js���%}

export{process};#netlify/edge-functions/tipr.js

We define Edge Functions for use with Netlify in the netlify/edge-functions folder. To make use of the core JavaScript logic in the Edge Function, I can import it from the module created above before using it in the function itself:

import{ process }from���./���/���/_site/j/process.js���;

functionsetCookie(context, name, value){
context.cookies.set({
name,
value,
path:���/���,
httpOnly:true,
secure:true,
sameSite:���Lax���,
});
}

exportdefaultasync(request, context)=>{
let url =newURL(request.url);

// Save to cookie, redirect back to form
if(url.pathname ===���/process/���&& request.method ===���POST���)
{
if( request.headers.get(���content-type���)===���application/x-www-form-urlencoded���)
{
let body =await request.clone().formData();
let postData = Object.fromEntries(body);

let result =process( postData.check, postData.percent );

setCookie( context,���check���, result.check );
setCookie( context,���tip���, result.tip );
setCookie( context,���total���, result.total );

returnnewResponse(null,{
status:302,
headers:{
location:���/results/���,
}
});
}
}

return context.next();
};

What���s happening here is that when a request comes in to this Edge Function, the default export will be executed. Most of this code is directly lifted from Netlify���s Edge Functions demo site. I grab the form data, pass it into the process function, and then set browser cookies for each of the returned values before redirecting the request to the result page.

On that page, I use Eleventy���s Edge plugin to render the check, tip, and total amounts:

{%edge%}
{%setcheck=eleventy.edge.cookies.check%}
{%settip=eleventy.edge.cookies.tip%}
{%settotal=eleventy.edge.cookies.total%}
<trid=���check���>
<thscope=���row���>Check&nbsp;</th>
<td>${{check}}</td>
</tr>
<trid=���tip���>
<thscope=���row���>Tip&nbsp;</th>
<td>${{tip}}</td>
</tr>
<trid=���total���>
<thscope=���row���>Total&nbsp;</th>
<td>${{total}}</td>
</tr>
{%endedge%}

Side note: The cookies get reset using a separate Edge Function.

#netlify.toml

To wire up the Edge Functions, we use put a netlify.toml file in the root of the project. Configuration is pretty straightforward: you tell it the Edge Function you want to use and the path to associate it with. You can choose to associate it with a unique path or run the Edge Function on every path.

Here���s an excerpt from Tipr���s netlify.toml as it pertains to the Edge Function above:

[[edge_functions]]
function=���tipr���
path=���/process/���

This tells Netlify to route requests to /process/ through netlify/edge-functions/tipr.js. Then all that was left to do was wire up the form to use that endpoint as its action:

<formid=���calc���method=���post���action=���/process/���># Isometric Edges

It took a fair bit of time to figure this all out, but I���m pretty excited by the possibilities of this approach for building more static isomorphic apps. Oh, and the new site��� is fast.

Why a palindrome? Well, it makes it pretty easy to detect tip fraud because all restaurant totals will always be the same forwards & backwards. It���s a little easier than a checksum. ������

 •  0 comments  •  flag
Share on Twitter
Published on February 03, 2023 12:40