Tags: age

3259

sparkline

Thursday, January 21st, 2021

Letters of exclusion

I think my co-workers are getting annoyed with me. Any time they use an acronym or initialism—either in a video call or Slack—I ask them what it stands for. I’m sure they think I’m being contrarian.

The truth is that most of the time I genuinely don’t know what the letters stand for. And I’ve got to that age where I don’t feel any inhibition about asking “stupid” questions.

But it’s also true that I really, really dislike acronyms, initialisms, and other kinds of jargon. They’re manifestations of gatekeeping. They demarcate in-groups from outsiders.

Of course if you’re in a conversation with an in-group that has the same background and context as you, then sure, you can use acronyms and initialisms with the confidence that there’s a shared understanding. But how often can you be that sure? The more likely situation—and this scales exponentially with group size—is that people have differing levels of inside knowledge and experience.

I feel sorry for anyone trying to get into the field of web performance. Not only are there complex browser behaviours to understand, there’s also a veritable alphabet soup of initialisms to memorise. Here’s a really good post on web performance by Harry, but notice how the initialisms multiply like tribbles as the post progresses until we’re talking about using CWV metrics like LCP, FID, and CLS—alongside TTFB and SI—to look at PLPs, PDPs, and SRPs. And fair play to Harry; he expands each initialism the first time he introduces it.

But are we really saving any time by saying FID instead of first input delay? I suspect that the only reason why the word “cumulative” precedes “layout shift” is just to make it into the three-letter initialism CLS.

Still, I get why initialisms run rampant in technical discussions. You can be sure that most discussions of particle physics would be incomprehensible to outsiders, not necessarily because of the concepts, but because of the terminology.

Again, if you’re certain that you’re speaking to peers, that’s fine. But if you’re trying to communicate even a little more widely, then initialisms and abbreviations are obstacles to overcome. And once you’re in the habit of using the short forms, it gets harder and harder to apply context-shifting in your language. So the safest habit to form is to generally avoid using acronyms and initialisms.

Unnecessary initialisms are exclusionary.

Think about on-boarding someone new to your organisation. They’ve already got a lot to wrap their heads around without making them figure out what a TAM is. That’s a real example from Clearleft. We have a regular Thursday afternoon meeting. I call it the Thursday afternoon meeting. Other people …don’t.

I’m trying—as gently as possible—to ensure we’re not being exclusionary in our language. My co-workers indulge me, even it’s just to shut me up.

But here’s the thing. I remember many years back when a job ad went out on the Clearleft website that included the phrase “culture fit”. I winced and explained why I thought that was a really bad phrase to use—one that is used as code for “more people like us”. At the time my concerns were met with eye-rolls and chuckles. Now, as knowledge about diversity and inclusion has become more widespread, everyone understands that using a phrase like “culture fit” can be exclusionary.

But when I ask people to expand their acronyms and initialisms today, I get the same kind of chuckles. My aversion to abbreviations is an eccentric foible to be tolerated.

But this isn’t about me.

Sunday, January 17th, 2021

Checked in at Queen's Park. Parklife! — with Jessica map

Checked in at Queen’s Park. Parklife! — with Jessica

Saturday, December 26th, 2020

Talking out loud to yourself is a technology for thinking | Psyche Ideas

This explains rubber ducking.

Speaking out loud is not only a medium of communication, but a technology of thinking: it encourages the formation and processing of thoughts.

Friday, December 18th, 2020

Conditional JavaScript - JavaScript - Dev Tips

This is a good round-up of APIs you can use to decide if and how much JavaScript to load. I might look into using storage.estimate() in service workers to figure out how much gets pre-cached.

Wednesday, December 16th, 2020

Fluffy sheep grazing on the hillside in the low winter sunlight.

Fluffy sheep grazing on the hillside in the low winter sunlight.

Tuesday, December 15th, 2020

Cascading Style Sheets

There are three ways—that I know of—to associate styles with markup.

External CSS

This is probably the most common. Using a link element with a rel value of “stylesheet”, you point to a URL using the href attribute. That URL is a style sheet that is applied to the current document (“the relationship of the linked resource it is that is a ‘stylesheet’ for the current document”).

<link rel="stylesheet" href="/path/to/styles.css">

In theory you could associate a style sheet with a document using an HTTP header, but I don’t think many browsers support this in practice.

You can also pull in external style sheets using the @import declaration in CSS itself, as long as the @import rule is declared at the start, before any other styles.

@import url('/path/to/more-styles.css');

When you use link rel="stylesheet" to apply styles, it’s a blocking request: the browser will fetch the style sheet before rendering the HTML. It needs to know how the HTML elements will be painted to the screen so there’s no point rendering the HTML until the CSS is parsed.

Embedded CSS

You can also place CSS rules inside a style element directly in the document. This is usually in the head of the document.

<style>
element {
    property: value;
}
</style>

When you embed CSS in the head of a document like this, there is no network request like there would be with external style sheets so there’s no render-blocking behaviour.

You can put any CSS inside the style element, which means that you could use embedded CSS to load external CSS using an @import statement (as long as that @import statement appears right at the start).

<style>
@import url('/path/to/more-styles.css');
element {
    property: value;
}
</style>

But then you’re back to having a network request.

Inline CSS

Using the style attribute you can apply CSS rules directly to an element. This is a universal attribute. It can be used on any HTML element. That doesn’t necessarily mean that the styles will work, but your markup is never invalidated by the presence of the style attribute.

<element style="property: value">
</element>

Whereas external CSS and embedded CSS don’t have any effect on specificity, inline styles are positively radioactive with specificity. Any styles applied this way are almost certain to over-ride any external or embedded styles.

You can also apply styles using JavaScript and the Document Object Model.

element.style.property = 'value';

Using the DOM style object this way is equivalent to inline styles. The radioactive specificity applies here too.

Style declarations specified in external style sheets or embedded CSS follow the rules of the cascade. Values can be over-ridden depending on the order they appear in. Combined with the separate-but-related rules for specificity, this can be very powerful. But if you don’t understand how the cascade and specificity work then the results can be unexpected, leading to frustration. In that situation, inline styles look very appealing—there’s no cascade and everything has equal specificity. But using inline styles means foregoing a lot of power—you’d be ditching the C in CSS.

A common technique for web performance is to favour embedded CSS over external CSS in order to avoid the extra network request (at least for the first visit—there are clever techniques for caching an external style sheet once the HTML has already loaded). This is commonly referred to as inlining your CSS. But really it should be called embedding your CSS.

This language mix-up is not a hill I’m going to die on (that hill would be referring to blog posts as blogs) but I thought it was worth pointing out.

Monday, December 14th, 2020

Web Almanac 2020

I spent most of the weekend reading through this and I’ve still barely scratched the surface—a lot of work has gone to the analyses and write-ups!

The sections on accessibility and performance get grimmer each year but the raw numbers on framework adaption are refreshingly perspective-setting.

Thursday, December 10th, 2020

Watching one of my favourite presenters—@CassieCodes talking about SVG animation!

Watching one of my favourite presenters—@CassieCodes talking about SVG animation!

Tuesday, December 8th, 2020

What Makes CSS Hard To Master - Tim Severien

CSS is simple, but not easy.

If we, as a community, start to appreciate the complexity of writing CSS, perhaps we can ask for help instead of blaming the language when we’re confused or stuck. We might also stop looking down on CSS specialists.

Wednesday, December 2nd, 2020

Creating websites with prefers-reduced-data | Polypane Browser for Developers

There’s no browser support yet but that doesn’t mean we can’t start adding prefers-reduced-data to our media queries today. I like the idea of switching between web fonts and system fonts.

Wednesday, November 25th, 2020

I met some nice sheep on yesterday’s walk. 🐑

I met some nice sheep on yesterday’s walk. 🐑

Sunday, November 22nd, 2020

Static sites, slack and scrollytelling. | Clearleft

Cassie’s enthusiasm for fun and interesting SVG animation shines through in her writing!

Friday, November 13th, 2020

Levelled up my blood donation game! You can challenge my score here: https://www.blood.co.uk 🩸🥇

Levelled up my blood donation game!

You can challenge my score here: https://www.blood.co.uk

🩸🥇

Thursday, November 12th, 2020

Caching and storing

When I was speaking at conferences last year about service workers, I’d introduce the Cache API. I wanted some way of explaining the difference between caching and other kinds of storage.

The way I explained was that, while you might store stuff for a long time, you’d only cache stuff that you knew you were going to need again. So according to that definition, when you make a backup of your hard drive, that’s not caching …becuase you hope you’ll never need to use the backup.

But that explanation never sat well with me. Then more recently, I was chatting with Amber about caching. Once again, we trying to define the difference between, say, the Cache API and things like LocalStorage and IndexedDB. At some point, we realised the fundamental difference: caches are for copies.

Think about it. If you store something in LocalStorage or IndexedDB, that’s the canonical home for that data. But anything you put into a cache must be a copy of something that exists elsewhere. That’s true of the Cache API, the browser cache, and caches on the server. An item in one of those caches is never the original—it’s always a copy of something that has a canonical home elsewhere.

By that definition, backing up your hard drive definitely is caching.

Anyway, I was glad to finally have a working definition to differentiate between caching and storing.

Saturday, November 7th, 2020

Digital gardens let you cultivate your own little bit of the internet | MIT Technology Review

Some suggested that the digital garden was a backlash to the internet we’ve become grudgingly accustomed to, where things go viral, change is looked down upon, and sites are one-dimensional. Facebook and Twitter profiles have neat slots for photos and posts, but enthusiasts of digital gardens reject those fixed design elements. The sense of time and space to explore is key.

Sunday, November 1st, 2020

Presentable #96: The Employee-Owned Design Agency - Relay FM

If you want to know more about Clearleft’s new employee-ownserhip model, Andy tells Jeff all about it in this huffduffable hour of audio.

Saturday, October 31st, 2020

Creepy potato.

Creepy potato.

Wednesday, October 21st, 2020

Chrome exempts Google sites from user site data settings

Collusion between three separate services owned by the same company: the Google search engine, the YouTube website, and the Chrome web browser.

Gosh, this kind of information could be really damaging if there were, say, antitrust proceedings initiated.

In the meantime, use Firefox

Sunday, October 18th, 2020

Checked in at Baker Street Coffee. Flat whites outdoors — with Jessica map

Checked in at Baker Street Coffee. Flat whites outdoors — with Jessica

Wednesday, October 14th, 2020

Saving forms

I added a long-overdue enhancement to The Session recently. Here’s the scenario…

You’re on a web page with a comment form. You type your well-considered thoughts into a textarea field. But then something happens. Maybe you accidentally navigate away from the page or maybe your network connection goes down right when you try to submit the form.

This is a textbook case for storing data locally on the user’s device …at least until it has safely been transmitted to the server. So that’s what I set about doing.

My first decision was choosing how to store the data locally. There are multiple APIs available: sessionStorage, IndexedDB, localStorage. It was clear that sessionStorage wasn’t right for this particular use case: I needed the data to be saved across browser sessions. So it was down to IndexedDB or localStorage. IndexedDB is the more versatile and powerful—because it’s asynchronous—but localStorage is nice and straightforward so I decided on that. I’m not sure if that was the right decision though.

Alright, so I’m going to store the contents of a form in localStorage. It accepts key/value pairs. I’ll make the key the current URL. The value will be the contents of that textarea. I can store other form fields too. Even though localStorage technically only stores one value, that value can be a JSON object so in reality you can store multiple values with one key (just remember to parse the JSON when you retrieve it).

Now I know what I’m going to store (the textarea contents) and how I’m going to store it (localStorage). The next question is when should I do it?

I could play it safe and store the comment whenever the user presses a key within the textarea. But that seems like overkill. It would be more efficient to only save when the user leaves the current page for any reason.

Alright then, I’ll use the unload event. No! Bad Jeremy! If I use that then the browser can’t reliably add the current page to the cache it uses for faster back-forwards navigations. The page life cycle is complicated.

So beforeunload then? Well, maybe. But modern browsers also support a pagehide event that looks like a better option.

In either case, just adding a listener for the event could screw up the caching of the page for back-forwards navigations. I should only listen for the event if I know that I need to store the contents of the textarea. And in order to know if the user has interacted with the textarea, I’m back to listening for key presses again.

But wait a minute! I don’t have to listen for every key press. If the user has typed anything, that’s enough for me. I only need to listen for the first key press in the textarea.

Handily, addEventListener accepts an object of options. One of those options is called “once”. If I set that to true, then the event listener is only fired once.

So I set up a cascade of event listeners. If the user types anything into the textarea, that fires an event listener (just once) that then adds the event listener for when the page is unloaded—and that’s when the textarea contents are put into localStorage.

I’ve abstracted my code into a gist. Here’s what it does:

  1. Cut the mustard. If this browser doesn’t support localStorage, bail out.
  2. Set the localStorage key to be the current URL.
  3. If there’s already an entry for the current URL, update the textarea with the value in localStorage.
  4. Write a function to store the contents of the textarea in localStorage but don’t call the function yet.
  5. The first time that a key is pressed inside the textarea, start listening for the page being unloaded.
  6. When the page is being unloaded, invoke that function that stores the contents of the textarea in localStorage.
  7. When the form is submitted, remove the entry in localStorage for the current URL.

That last step isn’t something I’m doing on The Session. Instead I’m relying on getting something back from the server to indicate that the form was successfully submitted. If you can do something like that, I’d recommend that instead of listening to the form submission event. After all, something could still go wrong between the form being submitted and the data being received by the server.

Still, this bit of code is better than nothing. Remember, it’s intended as an enhancement. You should be able to drop it into any project and improve the user experience a little bit. Ideally, no one will ever notice it’s there—it’s the kind of enhancement that only kicks in when something goes wrong. A little smidgen of resilient web design. A defensive enhancement.