iTEST YOUR SITE IN LYNX null (FALSE) 0 i null (FALSE) 0 i2024-05-01 null (FALSE) 0 i null (FALSE) 0 iWhen was the last time you tested your website in a text-only browser like null (FALSE) 0 iLynx (or ELinks, or one of several others)? Perhaps you should. null (FALSE) 0 i null (FALSE) 0 i null (FALSE) 0 i null (FALSE) 0 iI'm a big fan of CSS Naked Day. I love the idea of JS Naked Day, although I null (FALSE) 0 imissed it earlier this month (I was busy abroad, plus my aggressive caching, null (FALSE) 0 iincluding in service workers, makes it hard to reliably make sweeping changes null (FALSE) 0 ifor short periods). I'm a big fan of the idea that, for the vast majority of null (FALSE) 0 iwebsites, if it isn't at least usable without any CSS or JavaScript, it should null (FALSE) 0 iprobably be considered broken. null (FALSE) 0 i null (FALSE) 0 iThis year, I thought I'd celebrate the events by testing DanQ.me in the null (FALSE) 0 imost-limited browser I had to-hand: Lynx. Lynx has zero CSS or JavaScript null (FALSE) 0 isupport, along with limited-to-no support for heading levels, tables, images, null (FALSE) 0 ietc. That may seem extreme, but it's a reasonable analogue for the level of null (FALSE) 0 ifunctionality you might routinely expect to see in the toughest environments null (FALSE) 0 iin which your site is accessed: slow 2G connections from old mobile hardware, null (FALSE) 0 ipeople on the other side of highly-restrictive firewalls or overenthusiastic null (FALSE) 0 iprivacy and security software, and of course users of accessibility null (FALSE) 0 itechnologies. null (FALSE) 0 i null (FALSE) 0 iHere's what broke (and some other observations): null (FALSE) 0 i null (FALSE) 0 iS AT THE TOP null (FALSE) 0 i null (FALSE) 0 iI see the thinking that Lynx (and in an even more-extreme fashion, ELinks) null (FALSE) 0 ihave with showing "alternate versions" of a page at the top, but it's not null (FALSE) 0 iterribly helpful: most of mine are designed to help robots, not humans! null (FALSE) 0 i null (FALSE) 0 IScreenshot showing four alternate links at the top of DanQ.me as viewed in Lynx. /2024/04/screenshot-01.png danq.me 70 i null (FALSE) 0 iI wonder if switching from elements to Link: HTTP null (FALSE) 0 iheaders would indicate to Lynx that it shouldn't be putting these URLs in null (FALSE) 0 ihumans' faces, while still making them accessible to all the services that null (FALSE) 0 iexpect to find them? Doing so would require some changes to my caching logic, null (FALSE) 0 ibut might result in a cleaner, more human-readable HTML file as a side-effect. null (FALSE) 0 iPossibly something worth investigating. null (FALSE) 0 i null (FALSE) 0 iFortunately, I ensure that my s have a title attribute, null (FALSE) 0 iwhich is respected by Lynx and ELinks and makes these scroll-past links null (FALSE) 0 islightly less-confusing. null (FALSE) 0 i null (FALSE) 0 ILynx screenshot from IKEA.com, showing no fewer than 113 anonymous "alternate" links at the top of the page. /2024/04/screenshot-03.png danq.me 70 i null (FALSE) 0 iPOST LIST INDENTATION null (FALSE) 0 i null (FALSE) 0 iPosts on the homepage are structured a little like this: null (FALSE) 0 i null (FALSE) 0 i
  • null (FALSE) 0 i   null (FALSE) 0 i    

    Post Title

    null (FALSE) 0 i    

    ...post metadata, image, and things...

    null (FALSE) 0 i   null (FALSE) 0 i
  • null (FALSE) 0 iStrictly-speaking, that's not valid. Heading elements are only permitted null (FALSE) 0 iwithin flow elements. I chose to implement it that way because it seemed to be null (FALSE) 0 ithe most semantically-correct way to describe the literal "list of posts". But null (FALSE) 0 iprobably my use of

    is not the best solution. Let's see how Lynx handles null (FALSE) 0 iit: null (FALSE) 0 i null (FALSE) 0 IScreenshot from Lynx showing headings "outdented" from the list items they're children of. /2024/05/screenshot-04.png danq.me 70 i null (FALSE) 0 iIt's not intolerable, but it's a little ugly. null (FALSE) 0 i null (FALSE) 0 iCSS LIGHTBOXES ADD A STEP TO IMAGES null (FALSE) 0 i null (FALSE) 0 iI use a zero-JavaScript approach to image lightboxes: you can see it by null (FALSE) 0 iclicking on any of the images in this post! It works by creating a (closed) null (FALSE) 0 i at the bottom of the page, for each image. Each has a unique null (FALSE) 0 iid, and the inline image links to that anchor. null (FALSE) 0 i null (FALSE) 0 iOriginally, I used a CSS :target selector to detect when the link had been null (FALSE) 0 iclicked and show the . I've since changed this to a :has(:target) and null (FALSE) 0 idirected the link to an element within the dialog, because it works better on null (FALSE) 0 ibrowsers without CSS support. null (FALSE) 0 i null (FALSE) 0 iIt's not perfect: in Lynx navigating on an inline image scrolls down to a list null (FALSE) 0 iof images at the bottom of the page and selects the current one: hitting the null (FALSE) 0 ilink again now offers to download the image. I wonder if I might be better to null (FALSE) 0 iuse a JavaScript-powered lightbox after all! null (FALSE) 0 i null (FALSE) 0 iGOPHER: AND FINGER: LINKS WORK PERFECTLY! null (FALSE) 0 i null (FALSE) 0 iI was pleased to discover that gopher: and finger: links to alternate copies null (FALSE) 0 iof a post... worked perfectly! That shouldn't be a surprise - Lynx natively null (FALSE) 0 isupports these protocols. null (FALSE) 0 i null (FALSE) 0 ILynx screenshot showing DanQ.me via the Finger protocol. /2024/05/screenshot-05.png danq.me 70 i null (FALSE) 0 iIn a fun quirk and unusually for a standard of its age, the Finger null (FALSE) 0 ispecification did not state the character encoding that ought to be used. I null (FALSE) 0 iguess the authors just assumed everybody reading it would use ASCII. But both null (FALSE) 0 imy WordPress-to-Finger bridge and Lynx instead assume that UTF-8 is acceptable null (FALSE) 0 i(being a superset of ASCII, that seems fair!) which means that emoji work (as null (FALSE) 0 ishown in the screenshot above). That's nuts, isn't it? null (FALSE) 0 i null (FALSE) 0 iYOU CAN'T REACT TO ANYTHING null (FALSE) 0 i null (FALSE) 0 iBack in November I added the ability to "react" to a post by clicking an null (FALSE) 0 iemoji, rather than typing out a full comment. Because I was feeling lazy, the null (FALSE) 0 ifeature was (and remains) experimental, and I didn't consider it essential null (FALSE) 0 ifunctionality, I implemented it mostly in JavaScript. Without JavaScript, all null (FALSE) 0 iyou can do is see what others have clicked. null (FALSE) 0 i null (FALSE) 0 iIn a browser with no JavaScript but with functional CSS, the buttons correctly null (FALSE) 0 iappear disabled. null (FALSE) 0 i null (FALSE) 0 iBut with neither technology available, as in Lynx, they look like they should null (FALSE) 0 iwork, but just... don't. Oops. null (FALSE) 0 i null (FALSE) 0 IScreenshot from Lynx showing a "Bad HTML!! No form action defined." error when clicking an emoji reaction button. /2024/05/screenshot-06.png danq.me 70 i null (FALSE) 0 iIf I decide to keep the reaction buttons long-term, I'll probably reimplement null (FALSE) 0 ithem so that they function using plain-old HTML and HTTP, using a
    , and null (FALSE) 0 irefactor my JavaScript to properly progressively-enhance the buttons for those null (FALSE) 0 ithat support it. For now, this'll do. null (FALSE) 0 i null (FALSE) 0 iCOMMENT FORM HONEYPOT null (FALSE) 0 i null (FALSE) 0 iThe comment form on my blog posts works... but there's a quirk: null (FALSE) 0 i null (FALSE) 0 iAt the end of the comments form, an additional appears! null (FALSE) 0 i null (FALSE) 0 iThat's an annoyance. It turns out it's a honeypot added by Akismet: a fake null (FALSE) 0 icomments field, normally hidden, that tries to trick spam bots into filling it null (FALSE) 0 i(and thus giving themselves away): sort-of a "reverse CAPTCHA" where the null (FALSE) 0 irobots do something extra, unintentionally, to prove their inhumanity. Lynx null (FALSE) 0 idoesn't understand the code that Akismet uses to hide the form, and so it's null (FALSE) 0 ivisible to humans, which is suboptimal both because it's confusing but also null (FALSE) 0 ibecause a human who puts details into it is more-likely to be branded a null (FALSE) 0 ispambot! null (FALSE) 0 i null (FALSE) 0 iI might look into suppressing Akismet adding its honeypot field in the first null (FALSE) 0 iplace, or else consider one of the alternative anti-spam plugins for null (FALSE) 0 iWordPress. I've heard good things about Antispam Bee; I ought to try it at null (FALSE) 0 isome point. null (FALSE) 0 i null (FALSE) 0 iOVERALL, IT'S PRETTY GOOD null (FALSE) 0 i null (FALSE) 0 iOn the whole, DanQ.me works reasonably well in browsers without any JavaScript null (FALSE) 0 ior CSS capability, with only a few optional features failing to function null (FALSE) 0 ifully. There's always room for improvement, of course, and I've got a few null (FALSE) 0 ithings now to add to my "one day" to-do list for my little digital garden. null (FALSE) 0 i null (FALSE) 0 iObviously, this isn't really about supporting people using text-mode browsers, null (FALSE) 0 iwho probably represent an incredible minority. It's about making a real null (FALSE) 0 icommitment to the semantic web, to accessibility, and to progressive null (FALSE) 0 ienhancement! That making your site resilient, performant, and accessible also null (FALSE) 0 ihelps make it function in even the most-uncommon of browsers is just a bonus. null (FALSE) 0 i null (FALSE) 0 iLINKS null (FALSE) 0 i null (FALSE) 0 hLynx URL:https://lynx.browser.org/ (FALSE) 0 hELinks URL:http://elinks.or.cz/ (FALSE) 0 h K.Mandla's blog post comparing six text-mode browsers URL:https://kmandla.wordpress.com/2011/01/13/a-comparison-of-text-based-browsers/ (FALSE) 0 hCSS Naked Day URL:https://css-naked-day.github.io/ (FALSE) 0 hJS Naked Day URL:https://js-naked-day.org/ (FALSE) 0 hOEmbed URL:https://oembed.com/ (FALSE) 0 hBlog post describing my zero-JS approach to lightboxes URL:https://danq.me/2023/12/12/no-js-lightbox/ (FALSE) 0 1My blog post describing how I made DanQ.me accessible over the Finger protocol /posts/wp-finger danq.me 70 hFinger specification URL:https://www.rfc-editor.org/rfc/rfc742 (FALSE) 0 hMy blog post about adding emoji reactions URL:https://danq.me/2023/11/24/emoji-reactions/ (FALSE) 0 hRuth URL:https://fleeblewidget.co.uk/ (FALSE) 0 hAkismet URL:https://akismet.com/ (FALSE) 0 hAntispam Bee URL:https://wordpress.org/plugins/antispam-bee/ (FALSE) 0 .