SEO Crawlability Issue: Resources are formatted as page link

on in JavaScript DOM, SEO
Last modified on

While working on a Semrush audit, I found a new type of crawlability notice:

47 resources are formatted as page link

According to their documentation, “we detected that some links to resources are formatted with <a href> HTML element. An <a> tag with a href attribute is used to link to other webpages and must only contain a page URL. Search engines will crawl your site from page to page by following these HTML page links. When following a page link that contains a resource, for example, an image, the returned page will not contain anything except an image. This may confuse search engines and will indicate that your site has poor architecture.”

Semrush Site Audit

Again, according to their documentation, this is how to fix it:

“Review your links. Replace <a href> links with tags necessary for specific resources. For example, if you’d like to add an image, use an <img> tag with an alt attribute describing the contents of your image.”

Semrush Site Audit

Now, the pages I’m getting this notice for are all using the same template, and that includes a carousel with off-site (Amazon S3, Google Cloud, Azure) images. As I don’t want to lose the “click to see a larger image” functionality, I decided to remove the <a> links and use a tiny snippet of JavaScript code. An alternative would be a lightbox script, but most of them still use an <a> element.

Here’s the image element:

<img data-enlargeable width="100" style="cursor: zoom-in" src="https://images.unsplash.com/photo-1678395319602-4b2804bdac91?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80">

Note how I’m setting a smaller size (to fit into my container) and I also use an inline style to set a custom cursor.

And here’s the JavaScript code:

document.querySelectorAll("img[data-enlargeable]").forEach((img) => {
    img.classList.add("img-enlargeable");
    img.addEventListener("click", () => {
        const src = img.getAttribute("src");
        let modal;

        const removeModal = () => {
            modal.remove();
            document.body.removeEventListener("keyup", handleKeyup);
        };

        const handleKeyup = (e) => {
            if (e.key === "Escape") {
                removeModal();
            }
        };

        modal = document.createElement("div");
        modal.style.background = `rgba(0,0,0,.5) url(${src}) no-repeat center`;
        modal.style.backgroundSize = "contain";
        modal.style.width = "100%";
        modal.style.height = "100%";
        modal.style.position = "fixed";
        modal.style.zIndex = "10000";
        modal.style.top = "0";
        modal.style.left = "0";
        modal.style.cursor = "zoom-out";
        modal.addEventListener("click", removeModal);
        document.body.appendChild(modal);


        document.body.addEventListener("keyup", handleKeyup);
    });
});

See an awesome demo here.

The JavaScript is small enough to be inlined (652 bytes), especially when minified and compressed:

<script>document.querySelectorAll("img[data-enlargeable]").forEach((e=>{e.classList.add("img-enlargeable"),e.addEventListener("click",(()=>{const t=e.getAttribute("src");let n;const d=()=>{n.remove(),document.body.removeEventListener("keyup",o)},o=e=>{"Escape"===e.key&&d()};n=document.createElement("div"),n.style.background=`rgba(0,0,0,.5) url(${t}) no-repeat center`,n.style.backgroundSize="contain",n.style.width="100%",n.style.height="100%",n.style.position="fixed",n.style.zIndex="10000",n.style.top="0",n.style.left="0",n.style.cursor="zoom-out",n.addEventListener("click",d),document.body.appendChild(n),document.body.addEventListener("keyup",o)}))}));</script>

The usage is simple, after inlining the JavaScript, just edit the images and add a data-enlargeable attribute:

<img data-enlargeable width="100" style="cursor: zoom-in" src="path/to/image.jpg" alt="">

The script can be amended to add image captions and to specify different URLs for the thumbnail and the large image. I won’t go into these details, as the code above solved my crawlability issue without sacrificing the user experience.

Related posts