Faster Connectivity !== Faster Websites - Jim Nielsen’s Blog
The bar to overriding browser defaults should be way higher than it is.
Amen!
The bar to overriding browser defaults should be way higher than it is.
Amen!
A great talk from Addy on just how damaging client-side JavaScript can be to the user experience …and what you can do about it.
I documented a weird bug with web audio on iOS a while back:
On some pages of The Session, as well as the audio player for tunes (using the Web Audio API) there are also embedded YouTube videos (using the
video
element). Press play on the audio player; no sound. Press play on the YouTube video; you get sound. Now go back to the audio player and suddenly you do get sound!It’s almost like playing a
video
oraudio
element “kicks” the browser into realising it should be playing the sound from the Web Audio API too.This was happening on iOS devices set to mute, but I was also getting reports of it happening on devices with the sound on. But it’s that annoyingly intermittent kind of bug that’s really hard to reproduce consistently. Sometimes the sound doesn’t play. Sometimes it does.
I found a workaround but it was really hacky. By playing a one-second long silent mp3 file using audio
, you could “kick” the sound into behaving. Then you can use the Web Audio API and it would play consistently.
Well, that’s all changed with the latest release of Mobile Safari. Now what happens is that the Web Audio stuff plays …for one second. And then stops.
I removed the hacky workaround and the Web Audio API started behaving itself again …but your device can’t be set to silent.
The good news is that the Web Audio behaviour seems to be consistent now. It only plays if the device isn’t muted. This restriction doesn’t apply to video
and audio
elements; they will still play even if your device is set to silent.
This descrepancy between the two different ways of playing audio is kind of odd, but at least now the Web Audio behaviour is predictable.
You can hear the Web Audio API in action by going to any tune on The Session and pressing the “play audio” button.
Forms on the web are an opportunity to make big improvements to the user experience with very little effort. The effort can be as little as sprinkling in a smattering of humble HTML attributes. But the result can be a turbo-charged experience for the user, allowing them to sail through their task.
This is particularly true on mobile devices where people have to fill in forms using a virtual keyboard. Any improvement you can make to their flow is worth investigating. But don’t worry: you don’t need to add a complex JavaScript library or write convoluted code. Well-written HTML will get you very far.
If you’re using the right input type
value, you’re most of the way there. Browsers on mobile devices can use this value to infer which version of the virtual keyboard is best. So think beyond the plain text
value, and use search
, email
, url
, tel
, or number
when they’re appropriate.
But you can offer more hints to those browsers. Here are three attributes you can add to input
elements. All three are enumerated values, which means they have a constrained vocabulary. You don’t need to have these vocabularies memorised. You can look them when you need to.
inputmode
The inputmode
attribute is the most direct hint you can give about the virtual keyboard you want. Some of the values are redundant if you’re already using an input type
of search
, email
, tel
, or url
.
But there might be occasions where you want a keyboard optimised for numbers but the input should also accept other characters. In that case you can use an input type
of text
with an inputmode
value of numeric
. This also means you don’t get the spinner controls on desktop browsers that you’d normally get with an input type
of number
. It can be quite useful to supress the spinner controls for numbers that aren’t meant to be incremented.
If you combine inputmode="numeric"
with pattern="[0-9]"
, you’ll get a numeric keypad with no other characters.
The list of possible values for inputmode
is text
, numeric
, decimal
, search
, email
, tel
, and url
.
enterkeyhint
Whereas the inputmode
attribute provides a hint about which virtual keyboard to show, the enterkeyhint
attribute provides an additional hint about one specific key on that virtual keyboard: the enter key.
For search forms, you’ve got an enterkeyhint
option of search
, and for contact forms, you’ve got send
.
The enterkeyhint
only changes the labelling of the enter key. On some browsers that label is text. On others it’s an icon. But the attribute by itself doesn’t change the functionality. Even though there are enterkeyhint
values of previous
and next
, by default the enter key will still submit the form. So those two values are less useful on long forms where the user is going from field to field, and more suitable for a series of short forms.
The list of possible values is enter
, done
, next
, previous
, go
, search
, and send
.
autocomplete
The autocomplete
attribute doesn’t have anything to do with the virtual keyboard. Instead it provides a hint to the browser about values that could pre-filled from the user’s browser profile.
Most browsers try to guess when they can they do this, but they don’t always get it right, which can be annoying. If you explicitly provide an autocomplete
hint, browsers can confidently prefill the appropriate value.
Just think about how much time this can save your users!
There’s a name
value you can use to get full names pre-filled. But if you have form fields for different parts of names—which I wouldn’t recommend—you’ve also got:
given-name
,additional-name
,family-name
,nickname
,honorific-prefix
, andhonorific-suffix
.You might be tempted to use the nickname
field for usernames, but no need; there’s a separate username
value.
As with names, there’s a single tel
value for telephone numbers, but also an array of sub-values if you’ve split telephone numbers up into separate fields:
tel-country-code
,tel-national
,tel-area-code
,tel-local
, andtel-extension
.There’s a whole host of address-related values too:
street-address
,address-line1
,address-line2
, andaddress-line3
, but alsoaddress-level1
,address-level2
,address-level3
, andaddress-level4
.If you have an international audience, addresses can get very messy if you’re trying to split them into separate parts like this.
There’s also postal-code
(that’s a ZIP code for Americans), but again, if you have an international audience, please don’t make this a required field. Not every country has postal codes.
Speaking of countries, you’ve got a country-name
value, but also a country
value for the country’s ISO code.
Remember, the autocomplete
value is specifically for the details of the current user. If someone is filling in their own address, use autocomplete
. But if someone has specified that, say, a billing address and a shipping address are different, that shipping address might not be the address associated with that person.
On the subject of billing, if your form accepts credit card details, definitely use autocomplete
. The values you’ll probably need are:
cc-name
for the cardholder,cc-number
for the credit card number itself,cc-exp
for the expiry date, andcc-csc
for the security again.Again, some of these values can be broken down further if you need them: cc-exp-month
and cc-exp-year
for the month and year of the expiry date, for example.
The autocomplete
attribute is really handy for log-in forms. Definitely use the values of email
or username
as appropriate.
If you’re using two-factor authentication, be sure to add an autocomplete
value of one-time-code
to your form field. That way, the browser can offer to prefill a value from a text message. That saves the user a lot of fiddly copying and pasting. Phil Nash has more details on the Twilio blog.
Not every mobile browser offers this functionality, but that’s okay. This is classic progressive enhancement. Adding an autocomplete
value won’t do any harm to a browser that doesn’t yet understand the value.
Use an autocomplete
value of current-password
for password fields in log-in forms. This is especially useful for password managers.
But if a user has logged in and is editing their profile to change their password, use a value of new-password
. This will prevent the browser from pre-filling that field with the existing password.
That goes for sign-up forms too: use new-password
. With this hint, password managers can offer to automatically generate a secure password.
There you have it. Three little HTML attributes that can help users interact with your forms. All you have to do was type a few more characters in your input
elements, and users automatically get a better experience.
This is a classic example of letting the browser do the hard work for you. As Andy puts it, be the browser’s mentor, not its micromanager:
Give the browser some solid rules and hints, then let it make the right decisions for the people that visit it, based on their device, connection quality and capabilities.
This post has also been translated into French.
The capture
attribute is pretty nifty—and I just love that you get so much power in a declarative way:
<input type="file" accept="image/*" capture="environment">
Following on from that excellent blog post about removing jQuery from gov.uk, here are the performance improvements in charts and numbers.
It may sound like 32 kb of JavaScript is nothing on today’s modern web with quick devices and fast broadband connections. But for a certain cohort of users, it makes a big difference to how they experience GOV.UK.
This is a great succinct definition of progressive enhancement:
Progressive enhancement is a web development strategy by which we ensure that the essential content and functionality of a website is accessible to as many users as possible, while providing an improved experience using newer features for users whose devices are capable of supporting them.
Developers, particularly in Silicon Valley firms, are definitionally wealthy and enfranchised by world-historical standards. Like upper classes of yore, comfort (“DX”) comes with courtiers happy to declare how important comfort must surely be. It’s bunk, or at least most of it is.
As frontenders, our task is to make services that work well for all, not just the wealthy. If improvements in our tools or our comfort actually deliver improvements in that direction, so much the better. But we must never forget that measurable improvement for users is the yardstick.
Remember when I wrote about Web Audio weirdness on iOS? Well, this is a nice little library that wraps up the same hacky solution that I ended up using.
It’s always gratifying when something you do—especially something that feels so hacky—turns out to be independently invented elsewhere.
I told you about how I’m using the Web Audio API on The Session to generate synthesised audio of each tune setting. I also said:
Except for some weirdness on iOS that I had to fix.
Here’s that weirdness…
Let me start by saying that this isn’t anything to do with requiring a user interaction (the Web Audio API insists on some kind of user interaction to prevent developers from having auto-playing sound on websites). All of my code related to the Web Audio API is inside a click
event handler. This is a different kind of weirdness.
First of all, I noticed that if you pressed play on the audio player when your iOS device is on mute, then you don’t hear any audio. Seems logical, right? Except if using the same device, still set to mute, you press play on a video
or audio
element, the sound plays just fine. You can confirm this by going to Huffduffer and pressing play on any of the audio
elements there, even when your iOS device is set on mute.
So it seems that iOS has different criteria for the Web Audio API than it does for audio
or video
. Except it isn’t quite that straightforward.
On some pages of The Session, as well as the audio player for tunes (using the Web Audio API) there are also embedded YouTube videos (using the video
element). Press play on the audio player; no sound. Press play on the YouTube video; you get sound. Now go back to the audio player and suddenly you do get sound!
It’s almost like playing a video
or audio
element “kicks” the browser into realising it should be playing the sound from the Web Audio API too.
This was happening on iOS devices set to mute, but I was also getting reports of it happening on devices with the sound on. But it’s that annoyingly intermittent kind of bug that’s really hard to reproduce consistently. Sometimes the sound doesn’t play. Sometimes it does.
Following my theory that the browser needs a “kick” to get into the right frame of mind for the Web Audio API, I resorted to a messy little hack.
In the event handler for the audio player, I generate the “kick” by playing a second of silence using the JavaScript equivalent of the audio
element:
var audio = new Audio('1-second-of-silence.mp3');
audio.play();
I’m not proud of that. It’s so hacky that I’ve even wrapped the code in some user-agent sniffing on the server, and I never do user-agent sniffing!
Still, if you ever find yourself getting weird but inconsistent behaviour on iOS using the Web Audio API, this nasty little hack could help.
Update: Time to remove this workaround. Mobile Safari has been updated.
Back in March, I wrote about a dilemma I was facing. I could make the certificates on The Session more secure. But if I did that, people using older Android and iOS devices could no longer access the site:
As a site owner, I can either make security my top priority, which means you’ll no longer be able to access my site. Or I can provide you access, which makes my site less secure for everyone.
In the end, I decided in favour of access. But now this issue has risen from the dead. And this time, it doesn’t matter what I think.
Let’s Encrypt are changing the way their certificates work and once again, it’s people with older devices who are going to suffer:
Most notably, this includes versions of Android prior to 7.1.1. That means those older versions of Android will no longer trust certificates issued by Let’s Encrypt.
This makes me sad. It’s another instance of people being forced to buy new devices. Last time ‘round, my dilemma was choosing between security and access. This time, access isn’t an option. It’s a choice between security and the environment (assuming that people are even in a position to get new devices—not an assumption I’m willing to make).
But this time it’s out of my hands. Let’s Encrypt certificates will stop working on older devices and a whole lotta websites are suddenly going to be inaccessible.
I could look at using a different certificate authority, one I’d have to pay for. It feels a bit galling to have to go back to the scammy world of paying for security—something that Let’s Encrypt has taught us should quite rightly be free. But accessing a website should also be free. It shouldn’t come with the price tag of getting a new device.
The street finds its own uses for things, and it may be that the use for Google Glass is assistive technology. Here’s Léonie’s in-depth hands-on review of Envision Glasses, based on Google Glass.
The short wait whilst the image is processed is mitigated by the fact a double tap is all that’s needed to request another scene description, and being able to do it just by looking at what I’m interested in and tapping a couple of times on my glasses is nothing short of happiness in a pair of spectacles.
Excellent research by Jeremy Wagner comparing the performance impact of React, Preact, and vanilla JavaScript. The results are simultaneously shocking and entirely unsurprising.
This is a great case study of the excellent California COVID-19 response site. Accessibility and performance are the watchwords here.
Want to know their secret weapon?
A $20 device running Android 9, with no contract commitment has been one of the most useful and effective tools in our effort to be accessible.
Leaner, faster sites benefit everybody, but making sure your applications run smoothly on low-end hardware makes a massive difference for those users.
The cloud gives us collaboration, but old-fashioned apps give us ownership. Can’t we have the best of both worlds?
We would like both the convenient cross-device access and real-time collaboration provided by cloud apps, and also the personal ownership of your own data embodied by “old-fashioned” software.
This is a very in-depth look at the mindset and the challenges involved in building truly local-first software—something that Tantek has also been thinking about.
Apple aren’t the best at developer relations. But, bad as their communications can be, I’m willing to cut them some slack. After all, they’re not used to talking with the developer community.
John Wilander wrote a blog post that starts with some excellent news: Full Third-Party Cookie Blocking and More. Safari is catching up to Firefox and disabling third-party cookies by default. Wonderful! I’ve had third-party cookies disabled for a few years now, and while something occassionally breaks, it’s honestly a pretty great experience all around. Denying companies the ability to track users across sites is A Good Thing.
In the same blog post, John said that client-side cookies will be capped to a seven-day lifespan, as previously announced. Just to be clear, this only applies to client-side cookies. If you’re setting a cookie on the server, using PHP or some other server-side language, it won’t be affected. So persistent logins are still doable.
Then, in an audacious example of burying the lede, towards the end of the blog post, John announces that a whole bunch of other client-side storage technologies will also be capped to seven days. Most of the technologies are APIs that, like cookies, can be used to store data: Indexed DB, Local Storage, and Session Storage (though there’s no mention of the Cache API). At the bottom of the list is this:
Service Worker registrations
Okay, let’s clear up a few things here (because they have been so poorly communicated in the blog post)…
The seven day timer refers to seven days of Safari usage, not seven calendar days (although, given how often most people use their phones, the two are probably interchangable). So if someone returns to your site within a seven day period of using Safari, the timer resets to zero, and your service worker gets a stay of execution. Lucky you.
This only applies to Safari. So if your site has been added to the home screen and your web app manifest has a value for the “display” property like “standalone” or “full screen”, the seven day timer doesn’t apply.
That piece of information was missing from the initial blog post. Since the blog post was updated to include this clarification, some people have taken this to mean that progressive web apps aren’t affected by the upcoming change. Not true. Only progressive web apps that have been added to the home screen (and that have an appropriate “display” value) will be spared. That’s a vanishingly small percentage of progressive web apps, especially on iOS. To add a site to the home screen on iOS, you need to dig and scroll through the share menu to find the right option. And you need to do this unprompted. There is no ambient badging in Safari to indicate that a site is installable. Chrome’s install banner isn’t perfect, but it’s better than nothing.
Just a reminder: a progressive web app is a website that
Adding to the home screen is something you can do with a progressive web app (or any other website). It is not what defines progressive web apps.
In any case, this move to delete service workers after seven days of using Safari is very odd, and I’m struggling to find the connection to the rest of the blog post, which is about technologies that can store data.
As I understand it, with the crackdown on setting third-party cookies, trackers are moving to first-party technologies. So whereas in the past, a tracking company could tell its customers “Add this script
element to your pages”, now they have to say “Add this script
element and this script file to your pages.” That JavaScript file can then store a unique idenitifer on the client. This could be done with a cookie, with Local Storage, or with Indexed DB, for example. But I’m struggling to understand how a service worker script could be used in this way. I’d really like to see some examples of this actually happening.
The best explanation I can come up with for this move by Apple is that it feels like the neatest solution. That’s neat as in tidy, not as in nifty. It is definitely not a nifty solution.
If some technologies set by a specific domain are being purged after seven days, then the tidy thing to do is purge all technologies from that domain. Service workers are getting included in that dragnet.
Now, to be fair, browsers and operating systems are free to clean up storage space as they see fit. Caches, Local Storage, Indexed DB—all of those are subject to eventually getting cleaned up.
So I was curious. Wanting to give Apple the benefit of the doubt, I set about trying to find out how long service worker registrations currently last before getting deleted. Maybe this announcement of a seven day time limit would turn out to be not such a big change from current behaviour. Maybe currently service workers last for 90 days, or 60, or just 30.
Nope:
There was no time limit previously.
This is not a minor change. This is a crippling attack on service workers, a technology specifically designed to improve the user experience for return visits, whether it’s through improved performance or offline access.
I wouldn’t be so stunned had this announcement come with an accompanying feature that would allow Safari users to know when a website is a progressive web app that can be added to the home screen. But Safari continues to ignore the existence of progressive web apps. And now it will actively discourage people from using service workers.
If you’d like to give feedback on this ludicrous development, you can file a bug (down in the cellar in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying “Beware of the Leopard”).
No doubt there will still be plenty of Apple apologists telling us why it’s good that Safari has wished service workers into the cornfield. But make no mistake. This is a terrible move by Apple.
I will say this though: given The Situation we’re all living in right now, some good ol’ fashioned Hot Drama by a browser vendor behaving badly feels almost comforting.
I made an offhand remark at the Clearleft Christmas party and Trys ran with it…
This is the transcript of a brilliant presentation by Scott—read the whole thing! It starts with a much-needed history lesson that gets to where we are now with the dismal state of performance on the web, and then gives a whole truckload of handy tips and tricks for improving performance when it comes to styles, scripts, images, fonts, and just about everything on the front end.
Essential!
The inexorable rise of frameworks such as Angular, React, Vue and their many cousins has been led by an assumption that managing state in the browser is quicker than a request to a server. This assumption, I can only assume, is made by developers who have flagship mobile devices or primarily work on desktop devices.
Testing on a <$100 Android device on a 3G network should be an integral part of testing your website. Not everyone is on a brand-new device or upgrades often, especially with the price point of a high-end phones these days.
When we design and build our websites with the outliers in mind, whether it’s for performance or even user experience, we build an experience that can be easy for all to access and use — and that’s what the web is about, access and information for all.