Encouraging thoughtful alt text behavior on Mastodon with CSS

The admins of my Mastodon instance, front-end.social, have done a terrific job of encouraging good alt-text habits by using some custom CSS to apply badges to every user-posted image.

A green alt badge in the lower left corner of the image indicates the image contains alt text:

A post on Mastodon has an image alt text; a small green badge that reads 'alt' appears in the lower left corner

while a red no alt badge indicates alt text is missing:

A post on Mastodon has an image without alt text; a small red badge that reads 'no alt' appears in the lower left corner

I don't use a screen reader to navigate the web, but I still find a lot of personal benefit from having these badges displayed on Mastodon.

Badging as a (public) service

Knowing that any images I post will be badged locally is a helpful nudge to always add alt text, lest my fellow instance users see I got careless or lazy 😬

Just as importantly, posts from all users are badged regardless of what instance they're on, letting me know whether I should share that post with anyone who follows me.

No alt, no boost

Without badging, I might not take the time to investigate whether an image has been described, and inadvertently boost an image without alt text into the timeline of someone who depends on a screen reader.

Thanks to my instance admins, though, seeing the red no alt badge is a simple way for me to know not to boost that post. Conversely, an alt badge gives me the green light to boost, knowing the author has taken the time to describe the image.

Adding badges to your instance

Mastodon provides admins the ability to add custom CSS to their instances, which is rad. (I'm not an admin, so I'm not sure where this lives exactly.)

If you're interested in having alt text badging on your instance, I'd encourage you to ask your admin to copy or adapt these styles from front-end.social:

 * Copied from https://about.front-end.social/css/override.css on 2022-12-27
 * Check the original source for updates.

/* show when images have alt text */
.media-gallery__item {
  --alt-crop-x: 6ch;
  --alt-crop-y: 2em;
  background: darkgreen;
  color: white;

/* only revealed by cutaway when alt is defined */
.media-gallery__item::after {
  content: "alt";
  display: grid;
  inset-block-end: 0;
  inset-inline-start: 0;
  min-height: var(--alt-crop-y);
  min-width: var(--alt-crop-x);
  place-content: center;
  position: absolute;

/* cut away to reveal badge */
.media-gallery__item img[alt] {
  clip-path: polygon(0 0, 100% 0, 100% 100%, var(--alt-crop-x) 100%, var(--alt-crop-x) calc(100% - var(--alt-crop-y)), 0 calc(100% - var(--alt-crop-y)));

/* Remove the clip path if we can do better with :has() */
.media-gallery__item:has(img) img[alt] {
  clip-path: none;

/* Apply better alt-text badge over top of image */
.media-gallery__item:has(img)::after {
  --alt-crop-x: initial;
  --alt-crop-y: initial;
  background: darkgreen;
  border: thin solid rgba(255, 255, 255, 0.4);
  border-radius: 3px;
  inset-block-end: 0.5em;
  inset-inline-start: 0.5em;
  padding: 0.25rem 0.5rem;
  position: absolute;
  pointer-events: none;
  z-index: 2;

/* Change badge when no alt is defined */
.media-gallery__item:has(img:not([alt]))::after {
  background: maroon;
  content: "no alt";