12
头图
Welcome to my public account: front-end detective

I made a Chrome plug-in before, which can generate different icons according to different addresses, which can easily distinguish different development environments. The effect is as follows

image-20220507151813352

The main implementation process is actually not complicated. First, get the website favicon, then add a logo to the favicon, and redraw the generation.

image-20220515170432251

Among them, the icons here are generated by SVG, let's take a look at the specific implementation.

1. How to get 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 the website favicon .

The first one is set by the link tag (requires rel="icon" attribute)

 <link rel="icon" href="xxx.png">

The second is to put a favicon.ico directly in the root directory of the website (must be this name, the browser defaults), nothing in html needs to be set

 - 网站目录
    index.html
    favicon.ico

If none of the above are set, you will most likely see the following errors

image-20220515115822814

Knowing these, the acquisition is simple, first get it through link , as long as rel include icon

 const link = document.querySelector('link[rel~="icon"]');

If you can't find it, you can request /favicon.ico , and add a 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
    }
}

Obtained in this way link is guaranteed to exist, and then draws

2. Drawing using canvas

Since the image needs to be composited, the original image needs to be drawn first. When it comes to image drawing, you can think of canvas drawing, and only a little canvas basic knowledge 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 a situation where /favicon.ico is not set, it is necessary to give a default image when img fails to load

 img.onerror = () => {
    resolve("默认图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, in fact, you can continue to draw through canvas, and it is not difficult to draw a label. However, SVG can be used to draw here, which has the following advantages

  1. Lower cost and easier to understand than canvas
  2. High flexibility, some style control through CSS

First of all, we can draw such a layout freely in HTML, just like normal web development, I believe there is no difficulty

image-20220515162514000

 <body>
  <strong>local</strong>
  <img src='xxx.png'>
</body>

Due to the limited width, it is necessary to force the text to wrap, beyond the hidden, 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;
}

Next, put this piece of html into the foreignObject tag. For the role of foreignObject , you can refer to this article by Mr. Zhang Xinxu, SVG introduction and screenshots, and other applications . Here, you can simply understand that it is HTML tags can be included, and SVG itself is also a kind of image, which achieves the purpose of synthesizing images

img

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')

A few things to note here

  1. The img tag needs to be written as <img></img> closed form in svg, otherwise it will be considered as a structural error
  2. img can only use inline images, such as base64, which is why the original favicon is drawn
  3. If you use inline svg, you need to escape the svg
  4. The problem of single and double quotation marks in strings also needs to be paid attention to

Then, set the resulting SVG directly as a favicon

 link.href= favicon;

image-20220515171925842

This will render it normally~

The complete implementation can 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 get the bottom line

 <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's update), 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, it 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 is used as a favicon is animated

Kapture 2022-05-15 at 19.08.20.gif

However, it doesn't work on Chrome, only the first frame is forbidden

image-20220515191044404

So before I want to achieve the effect of scrolling the logo text, I can stop here 😭

Similar to media queries, I saw such an implementation on the Internet before, and the dark mode is directly implemented 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 99.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, only works under Firefox, Chrome is static

Kapture 2022-05-15 at 19.18.39

In general, SVG provides infinite possibilities for drawing, not just the case in this article. Anyone who thinks canvas is too complicated can consider this solution

Finally, if you think it's good and helpful to you, please like, bookmark, and forward ❤❤❤

Welcome to my public account: front-end detective

XboxYan
18.1k 声望14.1k 粉丝