动态更改网站图标

489
我有一个网络应用程序,根据当前登录的用户进行品牌定制。我想将页面的favicon更改为专属标签的Logo,但是我无法找到任何代码或任何如何实现这一点的示例。有人以前成功过吗?
我考虑在一个文件夹中放置十几个图标,并动态生成与HTML页面一起使用的favicon.ico文件的引用。您有什么想法?

61
一个收藏夹图标里面有一款街机游戏。 - Corey Trager
19
街机游戏的链接已更改。这个链接 是正确的。 - Basil
请参考https://dev59.com/9G015IYBdhLWcg3w9gfh,了解如何使用画布在模板图像上绘制以动态更新网站的favicon。 - handle
2
已采纳答案中提供的代码示例存在一个小错误。由于我没有足够的声望分数来对答案进行评论,因此在这里写下来。 最后一行的括号位置颠倒了:}()); 应该改为 })(); 如果更新代码示例,其他人复制和粘贴时就不会出现这个问题了。 - Goran W
4
@CoreyTrager 网址已更改:http://www.p01.org/defender_of_the_favicon/。 - Clément
18个回答

4
我会使用Greg的方法,为favicon.ico制作自定义处理程序。这是一个(简化的)有效的处理程序:
using System;
using System.IO;
using System.Web;

namespace FaviconOverrider
{
    public class IcoHandler : IHttpHandler
    {
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "image/x-icon";
        byte[] imageData = imageToByteArray(context.Server.MapPath("/ear.ico"));
        context.Response.BinaryWrite(imageData);
    }

    public bool IsReusable
    {
        get { return true; }
    }

    public byte[] imageToByteArray(string imagePath)
    {
        byte[] imageByteArray;
        using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
        {
        imageByteArray = new byte[fs.Length];
        fs.Read(imageByteArray, 0, imageByteArray.Length);
        }

        return imageByteArray;
    }
    }
}

然后您可以将该处理程序用于IIS6中的web config的httpHandlers部分,或在IIS7中使用“Handler Mappings”功能。


1
我其实很好奇为什么这个回答被踩了?考虑到其他所有的回答都依赖于可能可用也可能不可用的脚本,这个回答实际上是最好的。 - ethermal
2
@ethermal 因为它看起来是在服务器端动态生成的。而楼主要求的是客户端的动态性。 - Alexis Wilke

4

对于使用jQuery的用户来说,有一个单行解决方案:

$("link[rel*='icon']").prop("href",'https://www.stackoverflow.com/favicon.ico');

4
唯一让这个在IE上运作的方法是将你的web服务器设置为处理对*.ico的请求,调用你的服务器端脚本语言(PHP,.NET等)。另外还要设置*.ico重定向到单个脚本,并且让这个脚本提供正确的favicon文件。如果你想在同一个浏览器中在不同的favicon之间来回切换,可能仍会出现一些有趣的缓存问题。

4

我在开发网站时经常使用此功能......这样我就可以一眼看到哪个标签页中运行的是本地、开发或生产环境。

由于Chrome支持SVG图标,这使得操作更加容易。

Tampermonkey脚本

请查看https://gist.github.com/elliz/bb7661d8ed1535c93d03afcd0609360f上的Tampermonkey脚本,它指向一个我放在https://elliz.github.io/svg-favicon/上的演示站点。

基本代码

从另一个答案中修改而来......可能还有改进的余地,但对我的需求已经足够好用了。

(function() {
    'use strict';

    // play with https://codepen.io/elliz/full/ygvgay for getting it right
    // viewBox is required but does not need to be 16x16
    const svg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
      <circle cx="8" cy="8" r="7.2" fill="gold" stroke="#000" stroke-width="1" />
      <circle cx="8" cy="8" r="3.1" fill="#fff" stroke="#000" stroke-width="1" />
    </svg>
    `;

    var favicon_link_html = document.createElement('link');
    favicon_link_html.rel = 'icon';
    favicon_link_html.href = svgToDataUri(svg);
    favicon_link_html.type = 'image/svg+xml';

    try {
        let favicons = document.querySelectorAll('link[rel~="icon"]');
        favicons.forEach(function(favicon) {
            favicon.parentNode.removeChild(favicon);
        });

        const head = document.getElementsByTagName('head')[0];
        head.insertBefore( favicon_link_html, head.firstChild );
    }
    catch(e) { }

    // functions -------------------------------
    function escapeRegExp(str) {
        return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
    }

    function replaceAll(str, find, replace) {
        return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
    }

    function svgToDataUri(svg) {
        // these may not all be needed - used to be for uri-encoded svg in old browsers
        var encoded = svg.replace(/\s+/g, " ")
        encoded = replaceAll(encoded, "%", "%25");
        encoded = replaceAll(encoded, "> <", "><"); // normalise spaces elements
        encoded = replaceAll(encoded, "; }", ";}"); // normalise spaces css
        encoded = replaceAll(encoded, "<", "%3c");
        encoded = replaceAll(encoded, ">", "%3e");
        encoded = replaceAll(encoded, "\"", "'"); // normalise quotes ... possible issues with quotes in <text>
        encoded = replaceAll(encoded, "#", "%23"); // needed for ie and firefox
        encoded = replaceAll(encoded, "{", "%7b");
        encoded = replaceAll(encoded, "}", "%7d");
        encoded = replaceAll(encoded, "|", "%7c");
        encoded = replaceAll(encoded, "^", "%5e");
        encoded = replaceAll(encoded, "`", "%60");
        encoded = replaceAll(encoded, "@", "%40");
        var dataUri = 'data:image/svg+xml;charset=UTF-8,' + encoded.trim();
        return dataUri;
    }

})();

只需将自己的SVG(如果使用工具,则可以使用Jake Archibald的SVGOMG进行清理)放入顶部的常量中。确保它是正方形(使用viewBox属性),就可以开始了。


@flyingsheep 因为它太贪心了。我只想编码在某些浏览器中存在问题的字形。使用上述子集,输出结果更加易读且易于编辑。由于我们不必再担心旧版 IE,因此上面的列表可能已经过时。我最近没有进行测试。 - Ruskin

3
我在我的项目中使用 favico.js
它允许将网站图标更改为一系列预定义的形状和自定义形状。
内部使用 canvas 进行渲染,使用 base64 数据 URL 进行图标编码。
该库还具有良好的功能:图标徽章和动画;据称,甚至可以将网络摄像头视频流嵌入图标 :)

链接和库非常有用,请提供一个描述它们如何工作的答案,以便这也成为问题的有效答案。 - Dima Tisnek
1
感谢@DimaTisnek。我已经更新了我的答案。 - Oscar Nevarez

2

完全可以实现

  • 在favicon.ico(和其他文件链接-请参见下面的答案链接)之后使用查询字符串
  • 只需确保服务器用正确的图像文件响应“someUserId”(这可以是静态路由规则或动态服务器端代码)。

例如:

<link rel="shortcut icon" href="/favicon.ico?userId=someUserId">

然后,无论您使用什么服务器端语言/框架,都应该能够根据userId轻松找到文件并在响应请求时提供服务。

但是要正确处理favicon(实际上是一个非常复杂的主题),请参见此处的答案:https://stackoverflow.com/a/45301651/661584

比自己解决所有细节要容易得多。

享受吧。


是的,链接没问题。我认为这些答案不能在IE中正常工作的主要原因是它们没有使用默认图标<link>,而是寻找apple-touch-icon或其他类似变量。 - Alexis Wilke

2
根据维基百科的介绍,您可以在部分使用参数rel="icon"来指定要加载的favicon文件。例如:
 <link rel="icon" type="image/png" href="/path/image.png">

我想,如果你想为该调用编写一些动态内容,你将可以访问cookie,以便通过这种方式检索会话信息并呈现适当的内容。
你可能会遇到文件格式问题(据报道,IE仅支持其 .ICO 格式,而大多数其他浏览器支持 PNG 和 GIF 图像),以及浏览器和代理缓存问题。这是因为 favicon 的最初目的是标记一个带有站点迷你徽标的书签。

这个主题远比那个复杂得多。https://stackoverflow.com/a/45301651/661584 生成器网站上的常见问题/信息会让你惊讶-这个主题有很多内容。 - MemeDeveloper
3
九年时间里,网络变化了很多。 - staticsan

1

在Chrome上测试2021年提出的解决方案时,我发现有时浏览器会缓存网站图标并且不显示更改,即使链接已经更改。

这段代码可以解决问题(类似于之前的建议,但添加了一个随机参数以避免缓存)。

let oldFavicon = document.getElementById('favicon')
var link = document.createElement('link')
link.id = 'favicon';
link.type = 'image/x-icon'
link.rel = 'icon';
link.href = new_favicon_url +'?=' + Math.random();
if (oldFavicon) {
    document.head.removeChild(oldFavicon);
}
document.head.appendChild(link);

https://gist.github.com/mathiasbynens/428626#gistcomment-1809869 复制,以防别人遇到同样的问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接