Cambiar el sitio web favicon dinámicamente

347

Tengo una aplicación web que está marcada según el usuario que ha iniciado sesión actualmente. Me gustaría cambiar el favicon de la página para que sea el logotipo de la etiqueta privada, pero no puedo encontrar ningún código ni ejemplos de cómo para hacer esto. ¿Alguien ha hecho esto con éxito antes?

Me imagino tener una docena de iconos en una carpeta, y la referencia a qué archivo favicon.ico usar se genera dinámicamente junto con la página HTML. Pensamientos?

SqlRyan
fuente
40
Hay un juego de arcade en un favicon.
Corey Trager el
Tenga en cuenta que la implementación dinámica de favicon de Chrome tiene errores y usa demasiada CPU. Ver code.google.com/p/chromium/issues/detail?id=121333
brillante
66
El enlace para el juego de arcade cambió. Este es el correcto.
Basil
Consulte stackoverflow.com/questions/6296574/… sobre cómo actualizar dinámicamente el favicon dibujando en la parte superior de una imagen de plantilla con lienzo.
manejar
1
Pequeño error en el ejemplo de código proporcionado en la respuesta aceptada. No tengo suficiente puntaje de reputación para comentar las respuestas, por lo tanto, escribo aquí. La última línea tiene los paréntesis intercambiados:} ()); tiene que leer })(); Sería bueno que el ejemplo de código se actualice, ya que lo más probable es que otros lo copien y peguen.
Goran W

Respuestas:

396

Por qué no?

(function() {
    var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    link.href = 'http://www.stackoverflow.com/favicon.ico';
    document.getElementsByTagName('head')[0].appendChild(link);
})();

Firefox debería ser genial con eso.

editado para sobrescribir correctamente los iconos existentes

keparo
fuente
2
Estoy pensando que esto está cerca de lo que estoy buscando, pero ¿cómo podría obtener el HREF apropiado de la base de datos? Supongo que tendré que hacer una búsqueda en el servidor desde JavaScript, pero no quiero que se complique demasiado. Gracias por el consejo.
SqlRyan
34
Como de todos modos esto no funciona en IE, puede eliminarlo shortcutdel relatributo. shortcutes una relación de enlace propietaria de IE no válida!
Mathias Bynens
8
Podrías buscar fácilmente un enlace favicon existente y actualizarlo o reemplazarlo.
keparo
55
Google puede proporcionarle el favicon de un sitio utilizando esta url, reemplazando stackoverflow.com por el dominio que desee: s2.googleusercontent.com/s2/favicons?domain=stackoverflow.com
kirb
55
¿Debería ingresar esto en la consola Javascript en Chrome? No puedo lograr que cambie los favicons en varios sitios de esa manera.
powerj1984
88

Aquí hay un código que funciona en Firefox, Opera y Chrome (a diferencia de cualquier otra respuesta publicada aquí). Aquí hay una demostración de código diferente que también funciona en IE11 . El siguiente ejemplo podría no funcionar en Safari o Internet Explorer.

/*!
 * Dynamically changing favicons with JavaScript
 * Works in all A-grade browsers except Safari and Internet Explorer
 * Demo: http://mathiasbynens.be/demo/dynamic-favicons
 */

// HTML5™, baby! http://mathiasbynens.be/notes/document-head
document.head = document.head || document.getElementsByTagName('head')[0];

function changeFavicon(src) {
 var link = document.createElement('link'),
     oldLink = document.getElementById('dynamic-favicon');
 link.id = 'dynamic-favicon';
 link.rel = 'shortcut icon';
 link.href = src;
 if (oldLink) {
  document.head.removeChild(oldLink);
 }
 document.head.appendChild(link);
}

Luego lo usaría de la siguiente manera:

var btn = document.getElementsByTagName('button')[0];
btn.onclick = function() {
 changeFavicon('http://www.google.com/favicon.ico');
};

Bifurca o mira una demostración .

Mathias Bynens
fuente
El error de Chrome se corrigió en Chrome 6 (lanzado el 10 de septiembre), por lo que el truco de Chrome ya no es realmente necesario; de hecho, sugiero encarecidamente no usarlo ya que rompe el botón de avance.
josh3736
El error de Chrome podría haberse solucionado, pero se volvió a romper en 14.0.835.187.
danorton
La demostración no me funciona con Chrome 21 / WinXP.
Hugo
La demo no me funciona en Chrome 26 / Win7. document.head || document.head = document.getElementsByTagName('head')[0]; Uncaught ReferenceError: Invalid left-hand side in assignment
Patrick
2
Esto funciona en todos los navegadores compatibles actualmente (IE 11, Edge, FF y Chrome) que no pueden realizar pruebas con safari
Aaron
46

Si tiene el siguiente fragmento de HTML:

<link id="favicon" rel="shortcut icon" type="image/png" href="favicon.png" />

Puede cambiar el favicon usando Javascript cambiando el elemento HREF en este enlace, por ejemplo (suponiendo que esté usando JQuery):

$("#favicon").attr("href","favicon2.png");

También puede crear un elemento Canvas y establecer el HREF como ToDataURL () del canvas, al igual que lo hace el Defensor Favicon .

fserb
fuente
1
Creo que para cuando se ejecute el JS, el navegador ya habrá visto el enlace y habrá intentado cargarlo favicon.png. Es posible que esto deba hacerse en el lado del servidor.
cHao
Si no usa JQuery, puede cambiar el hrefatributo de #faviconusar ¿ document.getElementById('favicon').setAttribute('href','favicon2.png') Tal vez puede agregarlo a su publicación @fserb?
johannchopin
37

Versión de jQuery:

$("link[rel='shortcut icon']").attr("href", "favicon.ico");

o mejor:

$("link[rel*='icon']").attr("href", "favicon.ico");

Versión Vanilla JS:

document.querySelector("link[rel='shortcut icon']").href = "favicon.ico";

document.querySelector("link[rel*='icon']").href = "favicon.ico";
vorillaz
fuente
@pkExec Una combinación de esto y la respuesta de keparo anterior (la respuesta elegida) lo hizo funcionar en ff y cromo para mí.
MrShmee
17

Un enfoque más moderno:

const changeFavicon = link => {
  let $favicon = document.querySelector('link[rel="icon"]')
  // If a <link rel="icon"> element already exists,
  // change its href to the given link.
  if ($favicon !== null) {
    $favicon.href = link
  // Otherwise, create a new element and append it to <head>.
  } else {
    $favicon = document.createElement("link")
    $favicon.rel = "icon"
    $favicon.href = link
    document.head.appendChild($favicon)
  }
}

Luego puede usarlo así:

changeFavicon("http://www.stackoverflow.com/favicon.ico")
Michał Perłakowski
fuente
11

El favicon se declara en la etiqueta de la cabeza con algo como:

<link rel="shortcut icon" type="image/ico" href="favicon.ico">

Debería poder simplemente pasar el nombre del icono que desea a lo largo de los datos de la vista y arrojarlo a la etiqueta de la cabeza.

Jeff Sheldon
fuente
1
IIRC, sin embargo, algunos navegadores (estoy mirando en su dirección, IE) realmente no respetan esto a veces.
Matthew Schinckel
(Descubrí que tenía mejores resultados simplemente teniendo el archivo de icono en la ubicación correcta, en lugar del enlace explícito).
Matthew Schinckel
9

Aquí hay un código que uso para agregar soporte de favicon dinámico a Opera, Firefox y Chrome. Sin embargo, no pude hacer que IE o Safari funcionaran. Básicamente, Chrome permite favicons dinámicos, pero solo los actualiza cuando la ubicación de la página (o un iframeetc.) cambia hasta donde puedo decir:

var IE = navigator.userAgent.indexOf("MSIE")!=-1
var favicon = {
    change: function(iconURL) {
        if (arguments.length == 2) {
            document.title = optionalDocTitle}
        this.addLink(iconURL, "icon")
        this.addLink(iconURL, "shortcut icon")

        // Google Chrome HACK - whenever an IFrame changes location 
        // (even to about:blank), it updates the favicon for some reason
        // It doesn't work on Safari at all though :-(
        if (!IE) { // Disable the IE "click" sound
            if (!window.__IFrame) {
                __IFrame = document.createElement('iframe')
                var s = __IFrame.style
                s.height = s.width = s.left = s.top = s.border = 0
                s.position = 'absolute'
                s.visibility = 'hidden'
                document.body.appendChild(__IFrame)}
            __IFrame.src = 'about:blank'}},

    addLink: function(iconURL, relValue) {
        var link = document.createElement("link")
        link.type = "image/x-icon"
        link.rel = relValue
        link.href = iconURL
        this.removeLinkIfExists(relValue)
        this.docHead.appendChild(link)},

    removeLinkIfExists: function(relValue) {
        var links = this.docHead.getElementsByTagName("link");
        for (var i=0; i<links.length; i++) {
            var link = links[i]
            if (link.type == "image/x-icon" && link.rel == relValue) {
                this.docHead.removeChild(link)
                return}}}, // Assuming only one match at most.

    docHead: document.getElementsByTagName("head")[0]}

Para cambiar los favicons, solo favicon.change("ICON URL")usa lo anterior.

(Créditos a http://softwareas.com/dynamic-favicons por el código en el que basé esto).

crio
fuente
El error de Chrome se corrigió en Chrome 6 (lanzado el 10 de septiembre), por lo que el truco de Chrome ya no es realmente necesario; de hecho, sugiero encarecidamente no usarlo ya que rompe el botón de avance.
josh3736
Chrome todavía tiene el mismo error, aunque en circunstancias ligeramente diferentes que el error específico observado. code.google.com/p/chromium/issues/detail?id=99549
danorton
4

Usaría el enfoque de Greg y haría un controlador personalizado para favicon.ico Aquí hay un controlador (simplificado) que funciona:

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;
    }
    }
}

Luego puede usar ese controlador en la sección httpHandlers de la configuración web en IIS6 o usar la función 'Asignaciones de controladores' en IIS7.

Dan
fuente
1
En realidad tengo curiosidad por qué esto se votó negativamente. esta es realmente la mejor respuesta teniendo en cuenta que todos los demás dependen de secuencias de comandos que pueden o no estar disponibles.
Etermal
1
@ethermal Porque parece que es dinámico en el lado del servidor. OP estaba pidiendo dinamismo por parte del cliente.
Alexis Wilke
3

La única forma de hacer que esto funcione para IE es configurar su servidor web para que trate las solicitudes de * .ico para que llame al lenguaje de script del lado del servidor (PHP, .NET, etc.). También configure * .ico para redirigir a un solo script y hacer que este script entregue el archivo favicon correcto. Estoy seguro de que todavía habrá algunos problemas interesantes con la memoria caché si desea poder rebotar de un lado a otro en el mismo navegador entre diferentes favicons.

Greg
fuente
3

Hay una solución de línea única para quienes usan jQuery:

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

O si quieres un emoticon :)

var canvas = document.createElement("canvas");
canvas.height = 64;
canvas.width = 64;

var ctx = canvas.getContext("2d");
ctx.font = "64px serif";
ctx.fillText("☠️", 0, 64); 

$("link[rel*='icon']").prop("href", canvas.toDataURL());

Atrezzo a https://koddsson.com/posts/emoji-favicon/

max4ever
fuente
2

Según WikiPedia , puede especificar qué archivo favicon cargar con la linketiqueta en la headsección, con un parámetro de rel="icon".

Por ejemplo:

 <link rel="icon" type="image/png" href="/path/image.png">

Me imagino que si quisieras escribir contenido dinámico para esa llamada, tendrías acceso a cookies para poder recuperar la información de tu sesión de esa manera y presentar el contenido apropiado.

Puede fallar los formatos de archivo (se dice que IE solo admite su formato .ICO, mientras que la mayoría de los demás admite imágenes PNG y GIF) y posiblemente problemas de almacenamiento en caché, tanto en el navegador como a través de servidores proxy. Esto se debe a la versión original de favicon, específicamente, para marcar un marcador con el mini-logotipo de un sitio.

staticsan
fuente
mucho más que eso. stackoverflow.com/a/45301651/661584 las preguntas frecuentes / información en el sitio del generador lo sorprenderán, hay mucho en este tema.
MemeDeveloper
3
La web cambia mucho en 9 años.
staticsan
2

Si totalmente posible

  • Use una cadena de consulta después del favicon.ico (y otros enlaces de archivos - vea el enlace de respuesta a continuación)
  • Simplemente asegúrese de que el servidor responde al "someUserId" con el archivo de imagen correcto (que podría ser reglas de enrutamiento estático o código dinámico del lado del servidor).

p.ej

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

Entonces, sea ​​cual sea el lenguaje / marco del lado del servidor que utilice, debería poder encontrar fácilmente el archivo en función del ID de usuario y servirlo en respuesta a esa solicitud .

Pero para hacer favicons correctamente (en realidad es un tema realmente complejo ), consulte la respuesta aquí https://stackoverflow.com/a/45301651/661584

Mucho más fácil que resolver todos los detalles usted mismo.

Disfrutar.

MemeDeveloper
fuente
Sí, el enlace es bueno. Creo que la razón principal por la que estas respuestas no funcionan en IE es porque no usan ese ícono predeterminado <link>, sino que buscan la apple-touch-iconu otra variante.
Alexis Wilke
1

Yo uso favico.js en mis proyectos.

Permite cambiar el favicon a una gama de formas predefinidas y también personalizadas.

Internamente se utiliza canvaspara la representación y base64URL de datos para la codificación de iconos.

La biblioteca también tiene buenas características: insignias de iconos y animaciones; supuestamente, incluso puede transmitir el video de la cámara web al icono :)

Oscar Nevarez
fuente
El enlace y la biblioteca son muy útiles, proporcione una descripción de cómo funciona para que esto también se convierta en una respuesta válida a la pregunta como se indica.
Dima Tisnek
1
Gracias @DimaTisnek. He actualizado mi respuesta.
Oscar Nevarez
0

Uso esta función todo el tiempo cuando desarrollo sitios ... así puedo ver de un vistazo qué pestaña tiene local, desarrollo o producción ejecutándose.

Ahora que Chrome admite favicons SVG, lo hace mucho más fácil.

Tampermonkey Script

Eche un vistazo a https://gist.github.com/elliz/bb7661d8ed1535c93d03afcd0609360f para obtener un script de tampermonkey que apunta a un sitio de demostración que lancé en https://elliz.github.io/svg-favicon/

Codigo basico

Adaptado esto de otra respuesta ... podría mejorarse, pero lo suficientemente bueno para mis necesidades.

(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;
    }

})();

Simplemente coloque su propio SVG (tal vez se limpie con el SVGOMG de Jake Archibald si está usando una herramienta) en la constante en la parte superior. Asegúrate de que sea cuadrado (con el atributo viewBox) y listo.

Ruskin
fuente