Latest Posts

Wednesday, 6 May 2026

Update to the Griffmonsters GPX Route Creator

Having spent 11 days exploring the Greek island of Crete, the Griffmonster GPX Route Creator tool came in very handy. This made it so easy, having learnt of new places and features to visit whilst based in the village of Piskopiano, to craft a route to walk to the feature we had been told about. This was the first time that we used the tool in anger and it proved to be easy to just create the route, download the plotted GPX, and then pull it into our navigation app, this currently being the OruxMaps.

However, there was one niggling issue that was found when plotting the route on a mobile device. When changing the screen map by clicking the right hand layers box, it was found that the top of the map layers container became hidden underneath the location bar, completely obscuring the default map selection. It was easy enough to work around but very annoying. Consequently, an improvement needed to be made once we returned from our Greek walking expeditions.

To accommodate the maps in the layer container, some css adjustments will now hide the location bar, returning it when closing the layers bar by clicking elsewhere on the page. This functionality is specific to screen sizes up to a maximum of 600px width. A few other css changes have also been made to the location bar, and this now works better for all screen sizes.

Screenshot of the Griffmonster GPX Route Creator tool as displayed on a mobile device
Screenshot of the Griffmonster GPX Route Creator tool as displayed on a mobile device
Elephant at sunset
Screenshot of the Griffmonster GPX Route Creator tool with the map layers expanded on a mobile device

The Griffmonsters GPX Route Creator tool version has now been increased to v0.52

This has been updated for both the Griffmonsters Great Walks and the Rhodes Great Walks websites.

Tuesday, 21 April 2026

Links, Dead Links and Missing Resources

We at Griffmonsters Great Walks make extensive use of the humble HTML anchor element to link to external resources. These links provide additional information and context for each walk, as well as references for facts and historical details mentioned on the site.

However, external websites are often transient by nature. A valuable resource may be available one day, then disappear a month, a year, or a decade later. In the best-case scenario, a 301 HTTP response redirects to an updated URI. In many cases, though, links instead return a 404 response, or worse, a 5XX server error.

This has naturally led to regular checks of linked resources using both online tools and open-source software. Traditionally, this has been a time-consuming and labour-intensive task, usually carried out during the winter months when short daylight hours and poor weather make walking less practical.

This year, however, the process has improved considerably. A custom Python script was created to process a generated list of all pages and validate their links. This proved that some previously used methods were missing a significant number of broken pages and links.

In addition to this full-site testing, a batch script is now generated in the build pipeline. It takes the source data and transforms it into blog HTML while also extracting a list of external URIs. These are then tested using Curl, with the results written to a text report. This allows targeted testing whenever a new walk is added or an older page is updated.

This year’s results have been particularly thorny, with a great deal of time spent finding suitable replacements for missing resources. Fortunately, in many cases, the Archive.org Wayback Machine has been able to provide archived copies of missing pages.

That is not always possible. Academic websites and commercial organisations — especially those hosting PDF documents — are often not archived reliably. In these cases, documents may have moved to a new URI without redirection, been removed entirely, or been superseded by newer material. This is especially problematic when walk notes rely on quoted or referenced material from those sources.

Another area affected by dead links are pubs. In recent years, many have closed permanently or been converted into housing or other uses. The scale of closures is substantial and surprising. In these cases, archived pub websites are often of limited practical value, though they may still hold historical interest. Where relevant, notes have been added to indicate closures, and links to CAMRA pages are included where pub history information is available.

Transport links are similarly transient. Routes are withdrawn, services change, and operators come and go. For anyone planning a walk from the site, the best option is to consult Traveline directly. Transport information on individual walk pages should therefore be treated primarily as historical reference material. More improvements in this area may follow.

In conclusion, the Griffmonsters Great Walks site has now been updated, and most links should be functioning correctly apart from a small number of archived pages that still require manual attention. Rhodes Great Walks is next in line for validation, though it is expected to contain fewer dead links overall.

Tuesday, 31 March 2026

Addressing Cumulative Layout Shift (CLS)

Addressing Cumulative Layout Shift (CLS)

In recent weeks I’ve been investigating issues highlighted by Chrome’s Lighthouse tool relating to Cumulative Layout Shift (CLS). This post explains what CLS is, why it matters, and how I resolved it across a large image-heavy site.

What is CLS?

CLS occurs when elements on a webpage move unexpectedly while the page is loading. A common example is when you try to click a button, only for the page to shift at the last moment— resulting in clicking something else entirely.

This is more than just a minor annoyance; it directly impacts usability and is now a key metric in Google’s Core Web Vitals.

CLS infographic showing layout shift before and after
A visual overview of how layout shifts occur and how to prevent them.

Why is this happening?

The primary cause of CLS on the Griffmonster Walks sites turned out to be images without defined dimensions.

When a browser encounters an image without width and height attributes, it has no way of knowing how much space to reserve during the initial page layout.

  • The browser renders the surrounding text first
  • No space is reserved for the image
  • The image loads later
  • The layout shifts to accommodate it

The Key Fix: Defining Image Dimensions

Modern browsers use width and height attributes not as styling, but as intrinsic size metadata. These values allow the browser to calculate the image’s aspect ratio before the image has even downloaded.

Before (No Dimensions)

Heading
READ MORE

After (With Dimensions)

Heading
READ MORE

Without dimensions

<img src="image.jpg">

This results in no reserved space and visible layout shift.

With dimensions

<img src="image.jpg" width="800" height="600">

The browser now knows the aspect ratio and reserves space immediately, preventing layout shift entirely.

HTML vs CSS: Clearing Up the Confusion

At first, adding dimensions directly into HTML may feel like mixing structure and styling. However, these attributes serve a different purpose:

  • HTML attributes define intrinsic dimensions (aspect ratio)
  • CSS controls how the image is displayed
<img src="image.jpg" width="800" height="600" class="responsive">

.responsive {
  width: 100%;
  height: auto;
}

In this setup, CSS controls the final size, while HTML prevents layout shift.

Other Causes of CLS

While images were the main issue here, CLS can also be caused by:

  • Ads or embedded content loading late
  • Web fonts changing text layout
  • Content injected dynamically above existing elements
  • Third-party scripts modifying the page

Automating the Fix

With thousands of images across the site, manually adding dimensions wasn’t realistic. Instead, I built an automated pipeline using XSLT and Node.js.

The process

  1. Extract all image URLs from the generated HTML using XSLT
  2. Process the URLs with a Node.js script to fetch image dimensions
  3. Store the results in an XML configuration file
  4. Use a second XSLT to inject width and height attributes back into the HTML
  5. Redeploy the updated site via the Google API

Unexpected benefits

This process also exposed a number of issues that had gone unnoticed:

  • Broken image URLs (404 errors)
  • Typos in image paths
  • Images hosted on unsupported external domains

Improving Image Loading

In addition to fixing layout shift, I improved loading behaviour using the loading attribute:

<img loading="lazy">

This defers loading of images until they are needed (i.e. when they enter the viewport).

Important exception

The main image at the top of each page was excluded from lazy loading:

<img loading="eager" fetchpriority="high">

This ensures critical content loads as quickly as possible and avoids negatively impacting Largest Contentful Paint (LCP).

Responsive Images

To further optimise performance, I implemented responsive images using srcset and sizes.

<img 
  src="image-800.jpg"
  srcset="
    image-400.jpg 400w,
    image-600.jpg 600w,
    image-800.jpg 800w"
  sizes="(max-width: 450px) 400px, (max-width: 800px) 600px, 800px"
  width="800"
  height="600"
  loading="lazy"
  alt="Example image">

This allows the browser to select the most appropriate image size for the device, reducing bandwidth usage and improving load times.

Integrating the Updates into the Workflow

The workflow was adjusted to included this process such that all future deployments will include the changes.

Final Thoughts

By ensuring all images include intrinsic dimensions and improving loading behaviour, CLS issues across the site were significantly reduced.

The key takeaway is simple:

Providing intrinsic size information allows the browser to stabilise layout during initial rendering.

It’s a relatively small change with a significant impact on both performance metrics and real-world user experience.

Friday, 13 March 2026

Leafletjs issue with elevation toggle button

Both the Rhodes Great Walks and Griffmonsters Great Walks sites make ample use of the Raruto Leaflet elevation plugin. This works very well and provides a graphic interface of the elevation of the gpx route, as seen in the image above. However, there has been a persistent niggling bug with the top right toggle switch which collapses/expands the elevation panel. After the page initally loads, upon clicking the toggle switch for the first time results in nothing happening and a second click is required to collapse the panel. The toggle button then works fine on subsequent clicks.

When trying to resolve the issue it was noticed that right clicking on the toggle button to bring up the developer panel in chrome resulted in the panel collapsing. That observation provided the "smoking gun" of the cause of the issue. It proves that the plugin is listening for focus, context menus, or window/container blur events to determine its state, rather than just a simple click. When you right-click, the browser shifts focus and triggers a "re-render" or a "state check" in Leaflet. The plugin realizes, "Oh, I'm supposed to be expanded (or collapsed)," and it snaps into position. This is why your first click does nothing—the plugin is essentially "asleep" until an external event (like a right-click or a second click) wakes it up.

The following function provided the solution.

  • Focusing: By calling btn.focus(), we mimic the part of the right-click that tells the browser "this element is now active."
  • Event Dispatching: Many Leaflet plugins don't just listen for click; they listen for the mousedown/mouseup sequence. By firing those manually, we clear the "waiting" state of the plugin.
  • The Result: When the user finally performs their "first" click, the plugin already thinks it has been interacted with, so it responds immediately.
// this will force the toggle button to work on page load
controlElevation.on('eledata_loaded', function() {
    // 1. Find the toggle button
    var btn = document.querySelector('.elevation-toggle-icon');
    
    if (btn) {
        // 2. Simulate the "Focus/Wake" behavior when right-clicking
        btn.focus();
        
        // 3. Dispatch a fake "initial" click that the plugin expects
        // but we do it so fast the user doesn't see it.
        // This 'primes' the toggle logic.
        btn.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}));
        btn.dispatchEvent(new MouseEvent('mouseup', {bubbles: true}));
        
        // 4. Force the internal variable to match the VISUAL reality
        // Since it's visible on load, we tell it it's NOT collapsed.
        controlElevation._collapsed = false;

	// The Fix: Force the plugin to initialize its expanded state logic
    if (typeof controlElevation._expand === "function") {
        controlElevation._expand();
        
        // Ensure the internal state is synced so the next click is a 'collapse'
        controlElevation._collapsed = false; 
    }

    // Final layout refresh
    setTimeout(function() {
        if (typeof map !== 'undefined') map.invalidateSize();
    }, 100);


     // 5. Trigger a fake resize to make sure the internal 'brain' is active
      window.dispatchEvent(new Event('resize'));
    }
});

Thursday, 12 March 2026

Distance and Terrain Information

More development tweaks now rolled out. When using the location and collection searches, lozenges indicating both distance and terrain will display at the top of each walk card in the results. This is not available on the default blogger label searches.

A key is provided for the various distances and terrains legends, this is availble from an information button that sits to the right of the lozenges

This has also been implemented into the map markers

For those who want to see this in practice, go to All Walks Search

Tuesday, 3 March 2026