新聞中心
之前做了一個 Chrome 插件,可以用于區(qū)分不同的開發(fā)環(huán)境,效果如下:

主要實現(xiàn)過程其實不復(fù)雜,首先獲取網(wǎng)站 favicon,然后給 favicon 添加標(biāo)識,重新繪制生成就行了。
其中,這里的圖標(biāo)就是通過 SVG 生成的,下面看看具體實現(xiàn)吧。
一、favicon 的獲取方式
想知道獲取方式,可以先了解設(shè)置方式。
一般有兩種方式可以設(shè)置網(wǎng)站的 favicon。
第一種,通過 link 標(biāo)簽設(shè)置(需要rel="icon"屬性)。
第二種,直接在網(wǎng)站根目錄放一張favicon.ico(必須是這個名稱,瀏覽器默認(rèn)的),html 中什么也不用設(shè)置。
- 網(wǎng)站目錄
index.html
favicon.ico
如果以上都沒有設(shè)置,那么大概率會看到以下錯誤。
了解這些,獲取就簡單了,先通過link獲取,只要rel包含icon就行了。
const link = document.querySelector('link[rel~="icon"]');如果找不到,可以請求/favicon.ico,這里直接添加一個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
}
}這樣獲取的link就保證存在了,然后就是繪制。
二、利用 canvas 進(jìn)行繪制
由于需要合成圖像,所以需要先繪制原有圖像。提到圖像繪制,可以想到 canvas 繪制,只需要一點點 canvas 基礎(chǔ)知識就足夠了。具體實現(xiàn)如下:
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;由于存在/favicon.ico沒有設(shè)置的情況,所以需要在 img 加載失敗的時候給一張默認(rèn)圖。
img.onerror = () => {
resolve("默認(rèn)圖base64");
}這樣就能獲取到 favicon 的圖像信息了。
三、利用 SVG 進(jìn)行圖片合成
在上面的基礎(chǔ)上,其實可以繼續(xù)通過 canvas 進(jìn)行繪制,再繪制一個標(biāo)簽也不是難事。不過這里可以采用 SVG 的方式來進(jìn)行繪制,有以下一些優(yōu)點。
成本更低,比 canvas 更易理解。
靈活性高,可以通過 CSS 進(jìn)行一些樣式控制。
首先,我們可以在 HTML 中自由的、像正常網(wǎng)頁開發(fā)一樣,繪制這樣一個布局,相信沒有什么難度。
local
由于寬度有限,所以需要強制文本換行,超出隱藏,關(guān)鍵樣式如下:
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;
}接著,將這一段 html 放入 foreignObject標(biāo)簽中,關(guān)于 foreignObject[1] 的作用,有興趣的可以參考張鑫旭老師的這篇文章 SVG 簡介與截圖等應(yīng)用[2],在這里,你可以簡單理解為是可以包含 HTML 的標(biāo)簽,而 SVG 本身也是一種圖片,這樣就達(dá)到了合成圖像的目的。
具體實現(xiàn)如下:
const link = getLink();
const icon = await img2Base64(link.href);
const favicon = `data:image/svg+xml;charset=utf-8,`.replace(/\n/g, '').replace(/\t/g, '').replace(/#/g, '%23')
這里需要注意幾點:
- img 標(biāo)簽在 svg 中需要寫成閉合標(biāo)簽形態(tài),不然會被認(rèn)為結(jié)構(gòu)錯誤。
- img 只能使用內(nèi)聯(lián)圖片,比如 base64,不然就是僅僅是一個字符串,這也是為何需要繪制原始 favicon 的原因。
- 如果使用內(nèi)聯(lián) svg,需要對 svg 進(jìn)行轉(zhuǎn)義。
- 字符串中的單雙引號問題也需要注意一下。
然后,將生成的 SVG 直接設(shè)置為 favicon,如下:
link.href= favicon;
添加標(biāo)識的 favicon
這樣就能正常地渲染了~
完整實現(xiàn)可以參考項目:https://github.com/XboxYan/auto-dev-favicon-chrome-plugin[3]。
四、目前一些局限
性首先是兼容性。
目前只有 Chrome 和 Firefox 是支持的(不過本文是運用在 Chrome 插件,所以無需關(guān)注這個問題),但是為了兼容其他瀏覽器,可以用一個 .ico來兜底。
另外,在 Chrome 上還有一個限制(不知道是不是Chrome 更新后的安全限制),當(dāng) favicon 使用 svg 格式圖片時,此時的 svg 會處于一種secure-static-mode[4],在這種模式下,所有動畫都不會執(zhí)行,會處于第一幀,比如下面這個例子:
很簡單的一個背景顏色動畫。在 Firefox 上是用作 favicon 是有動畫的。
Firefox 下是動畫狀態(tài)
但是,Chrome 上卻不行,只有禁止的第一幀。
Chrome 下是靜止?fàn)顟B(tài)
所以之前想實現(xiàn) favicon 文本滾動的效果可以就此打住了。
比較類似的還有媒體查詢,之前在網(wǎng)上看到有這樣的實現(xiàn),直接在 SVG 中實現(xiàn)黑暗模式。
比較類似的還有媒體查詢,之前在網(wǎng)上看到有這樣的實現(xiàn),直接在 SVG 中實現(xiàn)黑暗模式。
但是也是同樣的問題,只有 Firefox 下可行,Chrome是靜止不動的。
Firefox 下是支持媒體查詢的
什么時候 Chrome 可以解除這種限制呢?
總的來說,SVG 在繪制方面提供了無限可能,不僅僅是本文中的案例,覺得 canvas 過于復(fù)雜的都可以考慮這一方案。
參考資料
[1]foreignObject: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject。
[2]SVG 簡介與截圖等應(yīng)用: https://www.zhangxinxu.com/wordpress/2017/08/svg-foreignobject/。
[3]https://github.com/XboxYan/auto-dev-favicon-chrome-plugin: https://github.com/XboxYan/auto-dev-favicon-chrome-plugin。
[4]secure-static-mode: https://svgwg.org/svg2-draft/conform.html#secure-static-mode。
網(wǎng)站名稱:借助SVG生成帶標(biāo)識的Favicon
URL網(wǎng)址:http://www.dlmjj.cn/article/dhipgpe.html


咨詢
建站咨詢

