As part of an audit I wanted to fetch the highest quality favicon for every page that we check. It turned out to be slightly more complicated than I thought:
These stackoverflow posts suggest a few ways to get the favicon, but they all share a few issues:
It depends on a 3rd party (eg Google)
It ignores the default
/favicon.ico
, or uses it incorrectlyIt returns the first favicon, instead of the largest one
How the browser chooses a favicon
The standard way to include a favicon is with a link tag <link rel="icon"..
You can use multiple link tags to specify different sizes, for example:
<link rel="icon" sizes="16x16" href="/favicon_16.png">
<link rel="icon" sizes="32x32" href="/favicon_32.png">
Another popular variant is <link rel="shortcut icon"..
<link rel="shortcut icon" href="/favicon_32.png">
If none of these tags are present the browser will make a request to the /favicon.ico
file at the root directory. Some servers are badly configured though and will return an 200 OK
status even if the file is not present, so to be sure you have to check that the file is indeed an image.
The solution
The following codes combines all these factors, and loops through the available favicons to return the largest one.
// Get the largest favicon in the current document, or false if none is found.
let getLargestFavicon = async () => {
let getSize = el => {
return (el.sizes[0] && parseInt(el.sizes[0], 10)) || 0;
};
let favicons = [
...document.querySelectorAll('link[rel="shortcut icon"],link[rel="icon"]')
].sort((a, b) => {
return getSize(b) - getSize(a);
});
if (favicons.length > 0) {
return favicons[0].href;
}
// no favicon is specified in the meta tags, lets try the default /favicon.ico
let defaultLocation = document.location.origin + "/favicon.ico";
let r = await fetch(defaultLocation);
if (r.ok) {
let t = await r.blob();
if (t.type.indexOf("image") !== -1) {
return defaultLocation;
}
}
return false;
};
Originally published at https://blog.pagewatch.dev/post/finding-the-largest-favicon-with-js
Top comments (0)