I made a Chrome plug-in before , which can generate different icons according to different addresses. This can easily distinguish different development environments. The effect is as follows
The main implementation process is actually not complicated. First, obtain the website favicon, then add a logo to the favicon, and redraw it to generate it.
Among them, the icons here are generated through SVG. Let’s take a look at the specific implementation.
Contents
1. How to obtain favicon
If you want to know how to get it, you can first understand how to set it up.
There are generally two ways to set up a website favicon
.
The first one link
is set through tags (requires rel="icon"
attributes)
< link rel = "icon" href = "xxx.png" >
The second one is to put one directly in the root directory of the websitefavicon.ico
(it must be this name, the default of the browser), and there is no need to set anything in the html.
- Website directory index. html favicon. ico
If none of the above are set, you will most likely see the following error
After understanding these, obtaining is simple. First link
obtain it, as long as it is rel
included .icon
const link = document . querySelector ( 'link[rel~="icon"]' );
If you can’t find it, you can request it /favicon.ico
and add one directly here.link
function getLink (){ const link = document . querySelector ( 'link[rel~="icon"]' ); if (link) { return link } else { const link = document . createElement ( 'link' ); link.rel = "icon " ; link. href = "/favicon.ico" document . head . append (link); return link } }
What is obtained in this way link
is guaranteed to exist, and then it is drawn
2. Draw using canvas
Since the image needs to be synthesized, the original image needs to be drawn first. When it comes to image drawing, you can think of canvas drawing, and only a little basic knowledge of canvas is enough. The specific implementation is as follows
const canvas = document . createElement ( 'canvas' ), ctx = canvas.getContext ( ' 2d' ), img = new Image (); img. crossOrigin = 'anonymous' ; img. onload = () => { canvas.height = img.height ; canvas.width = img.width ; ctx. drawImage (img, 0 , 0 , canvas. width , canvas. height ); let dataURL = canvas. toDataURL ( "image/png" ); resolve (dataURL); canvas = null ; }; img.src = url;
Since there is /favicon.ico
no setting, a default image needs to be given when the img fails to load.
img. onerror = () => { resolve ( "Default image base64" ); }
In this way, the image information of the favicon can be obtained.
3. Use SVG for image synthesis
On the basis of the above, you can actually continue to draw through canvas, and it is not difficult to draw another label. However, SVG can be used to draw here, which has the following advantages:
- Lower cost and easier to understand than canvas
- High flexibility, some style control can be done through CSS
First of all, we can freely draw such a layout in HTML like normal web development. I believe it is not difficult.
< body > < strong > local </ strong > < img src = 'xxx.png' > </ body >
Since the width is limited, it is necessary to force the text to wrap and hide beyond it. The key styles are as follows
strong { position : absolute; bottom : 0 ; left : 50% ; transform : translateX (- 50% ); text-transform : uppercase; background-color : orange; color : #fff ; padding : 0px 2px ; border-radius : 2px ; font-size : 12px ; box-sizing : border-box; max-width : 100% ; width : max-content; height : 16px ; line-height : 16px ; word-break : break-all; overflow : hidden ; }
Then, put this piece of html into foreignObject
a tag. Regarding the role of foreignObject , those who are interested can refer to this article by Zhang Xinxu. SVG introduction and screenshots and other applications . Here, you can simply understand that it is a tag that can contain HTML, and SVG itself is also a kind of picture, thus achieving the purpose of synthesizing images.
The specific implementation is as follows
const link = getLink (); const icon = await img2Base64 (link. href ); const favicon = `data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org /2000/svg" width="32" height="32"><foreignObject x="0" y="0" width="100%" height="100%"><body xmlns="http:// www.w3.org/1999/xhtml"> <style> html,body{ height: 100%; margin: 0; text-align: center; } img{ display: block; width: 100%; height: 100%; object-fit: contain; } strong{ position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); text-transform: uppercase; background-color: ${color} ; color: #fff; padding: 0px 2px; border-radius: 2px; font-size: 12px; box-sizing: border-box; max-width: 100%; width: max-content; height: 16px; line-height: 16px; word-break: break-all; overflow: hidden; } </style> <strong>local</strong> <img src=' ${icon} '></img> </body></foreignObject></svg>` . replace ( /\n/g , '' ). replace ( /\t/g , '' ). replace ( /#/g , '%23' )
Several points need to be noted here
- The img tag needs to be written in a closed form in svg
<img></img>
, otherwise it will be considered a structural error. - img can only use inline images, such as base64, which is why the original favicon is drawn
- If you use inline svg, you need to escape the svg
- You also need to pay attention to the issue of single and double quotation marks in strings.
Then, set the generated SVG directly to the favicon
link.href = favicon;
This way you can render normally~
For complete implementation, please refer to the project: https://github.com/XboxYan/auto-dev-favicon-chrome-plugin
4. Some limitations
The first is compatibility.
Currently only Chrome and Firefox are supported. In order to be compatible with other browsers, you can use one .ico
to check the details.
< link rel = "icon" href = "/favicon.ico" sizes = "any" > < link rel = "icon" href = "/favicon.svg" type = "image/svg+xml" >
In addition, there is a limitation on Chrome (I don’t know if it is a limitation after Chrome is updated). When the favicon uses svg format images, the svg at this time will be in a secure-static-mode . In this mode, all The animation will not be executed and will be in the first frame, such as the following example
< svg xmlns = "http://www.w3.org/2000/svg" width = "100%" height = "100%" > < foreignObject width = "100%" height = "100%" > < body xmlns = "http://www.w3.org/1999/xhtml" > < style > html , body { margin : 0 ; height : 100% } div { height : 100% ; background : pink; animation : hue 3s infinite; } @keyframes hue { to { filter : hue-rotate ( 360deg ) } } </ style > < div > </ div > </ body > </ foreignObject > </ svg >
A very simple background color animation. On Firefox, it is used as a favicon and has animations.
However, it doesn’t work on Chrome, only the first frame is disabled
So if you want to achieve the scrolling effect of logo text before, you can stop here😭
Similar to media query, I have seen such an implementation on the Internet before, which implements dark mode directly in SVG.
< svg width = "128" height = "128" viewBox = "0 0 128 128" fill = "none" xmlns = "http://www.w3.org/2000/svg" > < style > path { fill: #fff ; } rect { fill: #B09AFE ; } @media ( prefers-color-scheme : dark) { path { fill: #B09AFE ; } rect { fill: #fff ; } } </ style > < rect width = "128" height = "128" rx = "64" fill = "#B09AFE" /> < path d = "M32.375 37.5714H22C22 58.004 38.2596 74.5714 58.3125 74.5714V98.3571C58.3125 9 9.8107 59.4797 101 60.9062 101H66.0937C67.5203 101 68.6875 99.8107 68.6875 98.3571V74.5714C68.6875 54.1388 52.4279 37.5714 32.375 37.5714ZM94.625 27C80.9754 27 69.109 34.6808 62.9002 46.0286C67.3906 51.017 70.7139 57.079 72.4646 63.8018C90.7344 61.8692 105 46.1442 105 27H94 .625Z" fill = "white" /> </ svg >
But it’s the same problem. It only works under Firefox, but Chrome is still.
In general, SVG provides endless possibilities in drawing, not just the cases in this article. Anyone who thinks canvas is too complicated can consider this solution.