Detect if the browser is using dark mode and use a different favicon

后端 未结 4 819
不思量自难忘°
不思量自难忘° 2021-01-30 08:33

Google Chrome 73 has been released, and it adds \"dark mode\" support to the browser. I notice that a lot of favicons look bad now.

Is there a way to d

相关标签:
4条回答
  • 2021-01-30 09:14

    CSS has a theme mode detection using prefers-color-scheme media feature:

    @media (prefers-color-scheme: dark) {
      ...
    }
    

    With that in mind, nowadays you can use an SVG as a favicon for your website:

    <link rel="icon" href="/favicon.svg" type="image/svg+xml">
    

    Then you can update the SVG favicon design using the CSS prefers-color-scheme media feature. Below is an SVG rectangle with rounded corners, which has a different color, depending on the active theme:

    <svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
      <style>
        rect {
          fill: green;
        }
        @media (prefers-color-scheme: dark) {
          rect {
            fill: red;
          }
        }
      </style>
      <rect width="50" height="50" rx="5"/>
    </svg>
    

    Now, considering the current browser support for the SVG favicon, a fallback is required for the older browsers:

    <link rel="icon" href="/favicon.svg" type="image/svg+xml">
    <link rel="icon" href="/favicon.png" type="image/png">
    <!-- favicon.ico in the root -->
    

    From https://catalin.red/svg-favicon-light-dark-theme/

    Here's a demo too: https://codepen.io/catalinred/pen/vYOERwL

    0 讨论(0)
  • 2021-01-30 09:31

    Adding and removing an icon from the document’s head works in Firefox but not Safari:

    • Demo: https://zesty-soybean.glitch.me/
    • Source: https://glitch.com/edit/#!/zesty-soybean

    Chrome is still implementing (prefers-color-scheme: dark), so the jury’s still out. https://crbug.com/889087. In Chrome 76 with --enable-blink-features=MediaQueryPrefersColorScheme, this correctly sets the icon when the page is loaded, but does not respond dynamically to changes in dark mode.

    Safari adds a grey background to dark icons in dark mode (for example, Wikimedia Foundation, Github), so this workaround isn't necessary for legibility.

    1. Add two link rel=icon elements with ids for later:

      <link rel="icon" href="a.png" id="light-scheme-icon">
      <link rel="icon" href="b.png" id="dark-scheme-icon">
      
    2. Create a CSS media matcher:

      matcher = window.matchMedia('(prefers-color-scheme: dark)');
      matcher.addListener(onUpdate);
      onUpdate();
      
    3. Add/remove the elements from the document's head:

      lightSchemeIcon = document.querySelector('link#light-scheme-icon');
      darkSchemeIcon = document.querySelector('link#dark-scheme-icon');
      
      function onUpdate() {
        if (matcher.matches) {
          lightSchemeIcon.remove();
          document.head.append(darkSchemeIcon);
        } else {
          document.head.append(lightSchemeIcon);
          darkSchemeIcon.remove();
        }
      }
      
    0 讨论(0)
  • 2021-01-30 09:33

    The easiest option is to change the source when you change the mode on your computer.

    var element = document.querySelector("link[rel='icon']");
    const darkModeListener = (event) => {
    if (event.matches) {
      console.log("dark");
      element.setAttribute("href","img/favicon-dark.svg");
    } else {
      console.log("light");
      element.setAttribute("href","img/favicon-light.svg");
    }
    };
    
    // Update favicon on Mode change 
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', darkModeListener);
    
    // Check Mode on load
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme:      dark)').matches) {
      element.setAttribute("href","img/favicon-dark.svg");
    } else {
      element.setAttribute("href","img/favicon-light.svg");
    }
     

    But if you have a multi-device favicon then you need to do something like this ...

    // Switch Favicon on Dark/Light Mode
            let colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
                const setColorScheme = e => {
                  if (e.matches) {
                    // Dark
                    var favicon = document.querySelectorAll('link[data-type="favicon"]');
                    var i = favicon.length;
                    while (i--) {              
                      favicon[i].setAttribute('href', favicon[i].dataset.dark);
                    }
                  } else {
                    // Light
                    var favicon = document.querySelectorAll('link[data-type="favicon"]');
                    var i = favicon.length;
                    while (i--) {              
                      favicon[i].setAttribute("href", favicon[i].dataset.light);
                    }
                  }
                }
               
               setColorScheme(colorSchemeQueryList);
               colorSchemeQueryList.addListener(setColorScheme);
    <link rel="apple-touch-icon" sizes="180x180" href="Images/favicon/light/apple-touch-icon.png" data-type="favicon" data-light="Images/favicon/light/apple-touch-icon.png" data-dark="Images/favicon/dark/apple-touch-icon.png">
      <link rel="icon" type="image/png" sizes="32x32" href="Images/favicon/light/favicon-32x32.png" data-type="favicon" data-light="Images/favicon/light/favicon-32x32.png" data-dark="Images/favicon/dark/favicon-32x32.png">
      <link rel="icon" type="image/png" sizes="16x16" href="Images/favicon/light/favicon-16x16.png" data-type="favicon" data-light="Images/favicon/light/favicon-16x16.png" data-dark="Images/favicon/dark/favicon-16x16.png">
      <link rel="favicon" href="Images/favicon/light/site.webfavicon" data-type="favicon" data-light="Images/favicon/light/site.webfavicon" data-dark="Images/favicon/dark/site.webfavicon">
      <link rel="mask-icon" href="Images/favicon/light/safari-pinned-tab.svg" color="#000000" data-type="favicon" data-light="Images/favicon/light/safari-pinned-tab.svg" data-dark="Images/favicon/dark/safari-pinned-tab.svg">

    0 讨论(0)
  • 2021-01-30 09:34

    To make it a little more generic than Josh's answer, try this whilst the browsers still get around to implementing media natively. (Notice no hardcoded number of themes, ids, or media-queries in the JS; it's all kept in the HTML.)

    <link rel="icon" href="/favicon.ico?light" media="(prefers-color-scheme:no-preference)">
    <link rel="icon" href="/favicon.ico?dark"  media="(prefers-color-scheme:dark)">
    <link rel="icon" href="/favicon.ico?light" media="(prefers-color-scheme:light)">
    
    $(document).ready(function() {
        if (!window.matchMedia)
            return;
    
        var current = $('head > link[rel="icon"][media]');
        $.each(current, function(i, icon) {
            var match = window.matchMedia(icon.media);
            function swap() {
                if (match.matches) {
                    current.remove();
                    current = $(icon).appendTo('head');
                }
            }
            match.addListener(swap);
            swap();
        });
    });
    

    The upshot is that once that attribute is supported, you just need to remove the Javascript and it'll still work.

    I deliberately split /favicon.ico?light into two tags instead of a single one with media="(prefers-color-scheme: no-preference), (prefers-color-scheme:light)" because some browsers that don't support media permanently pick the first rel="icon" they see… and others pick the last!

    0 讨论(0)
提交回复
热议问题