<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>Web Development &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Sat, 18 Oct 2025 22:41:02 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>Web Development &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Getting started with simple CSS View Transitions]]></title>
		<link>https://shkspr.mobi/blog/2025/10/getting-started-with-simple-css-view-transitions/</link>
					<comments>https://shkspr.mobi/blog/2025/10/getting-started-with-simple-css-view-transitions/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 21 Oct 2025 11:34:07 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=64009</guid>

					<description><![CDATA[There&#039;s (yet another) new piece of CSS to learn! Hurrah!  Way back in 2011, jQuery mobile introduced the web to page-change animations. Clicking on a link would make your high-tech Nokia display a cool page-flip as you navigated from one page of a website to another. Just like an app!!!!  A decade-and-a-half later, and CSS has caught up (mostly). No more JavaScript, just spec-compliant CSS. Well, …]]></description>
										<content:encoded><![CDATA[<p>There's (yet another) new piece of CSS to learn! Hurrah!</p>

<p>Way back in 2011, <a href="https://demos.jquerymobile.com/1.1.0/docs/pages/page-transitions.html">jQuery mobile introduced the web to page-change animations</a>. Clicking on a link would make your high-tech Nokia display a cool page-flip as you navigated from one page of a website to another. Just like an app!!!!</p>

<p>A decade-and-a-half later, and CSS has caught up (mostly). No more JavaScript, just spec-compliant CSS. Well, as long as you're using Chrome or Safari.  Here's a quick quick MVP which will add some fancy animations as people browse your website.</p>

<p>Every page which wants animations has to "opt in". That means you need this:</p>

<pre><code class="language-css">@view-transition {
    navigation: auto;
}
</code></pre>

<p>Next, you'll probably want to define some animations. Here are two I use:</p>

<pre><code class="language-css">@keyframes slide-in {
    from {
        translate: 100vw 0;
    }
}

@keyframes fade-out {
    to {
        opacity: 0;
    }
}
</code></pre>

<p>Any standard CSS animation will work. Get creative!</p>

<p>Which elements do you want to animate? I'm just going to do the whole page.</p>

<pre><code class="language-css">html {
    view-transition-name: page;
}
</code></pre>

<p>If you have a fancy app-like site, you might only want to animate specific parts of it.</p>

<p>While the page is transitioning, you can have something in the background to prevent things looking odd.</p>

<pre><code class="language-css">::view-transition {
    background: black;
}
</code></pre>

<p>That's optional, but rather useful.</p>

<p>Next, we have to assign the animations to specific events. Here, I have the old page fade out and the new page slide in.</p>

<pre><code class="language-css">::view-transition-old(page) {
    animation-name: fade-out;
    animation-duration: 1s;
}

::view-transition-new(page) {
    animation-name: slide-in;
    animation-duration: 1s;
}
</code></pre>

<p>You can set the duration to whatever makes sense for your page and animation style.</p>

<p>Finally, and this is <strong>important</strong>, some people find animations painful or discombobulating. Make sure the animations are turned off for those who don't like them.</p>

<pre><code class="language-css">@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(page) {
        animation-duration: 0s;
    }
}
</code></pre>

<p>And that's it! A couple of dozen lines of CSS and you've got started with view transitions.</p>

<p>For more information, you can <a href="https://view-transitions.chrome.dev/">see the Chrome Devs' demo page</a>, or take a read of <a href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API">the MDN documentation</a>. There's also a <a href="https://drafts.csswg.org/css-view-transitions-2/">full spec document</a> if you like that sort of thing.</p>

<p>Right, I'm off to create some delightful animations!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=64009&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/10/getting-started-with-simple-css-view-transitions/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Using a CSS cursor to show the external link's favicon]]></title>
		<link>https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/</link>
					<comments>https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 28 Oct 2024 12:34:18 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=53652</guid>

					<description><![CDATA[How do you know where this link goes to?  If you&#039;re on a desktop, you might notice that hovering your mouse over it displays the destination somewhere on your screen. If you&#039;re a geek, you could view the source-code of a page.  Can we improve the experience for users? Here&#039;s an attempt.  Try hovering your cursor over this link to a popular website.  This is what it should look like:    Here&#039;s how …]]></description>
										<content:encoded><![CDATA[<p>How do you know where <a href="https://google.com">this link</a> goes to?</p>

<p>If you're on a desktop, you <em>might</em> notice that hovering your mouse over it displays the destination <em>somewhere</em> on your screen. If you're a geek, you could view the source-code of a page.</p>

<p>Can we improve the experience for users? Here's an attempt.</p>

<p>Try hovering your cursor over <a href="https://google.com/" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/google.com.ico&quot;), auto;">this link to a popular website</a>.</p>

<p>This is what it should look like:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/10/hover-fs8.png" alt="A link with the Google logo hovering over it." width="500" height="46" class="aligncenter size-full wp-image-53656">

<p>Here's how it works.</p>

<h2 id="cursor-styles"><a href="https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/#cursor-styles">Cursor Styles</a></h2>

<p>CSS allows us to <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/cursor" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/developer.mozilla.org.ico&quot;), auto;">change the icon displayed by a cursor</a>.  There are dozens of built-in icons, but you can also <a href="https://drafts.csswg.org/css-ui/#cursor" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/w3.org.ico&quot;), auto;">supply your own image file</a>.</p>

<pre><code class="language-css">#link {
   cursor: url("/path/to/image.png"), auto;
}
</code></pre>

<p>Anything hovering over that link will get that .png as its cursor. Nifty!</p>

<h2 id="favicons"><a href="https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/#favicons">Favicons</a></h2>

<p>Most websites have <a href="https://en.wikipedia.org/wiki/Favicon" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/wikipedia.org.ico&quot;), auto;">a Favicon</a> - it is a little image that you see in your browser bar, or when you save a website to your favourites. It is usually found at <code>/favicon.ico</code> - but can be in a variety of places.</p>

<p>There are dozens of free and paid services which let you quickly grab a favicon from any site.</p>

<p>The one I tend to use is DuckDuckGo's service. It takes any domain name, like Google.com, and returns an icon. It looks like this <code>https://icons.duckduckgo.com/ip9/google.com.ico</code></p>

<h2 id="putting-it-all-together"><a href="https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/#putting-it-all-together">Putting it all together</a></h2>

<p>You can put the CSS anywhere - including inline with your links:</p>

<pre><code class="language-html">&lt;a
  href="https://google.com/"
  style='cursor:url("https://icons.duckduckgo.com/ip9/google.com.ico"), auto;'
&gt;Visit this website&lt;/a&gt;!
</code></pre>

<h2 id="is-this-a-good-idea"><a href="https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/#is-this-a-good-idea">Is this a good idea?</a></h2>

<p>Well… maybe? If you have lots of links to various destinations and don't want to clutter up your prose with "(Wikipedia)" or other things like that, it could be useful.</p>

<p>Not everyone will recognise the logo for every service - so it may not add anything useful.</p>

<p>It doesn't work on mobile.</p>

<p>This isn't a common UI pattern - which might be a little confusing for users.</p>

<p>Loading images from remote sites is <em>probably not</em> a security concern. But if a website is hacked, you might have unwanted images on your site.</p>

<p>A site could lie to you about its destination.</p>

<p>Automating it should be possible, but it could be a bit of a faff to maintain.</p>

<p>But it  <a href="https://disney.com/" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/disney.com.ico&quot;), auto;">looks</a>  <a href="https://openbenches.org/" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/openbenches.org.ico&quot;), auto;">so</a>  <a href="https://edent.tel/" style="cursor: url(&quot;https://icons.duckduckgo.com/ip9/edent.tel.ico&quot;), auto;">pretty</a>!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=53652&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/10/using-a-css-cursor-to-show-the-external-links-favicon/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Inline CSS - The Link "Cheat"]]></title>
		<link>https://shkspr.mobi/blog/2024/08/inline-css-the-link-cheat/</link>
					<comments>https://shkspr.mobi/blog/2024/08/inline-css-the-link-cheat/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 29 Aug 2024 11:34:42 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=52225</guid>

					<description><![CDATA[I am a bear of very little brains sometimes.  I had a site which, for various boring reasons, was printing a &#60;style&#62; element in the middle of the HTML&#039;s body.  Because &#60;style&#62; is a metadata element, it should only appear within the &#60;head&#62; element.  This is OK:  &#60;!doctype html&#62; &#60;html&#62;    &#60;head&#62;       &#60;style&#62; a { color: #f00; } &#60;/style&#62;    &#60;/head&#62;    &#60;body&#62;       …   This is an error:  &#60;!doctype h…]]></description>
										<content:encoded><![CDATA[<p>I am a bear of very little brains sometimes.</p>

<p>I had a site which, for various boring reasons, was printing a <code>&lt;style&gt;</code> element in the middle of the HTML's body.  Because <code>&lt;style&gt;</code> is a metadata element, <a href="https://html.spec.whatwg.org/multipage/semantics.html#the-style-element">it should only appear within the <code>&lt;head&gt;</code> element</a>.</p>

<p>This is OK:</p>

<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
   &lt;head&gt;
      &lt;style&gt; a { color: #f00; } &lt;/style&gt;
   &lt;/head&gt;
   &lt;body&gt;
      …
</code></pre>

<p>This is an error:</p>

<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
   &lt;head&gt;
   &lt;/head&gt;
   &lt;body&gt;
      &lt;style&gt; a { color: #f00; } &lt;/style&gt;
      …
</code></pre>

<p>Most modern browsers will parse the stylesheet and not complain. But I like doing things properly and to spec because I am a massive boring nerd who is no fun at parties.</p>

<p>There is another way to include CSS in a document - via the <code>&lt;link&gt;</code> element.</p>

<pre><code class="language-html">&lt;link rel="stylesheet" type="text/css" href="https://example.com/style.css"&gt;
</code></pre>

<p>It is <a href="https://html.spec.whatwg.org/multipage/links.html#body-ok"><em>sometimes</em> OK to have a <code>&lt;link&gt;</code> element in the <code>&lt;body&gt;</code></a> - but can you spot the problem? Yes! The <code>href</code> points to an external resource. That's no good because we want to put the CSS <em>inline</em>.</p>

<p>The <code>href</code> needs to point to a URl. But it can point to <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs">a <em>data</em> URl</a>!!!!</p>

<p>So, if the CSS is first Base64 encoded, it's possible to place inline CSS <em>within</em> the body of the HTML document!!!!!!!</p>

<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
   &lt;head&gt;
   &lt;/head&gt;
   &lt;body&gt;
      &lt;link rel="stylesheet" type="text/css" href="data:text/css;base64,Q29uZ3JhdHVsYXRpb25zISBZb3UgZm91bmQgbXkgc2VjcmV0IG1lc3NhZ2UhIFlvdSByZWNlaXZlICs1IEludGVybmV0IHBvaW50cy4="&gt;
      …
</code></pre>

<p>This also works with URl encoding, if you prefer that, thusly:</p>

<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
   &lt;head&gt;
   &lt;/head&gt;
   &lt;body&gt;
      &lt;link rel="stylesheet" type="text/css" href="data:text/css,%2F%2A%0AThis%20is%20my%20CSS%0A%2A%2F%0Aa%20%20%7Bfont-family%3Amonospace%3B%7D"&gt;
      …
</code></pre>

<p>Obviously, the <em>correct</em> thing to do is to change your rendering path so that the styles are all placed within the correct metadata section of the document. But, if you need to, this will work across all browsers in a standards compliant way.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=52225&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/08/inline-css-the-link-cheat/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[How and why to use Lynx - the faster web browser]]></title>
		<link>https://shkspr.mobi/blog/2020/12/how-and-why-to-use-lynx-the-faster-web-browser/</link>
					<comments>https://shkspr.mobi/blog/2020/12/how-and-why-to-use-lynx-the-faster-web-browser/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 11 Dec 2020 12:34:15 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[lynx]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[web dev]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=37392</guid>

					<description><![CDATA[Lynx is a text based browser. You think the people who browse without JavaScript are weird? Lynx doesn&#039;t even do images or CSS!  It downloads HTML and renders it at blazing fast speed. If you ever wondered just how slow modern web development has made the web - Lynx will show you the meaning of haste.  I use Lynx most days. Not as my exclusive browser - I&#039;m not a masochist - but as a handy tool.…]]></description>
										<content:encoded><![CDATA[<p>Lynx is a text based browser. You think the people who browse without JavaScript are weird? Lynx doesn't even do images or CSS!</p>

<p>It downloads HTML and renders it at blazing fast speed. If you ever wondered just how slow modern web development has made the web - Lynx will show you the meaning of haste.</p>

<p>I use Lynx most days. Not as my exclusive browser - I'm not a masochist - but as a handy tool. If I'm on a bandwidth constrained connection, or a site is overloaded, or I just want to browse without distraction. Lynx is where it's at. It is also brilliant for seeing what weird markup bugs your site has.</p>

<p>Linux users can install it with <code>sudo apt install lynx</code> or similar. Everyone else can <a href="https://lynx.invisible-island.net/">download Lynx from the official website</a>.</p>

<p>This is what it looks like:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/11/Screenshot-from-2020-11-29-09-36-02-fs8.png" alt="The Google home page rendered in text." width="1026" height="711" class="aligncenter size-full wp-image-37400"></p>

<p>Using it is simple. On the command line, type <code>lynx example.com</code> to go to example.com.</p>

<p>Arrow keys up and down move you... up and down. Left goes back a page, right follows a link. Q quits. And that's all you need to know for your first five minutes.</p>

<p>Pressing the letter <code>O</code> gets you to the option screen.  There are a bunch of things you can change here - and it shows off the UI pretty well.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/12/Screenshot-from-2020-11-29-09-37-36-fs8.png" alt="Options on a screen." width="1026" height="711" class="aligncenter size-full wp-image-37402">

<p>There are some things you can't change here. If you want to <em>always</em> accept or reject cookies - rather than be prompted every time - you'll need to edit the <code>~/.lyncrc</code> file.</p>

<p>Set <code>accept_all_cookies=TRUE</code>.</p>

<h2 id="why-is-this-important"><a href="https://shkspr.mobi/blog/2020/12/how-and-why-to-use-lynx-the-faster-web-browser/#why-is-this-important">Why is this important</a></h2>

<p>Computers lie to us. CSS hides our worst sins. JavaScript covers-up our poor architectural choices. With Lynx, there's no escape. You see the HTML rendered and <em>that's it</em>. Lynx renders all the HTML5 elements:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/12/Screenshot-from-2020-11-29-10-58-22-fs8.png" alt="HTML elements rendered in different colours." width="1026" height="711" class="aligncenter size-full wp-image-37403">

<p>It also does interactive elements as well:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/12/Screenshot-from-2020-11-29-10-59-11-fs8.png" alt="Form elements." width="1026" height="711" class="aligncenter size-full wp-image-37404">

<p>I've found <em>so</em> many bugs this way. Little quirks of markup which show up in the most unexpected places.</p>

<p>To be clear, Lynx isn't about accessibility testing. You should do that with proper tools which expose ARIA, show colour contrast, and the like. But Lynx is a good first pass at seeing how the text renders and flows, whether images have alt text, and if the general structure is easy to navigate.</p>

<p>Take some time to use it on your favourite sites today.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=37392&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2020/12/how-and-why-to-use-lynx-the-faster-web-browser/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Building an "On This Day" site for your Twitter Account]]></title>
		<link>https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/</link>
					<comments>https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 18 May 2020 11:19:35 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=35047</guid>

					<description><![CDATA[I wanted to see what I was Tweeting on this exact day last year. And all the years before. So I built a website! It&#039;s a disgusting hack, and I&#039;m truly sorry for unleashing it on you.  Using the API  You can&#039;t.  The Twitter search API only goes back 7 days. This whole idea would be much easier if I had access to the Premium API.  But! The Twitter website has no such restrictions.  Advanced Search  …]]></description>
										<content:encoded><![CDATA[<p>I wanted to see what I was Tweeting on this exact day last year. And all the years before. So I built a website! It's a <em>disgusting</em> hack, and I'm truly sorry for unleashing it on you.</p>

<h2 id="using-the-api"><a href="https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#using-the-api">Using the API</a></h2>

<p>You can't.</p>

<p>The Twitter search API only goes back 7 days. This whole idea would be much easier if I had access to the Premium API.</p>

<p>But! The Twitter website has no such restrictions.</p>

<h2 id="advanced-search"><a href="https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#advanced-search">Advanced Search</a></h2>

<p>Twitter's Advanced Search allows you to pick specific dates to search for.  Here's the string which shows my username's Tweets on Christmas day 2015:
<code>search?q=from:edent (until:2015-12-26 since:2015-12-25)</code></p>

<p>So how do we embed Twitter's site on our page?</p>

<h2 id="iframes"><a href="https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#iframes">iFrames!</a></h2>

<p>Nope!</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/05/iframe-blocked.png" alt="Blocked by X-Frame-Options Policy. An error occurred during a connection to twitter.com. Firefox prevented this page from loading in this context because the page has an X-Frame-Options policy that disallows it." width="439" height="267" class="aligncenter size-full wp-image-35048">

<p>Twitter's X-Frame-Options Policy doesn't allow embedding. Oh well. Guess we have to give up.</p>

<p>HA!</p>

<h2 id="busting-makes-me-feel-good"><a href="https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#busting-makes-me-feel-good">Busting makes me feel good</a></h2>

<p>Using the <a href="https://github.com/niutech/x-frame-bypass">X-Frame Bypass Web Component</a> is a real-life cheat-code.</p>

<blockquote><p>X-Frame-Bypass is a <a href="https://www.webcomponents.org/introduction">Web Component</a>, specifically a <a href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-customized-builtin-example">Customized Built-in Element</a>, which extends an IFrame to bypass the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options"><code>X-Frame-Options: deny/sameorigin</code></a> response header. Normally such headers prevent embedding a web page in an <code>&lt;iframe&gt;</code> element, but X-Frame-Bypass is using a CORS proxy to allow this.</p></blockquote>

<p>It's dead simple to use. Stick this in your <code>&lt;head&gt;</code></p>

<pre><code class="language-html">&lt;script type="module" src="https://unpkg.com/x-frame-bypass"&gt;&lt;/script&gt;
</code></pre>

<p>Done.</p>

<h2 id="stick-it-all-together"><a href="https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/#stick-it-all-together">Stick it all together.</a></h2>

<p>I wrote some <a href="https://gitlab.com/edent/on-this-day-twitter">horrible code</a> to shove a dozen iFrames on a page.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/05/Screenshot_2020-05-11-Terence-Edens-Old-Tweets.png" alt="Several columns of Tweets. Each one from a previous year." width="1907" height="987" class="aligncenter size-full wp-image-35049">
Ta-da!</p>

<p>The frames each point to the <em>mobile</em> version of the Twitter site - that provides a single column layout. The X-Frame Bypass doesn't send a User Agent Header - which is lucky because it forces Twitter to serve up a legacy version of the site.</p>

<p>It only loads 20 Tweets per day - so you'll need to click through if you were particularly loquacious that day.</p>

<p>I can't be bothered to release this as a proper site. But if you want to - go ahead!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=35047&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2020/05/building-an-on-this-day-site-for-your-twitter-account/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[How to fake Progressive WebP Images]]></title>
		<link>https://shkspr.mobi/blog/2020/04/how-to-fake-progressive-webp-images/</link>
					<comments>https://shkspr.mobi/blog/2020/04/how-to-fake-progressive-webp-images/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 19 Apr 2020 11:21:18 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=34710</guid>

					<description><![CDATA[WebP is the hip new image format on the scene. It offers unrivalled image compression at superior visual quality. But, in my opinion, it is deficient compared to JPG in one significant aspect. It doesn&#039;t have a progressive mode.  Progressive mode is useful because it can quickly load a low resolution preview of an image, and then gradually improve its quality.  WebP, by contrast, just loads up…]]></description>
										<content:encoded><![CDATA[<p>WebP is the <a href="https://developers.google.com/speed/webp">hip new image format</a> on the scene. It offers unrivalled image compression at superior visual quality. But, in my opinion, it is deficient compared to JPG in one significant aspect. It doesn't have a progressive mode.</p>

<p>Progressive mode is useful because it can quickly load a low resolution preview of an image, and then gradually improve its quality.</p>

<p>WebP, by contrast, just loads up the full image line by line. That's can be annoying on a slow connection.</p>

<p>What if we could change that? Here's a quick-and-dirty hack.
This is a 5472x3080 image which has been compressed down to "zero" quality on WebP and resized to 640x360. It is less than 5KB.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/04/pi-0-640.webp" alt="A fuzzy photo of a Raspberry Pi circuit board." width="640" height="360" class="aligncenter size-full wp-image-34734">

<p>The <a href="https://pixabay.com/photos/raspberry-pi-raspi-electronics-3640738/">original image</a> is 400 KB as a WebP and 1.6MB as a JPG.</p>

<p>There are <a href="https://jmperezperez.com/svg-placeholders/">lots</a> of <a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video">techniques</a> to <a href="https://css-tricks.com/the-blur-up-technique-for-loading-background-images/">load low-res images before the main image loads</a>.</p>

<p>We're going old-skool. Basic HTML + CSS.</p>

<pre><code class="language-html">&lt;img
    width=5472
    height=3080
    alt="Close up of a Raspberry Pi circuit board."
    style="background-image: url('Small.webp');"
    src=Big.webp
&gt;
</code></pre>

<p>This sets the <em>background</em> of the image to the low-resolution, low quality version. As the high-resolution image loads, it gradually replaces the image in the background.</p>

<p>There are a few more refinements we could make to this:</p>

<pre><code class="language-html">&lt;img
    width=5472
    height=3080
    alt="Close up of a Raspberry Pi circuit board."
    style="background-color: #0f0;
           background-image: url('Small.webp');"
    loading="lazy"
    src=Big.webp
/&gt;
</code></pre>

<p>This sets the <code>background-color</code> to the dominant colour of the image. That way, even before the background image has loaded, you get something to fill the gap. Because we've set <code>loading="lazy"</code> the massive image won't be downloaded until the <code>img</code> scrolls into view.</p>

<p>We can even go a step further.  Let's reduce the image down to a thumbnail of 160x90. That takes us down to a ludicrously small 564 Bytes.</p>

<p><img src="https://shkspr.mobi/blog/wp-content/uploads/2020/04/pi-0-160.webp" alt="Extremely fuzzy photo." width="160" height="90" class="aligncenter size-full wp-image-34732">
Which makes it small enough to stick directly in the HTML once we encode it in Base64:</p>

<pre><code class="language-css">background-image: url("data:image/webp;base64,UklGRiwCAABXRUJQVlA4ICACAACQEwCdASqgAFoAP/3+/3+/vLYyPv+8A/A/iWYIkCfrS2sOTiSUArLU15JWpmwHGTJDQ+i/y0UfRMWET8I422NGGsABPAdIKWnTFvlfPnla/wC0DPVYABJxuECkmqWUZwViSm1vqzvPgAnG+vioXrwz0V3Zx+c/znFFJvKBpH5SceJwmAUi8+8SRjzQvyc/qv3DKe3KfEYnXA+5aEBypmacRUvrvgAA+OUzEDYgEioYgJQRm/l9OIIl60M80PJW00cW6fX1fNpB/L4udWsUF5v6gOR6fB//5/0zuirXi2Z2GoqpVh3aeUDEdVThFtQOZStD/ulvCFO54uEqPVZlD63ukgBgt5Q5KA15Nse9lu4E+4XliSgao9azVod9zUr/XELtUpd2CLSyImxIXq3rRNGthLv0jePmYvlqijrhFxgMsdVer/GmM0C6xEyTC53yBQ+aGJlg/iqxrU5uwNjGNi3Or75QpJVdWW0lEyZlOsIiRsCZ+jTXsDMmgzkB4uaiiQASLl4TIYpK587PmaLb29WRF3hxpAtjR4TPDHne3iY6aBfYZhvMo1N41AMMKe7BLZg3w8LCQ2RHRHnkhgYsdtLL2jSFFpP8JgVtwLZ/KtKa6P7VaHm7aY7aT0UWyEwXPnUbZwo5a4yuK1H+P7YJqLj8yjuKSJZACY6z+6RgRxeoSyytYvQiopOOlc4f1Mdoy2WgfE3HR6Ap5jJiPryYLQAA")
</code></pre>

<p>Of course, you don't have to go down to quite this extreme level - choose some settings which make sense for you and your media.</p>

<p>To summarise:</p>

<ol>
<li>Scale the image down</li>
<li>Reduce its quality</li>
<li>Set it as the background to the <code>img</code> element</li>
</ol>

<h2 id="endnote"><a href="https://shkspr.mobi/blog/2020/04/how-to-fake-progressive-webp-images/#endnote">Endnote</a></h2>

<p>I wasn't involved with the development of WebP - but it seems bizarre to me that it doesn't contain a "thumbnail mode". On that ½ MB photo, adding a couple of KB doesn't seem like a huge overhead.</p>

<p>Similarly, the <a href="https://netflixtechblog.com/avif-for-next-generation-image-coding-b1d75675fe4">experimental AVIF</a> also lacks progressive / thumbnail support.</p>

<p>Anyone know what the reason is?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=34710&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2020/04/how-to-fake-progressive-webp-images/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Strategies for linking to obsolete websites]]></title>
		<link>https://shkspr.mobi/blog/2020/01/strategies-for-linking-to-obsolete-websites/</link>
					<comments>https://shkspr.mobi/blog/2020/01/strategies-for-linking-to-obsolete-websites/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 31 Jan 2020 12:21:56 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[meta]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=33842</guid>

					<description><![CDATA[I&#039;ve been blogging for a long time. Over the years, I&#039;ve linked to tens of thousands of websites. Inevitably, some of those sites have gone.  Even when sites still exist, webmasters seem to have forgotten that Cool URls Don&#039;t Change.  I use the WordPress Broken Link Checker plugin. It periodically monitors the links on my site and lets me know which ones are dead.  It also offers to link to…]]></description>
										<content:encoded><![CDATA[<p>I've been blogging for a long time. Over the years, I've linked to tens of thousands of websites. Inevitably, some of those sites have gone.  Even when sites still exist, webmasters seem to have forgotten that <a href="https://www.w3.org/Provider/Style/URI">Cool URls Don't Change</a>.</p>

<p>I use the <a href="https://wordpress.org/plugins/broken-link-checker/">WordPress Broken Link Checker plugin</a>. It periodically monitors the links on my site and lets me know which ones are dead.  It also offers to link to <a href="https://web.archive.org/">Wayback Machine</a> snapshots of the page.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/01/Screenshot_2020-01-12-View-Broken-Links-‹-Terence-Eden’s-Blog-—-WordPress.png" alt="Plugin offering to fix a broken link by replacing it with an archive link." width="625" height="267" class="aligncenter size-full wp-image-33844">

<p>It doesn't always work, of course. Sometimes the page will have been taken over by spammers, and the snapshot reflects that.</p>

<p>This isn't some SEO gambit. I believe that the web works best when users can seamlessly surf between sites. Forcing them to search for information is user-hostile.</p>

<h2 id="what-im-trying-to-achieve"><a href="https://shkspr.mobi/blog/2020/01/strategies-for-linking-to-obsolete-websites/#what-im-trying-to-achieve">What I'm trying to achieve</a></h2>

<p>When a visitor clicks on a link, they should get (in order of preference):</p>

<ol>
<li>The original page</li>
<li>An archive.org view of the page

<ol>
<li>Ideally the most recent snapshot</li>
<li>If the recent snapshot doesn't contain the correct content, a snapshot of the page around the time the link was made</li>
<li>A snapshot of the site's homepage around the time the link was made</li>
</ol></li>
<li>A replacement page. For example, Topsy used to show who had Tweeted about your page. <a href="https://keyhole.co/blog/top-3-topsy-alternatives/">Apple killed Topsy</a> - so now I point to <a href="https://twitter.com/search?q=%22future%20of%20android%2C%20and%20how%20to%20stop%20it%22&amp;src=typed_query&amp;f=live">Twitter's search results for a URl</a>.</li>
<li>If there is no archive, and no replacement, and the link contains useful semantic information - leave it broken.</li>
<li>Remove the link.</li>
</ol>

<p>Some links are from people leaving comments, and setting their comments. Is it useful for future web historians to know that Blogger Profile 1234 commented on my blog <em>and</em> your blog?</p>

<p>Some links are only temporarily dead (<a href="https://hitchhikers.fandom.com/wiki/Hotblack_Desiato">for tax reasons</a>?) - so I tend to leave them broken.</p>

<p>The Internet Archive say that "<a href="https://blog.archive.org/2017/01/25/see-something-save-something/">If you see something, save something</a>". So, going forward, I'll submit every link out from my blog to the Archive. I'm hoping to find a plugin to automate that - any ideas?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=33842&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2020/01/strategies-for-linking-to-obsolete-websites/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[No Javascript Day]]></title>
		<link>https://shkspr.mobi/blog/2013/11/no-javascript-day/</link>
					<comments>https://shkspr.mobi/blog/2013/11/no-javascript-day/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 08 Nov 2013 12:00:47 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[NaBloPoMo]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=8860</guid>

					<description><![CDATA[I&#039;d like to propose that web designers around the world spend one day this year browsing the web with JavaScript disabled.  I&#039;m tentatively calling this &#34;International No Javascript UseR Experience Day&#34; or INJURED for short.  A few weeks ago, a reader of my blog complained that all they saw was a blank screen. As Liz Conlan pointed out, my CSS was making the whole page invisible.  My WordPress…]]></description>
										<content:encoded><![CDATA[<p>I'd like to propose that web designers around the world spend one day this year browsing the web with JavaScript disabled.</p>

<p>I'm tentatively calling this "International No Javascript UseR Experience Day" or INJURED for short.</p>

<p>A few weeks ago, a reader of my blog <a href="https://news.ycombinator.com/item?id=6604555">complained that all they saw was a blank screen</a>. As <a href="https://twitter.com/lizconlan/status/393348112963883008">Liz Conlan pointed out</a>, my CSS was making the whole page invisible.  My WordPress theme has a feature which renders the page blank until all the extra fonts etc have properly loaded - then it makes the page visible.  That's a neat little hack to stop the page jumping around as it loads - but it fails utterly when the user doesn't have JavaScript.</p>

<h2 id="why-do-this"><a href="https://shkspr.mobi/blog/2013/11/no-javascript-day/#why-do-this">Why Do This?</a></h2>

<p>Firstly, let's ask <strong>how many</strong> people browse the web without JS.</p>

<p>According to this <a href="http://digital.cabinetoffice.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/">recent post by the UK Government's web team</a>, approximately 1.1% of their visitors don't or can't use JavaScript.
<a href="http://digital.cabinetoffice.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/"><img src="https://shkspr.mobi/blog/wp-content/uploads/2013/10/No-JavaScript-fs8.png" alt="No JavaScript-fs8" width="525" height="241" class="aligncenter size-full wp-image-8864"></a></p>

<p>That's a small fraction of visitors - but not an insignificant number of people to piss off if you run a major website.</p>

<p>Secondly, <em>why</em> don't people use JavaScript?  There are a variety of reasons, most of which seem to fall into the following categories:</p>

<ul>
    <li>Security. Why run untrusted code on your computer if not strictly necessary?</li>
    <li>Speed. On slower machines, or those with limited bandwidth, JavaScript can cause a page to render slowly.</li>
    <li>Privacy. JavaScript is often used to track users.</li>
    <li>Accessibility. Not all users have perfect vision or dexterity - JavaScript can be an annoyance, assuming their accessible browser supports it at all.</li>
    <li>Incompatible browser. As well as specialised browsers, many people still run outdated versions of popular web browsers.</li>
    <li>Network interference. Some ISPs and corporate networks will automatically degrade or disable JavaScript.</li>
</ul>

<p>So, we have a bunch of customers / users who either can't or won't use JavaScript.  Should we ignore them?</p>

<h2 id="how-the-other-half-live"><a href="https://shkspr.mobi/blog/2013/11/no-javascript-day/#how-the-other-half-live">How The Other Half Live</a></h2>

<p>I think it's important to see how our technology works when presented in less-than-ideal circumstances.  If an astronaut on the ISS wants to load your website on their IE6 box running over slow link with huge ping times, what's their experience going to be?</p>

<p>I quite often use <a href="http://lynx.isc.org/current/">Lynx to browse the web</a>.  It's a text only browser with very few bells and whistles.  Here's how it looks when trying to use Twitter.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/10/Lynx-Twitter-fs8.png" alt="Lynx Twitter-fs8" width="722" height="457" class="aligncenter size-full wp-image-8865">
I use Lynx for 4 main reasons:</p>

<ol>
    <li>How does my layout work for those who use Text-To-Speech to browse the web? It's not perfect, but I can see how easy it is to navigate, whether I've used alt/title tags for images correctly.</li>
    <li>When on a painfully slow connection. We've all be stuck somewhere with Internet speeds barely better than dial-up, right? With Lynx I'm not loading MBs of JS, CSS, images, Flash objects, HTML5 video.  Just the information I want.</li>
    <li>What does a search engine see?  When a spider comes crawling, how much semantic meaning do they derive from my markup?</li>
    <li>Does basic functionality work for the lowest common denominator.</li>
</ol>

<p>It's amazing how quick the web when you're ignoring everything other than the HTML!  Moreso, it's incredible how even some simple sites won't work without JavaScript.</p>

<p>I'm not proposing that we go back to a text-only existence, nor that we all disable JavaScript permanently.  Merely that - once in a while - we experience the web without our favourite toy.  Do our sites break catastrophically? Is there a more accessible way we can provide a feature?</p>

<p>I'm not proposing to make a website, logo, or define a specific day.  I'd just like you to turn off JavaScript for a day and see if anything odd happens.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=8860&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2013/11/no-javascript-day/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
