Hi there!
How can I create an external link that navigates to a specific section of a single-page site?
For example, similar to how a standard anchor works.
It is necessary for this link to work when connected to a QR code.
Thank you, but I have the opposite situation: I need an external link that leads to a specific anchor on my page.
For example, as it is done with a standard anchor (see the attachment).
While solving this issue, two problems were identified:
- The problem is that when the page loads, the hash
site.com/#Schoolyard
is reset, and the full URL of the page is lost, so the anchor cannot work. - The anchor needs to be created by a script after the page has fully loaded. The script must be executed at the very last stage of loading, after all others.
Script that restores the hash (URL):
Place this at the beginning inside the <head>
tag:
<head>
<script>
(function() {
// Save the original hash
var originalHash = window.location.hash;
// Function to restore the hash
function restoreHash() {
if (window.location.hash !== originalHash) {
//console.log('Restoring hash:', originalHash);
window.location.hash = originalHash;
}
}
// Override the history API methods
var originalPushState = history.pushState;
history.pushState = function(state, title, url) {
var result = originalPushState.apply(this, arguments);
restoreHash();
return result;
};
var originalReplaceState = history.replaceState;
history.replaceState = function(state, title, url) {
var result = originalReplaceState.apply(this, arguments);
restoreHash();
return result;
};
// Monitor hash changes
window.addEventListener('hashchange', function() {
//console.log('Hash changed to:', window.location.hash);
restoreHash();
});
// Restore the hash after the page loads
window.addEventListener('load', function() {
setTimeout(restoreHash, 0);
});
})();
</script>
</head>
Script that performs substitution based on aria-label
:
This uses the ALT-TEXT of an element; for example, I placed an image outside the visible area located above the desired place on the page.
Now, in the script, it’s sufficient to place an array of aria-label
correspondences to the final link.
The script smoothly moves focus to the anchor. But since the site’s content doesn’t load immediately, there’s a slight delay. If there’s animation on the page, there will be jerking during scrolling, so it’s better to replace 'smooth'
with 'auto'
.
To disable logging, simply comment out all lines starting with console.log
using //
.
Place this at the end, before </body>
:
<body>
<!-- Your page content -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const replacements = {
'aria-label1': 'aria-label1',
'aria-label2': 'aria-label2',
'aria-label3': 'aria-label3',
// Add additional correspondences as needed
};
function updateElements() {
//console.log("Starting to update elements with aria-label...");
const elements = document.querySelectorAll('[aria-label]');
//console.log(`Found elements with aria-label attribute: ${elements.length}`);
elements.forEach(element => {
const dataIdValue = element.getAttribute('aria-label');
// Check if there is a replacement for this aria-label
if (replacements[dataIdValue]) {
element.id = replacements[dataIdValue];
//console.log(`Element with aria-label="${dataIdValue}" received id="${element.id}"`);
}
});
}
function scrollToAnchor() {
const hash = window.location.hash;
if (hash) {
const targetId = hash.substring(1); // Remove the '#' symbol
const targetElement = document.getElementById(targetId);
if (targetElement) {
//console.log(`Scrolling to element with id="${targetId}"`);
targetElement.scrollIntoView({ behavior: 'smooth' });
} else {
//console.log(`Element with id="${targetId}" not found`);
}
} else {
//console.log("No anchor present in the URL");
}
}
// Initially update elements and try to scroll to anchor
updateElements();
scrollToAnchor();
// Create a MutationObserver to track changes in the DOM
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach(mutation => {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
//console.log("New nodes detected in DOM, updating elements...");
updateElements();
scrollToAnchor();
}
});
});
// Start observing the entire document
observer.observe(document.body, { childList: true, subtree: true });
//console.log("Started observing changes in the DOM");
});
</script>
</body>
Notes:
- To enable logging, uncomment all lines starting with
console.log
by delete//
at the beginning of each line. - Regarding smooth scrolling: If you experience jerky scrolling due to animations or delayed content loading, you might want to replace
{ behavior: 'smooth' }
with{ behavior: 'auto' }
in thescrollIntoView
method:
targetElement.scrollIntoView({ behavior: 'auto' });
- About the
replacements
object: This object mapsaria-label
values toid
values. You can add as many correspondences as you need. - Placement of scripts:
- Hash restoration script: Place it inside the
<head>
tag at the beginning of your HTML document. - Main script: Place it just before the closing
</body>
tag to ensure it runs after all content has been loaded.
- Hash restoration script: Place it inside the
By implementing these scripts, you address both problems:
- Hash Preservation: The first script ensures that the hash in the URL is preserved throughout page loads and navigation, allowing anchor links to function correctly.
- Anchor Creation After Page Load: The second script assigns
id
attributes to elements based on theiraria-label
after the DOM content is fully loaded. It then attempts to scroll to the anchor specified in the URL.
Example Usage:
In your replacements
object, you can define:
const replacements = {
'section1': 'section1',
'section2': 'section2',
// Add more as needed
};
This script will assign the id
attribute to each element based on its aria-label
, allowing you to use anchor links like yourpage.html#section1
.
Remember:
- The MutationObserver ensures that any new elements added to the DOM after initial load are also processed.
- Make sure that the elements you want to scroll to are available in the DOM and have the appropriate
aria-label
attributes. - Test the scripts thoroughly in your environment to ensure they work as expected.