Jak tworzyć adaptacyjne favicony dla trybu jasnego i ciemnego: Kompletny przewodnik dewelopera

Favicon.im

Nowoczesne strony internetowe muszą dostosowywać się do preferencji użytkownika, a stylizacja favicony to często pomijany detal, który może znacząco poprawić doświadczenie użytkownika. Gdy użytkownicy przełączają się między trybem jasnym i ciemnym, Twoja favicona powinna dostosowywać się odpowiednio, aby zachować spójność wizualną.

Ten kompleksowy przewodnik obejmuje wszystko — od prostych rozwiązań wyłącznie HTML po zaawansowane implementacje JavaScript w popularnych frameworkach. Niezależnie od tego, czy budujesz statyczną stronę czy złożoną aplikację webową, znajdziesz tu odpowiednie podejście dla swojego projektu.

Metoda 1: Rozwiązanie wyłącznie HTML (zalecane dla większości stron)

Podejście wyłącznie HTML jest najbardziej niezawodną metodą i nie wymaga JavaScriptu. Używa zapytań medialnych CSS w atrybucie media tagów link favicony do automatycznego przełączania favicony na podstawie preferencji systemowych użytkownika.

Dlaczego ta metoda działa najlepiej:

  • Zero JavaScriptu
  • Działa natychmiast po załadowaniu strony
  • Obsługiwane przez wszystkie nowoczesne przeglądarki
  • Brak narzutu wydajnościowego

Podstawowa implementacja

<head>
  <!-- Default favicon (fallback for unsupported browsers) -->
  <link rel="icon" href="/favicon-light.ico" type="image/x-icon">

  <!-- Light mode favicon -->
  <link rel="icon" href="/favicon-light.ico" type="image/x-icon" media="(prefers-color-scheme: light)">

  <!-- Dark mode favicon -->
  <link rel="icon" href="/favicon-dark.ico" type="image/x-icon" media="(prefers-color-scheme: dark)">
</head>

Kompletna implementacja wielorozmiarowa

Dla kompleksowej obsługi urządzeń, zaimplementuj wiele rozmiarów z wariantami motywu:

<head>
  <!-- Default favicons (fallback) -->
  <link rel="icon" type="image/x-icon" href="/favicon-light.ico">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png">

  <!-- Light mode favicons -->
  <link rel="icon" type="image/x-icon" href="/favicon-light.ico" media="(prefers-color-scheme: light)">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-light-16x16.png" media="(prefers-color-scheme: light)">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png" media="(prefers-color-scheme: light)">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-light.png" media="(prefers-color-scheme: light)">

  <!-- Dark mode favicons -->
  <link rel="icon" type="image/x-icon" href="/favicon-dark.ico" media="(prefers-color-scheme: dark)">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-dark-16x16.png" media="(prefers-color-scheme: dark)">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-dark-32x32.png" media="(prefers-color-scheme: dark)">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-dark.png" media="(prefers-color-scheme: dark)">

  <!-- SVG favicons with embedded CSS -->
  <link rel="icon" type="image/svg+xml" href="/favicon-adaptive.svg">
</head>

Adaptacyjna favicona SVG

Stwórz pojedynczą faviconę SVG, która automatycznie dostosowuje się do schematu kolorów:

<!-- favicon-adaptive.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  <style>
    .light-mode { fill: #000000; }
    .dark-mode { fill: #ffffff; }

    @media (prefers-color-scheme: dark) {
      .light-mode { display: none; }
    }

    @media (prefers-color-scheme: light) {
      .dark-mode { display: none; }
    }
  </style>

  <!-- Light mode design -->
  <circle class="light-mode" cx="16" cy="16" r="12"/>
  <text class="light-mode" x="16" y="20" text-anchor="middle" fill="#fff" font-size="14">L</text>

  <!-- Dark mode design -->
  <circle class="dark-mode" cx="16" cy="16" r="12"/>
  <text class="dark-mode" x="16" y="20" text-anchor="middle" fill="#000" font-size="14">D</text>
</svg>

Metoda 2: Implementacja JavaScript

Gdy potrzebujesz dynamicznego przełączania favicony wykraczającego poza preferencje systemowe — np. niestandardowe przełączniki motywu lub aktualizacje w czasie rzeczywistym — JavaScript zapewnia potrzebną elastyczność.

Użyj JavaScriptu, gdy:

  • Masz niestandardowe kontrolki motywu
  • Musisz zsynchronizować z stanem motywu aplikacji
  • Chcesz aktualizować favicony bez odświeżania strony
  • Budujesz aplikację SPA

Podstawowe podejście JavaScript

// Function to update favicon based on theme
function updateFavicon(theme) {
  const favicon = document.querySelector('link[rel="icon"]') ||
                 document.createElement('link');

  favicon.rel = 'icon';
  favicon.type = 'image/png';
  favicon.href = theme === 'dark' ? '/favicon-dark.png' : '/favicon-light.png';

  if (!document.querySelector('link[rel="icon"]')) {
    document.head.appendChild(favicon);
  }
}

// Listen for system theme changes
if (window.matchMedia) {
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

  // Set initial favicon
  updateFavicon(mediaQuery.matches ? 'dark' : 'light');

  // Listen for changes
  mediaQuery.addEventListener('change', (e) => {
    updateFavicon(e.matches ? 'dark' : 'light');
  });
}

Zaawansowany JavaScript z wieloma rozmiarami

class FaviconManager {
  constructor() {
    this.sizes = [
      { size: '16x16', selector: 'link[rel="icon"][sizes="16x16"]' },
      { size: '32x32', selector: 'link[rel="icon"][sizes="32x32"]' },
      { size: '180x180', selector: 'link[rel="apple-touch-icon"]' }
    ];

    this.init();
  }

  init() {
    // Set initial theme
    this.updateTheme(this.getSystemTheme());

    // Listen for system changes
    if (window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      mediaQuery.addEventListener('change', (e) => {
        this.updateTheme(e.matches ? 'dark' : 'light');
      });
    }
  }

  getSystemTheme() {
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
      ? 'dark' : 'light';
  }

  updateTheme(theme) {
    this.sizes.forEach(({ size, selector }) => {
      let link = document.querySelector(selector);

      if (!link) {
        link = document.createElement('link');
        link.rel = size === '180x180' ? 'apple-touch-icon' : 'icon';
        link.type = 'image/png';
        if (size !== '180x180') link.sizes = size;
        document.head.appendChild(link);
      }

      link.href = `/favicon-${theme}-${size}.png`;
    });

    // Update default ico file
    let icoLink = document.querySelector('link[rel="icon"][type="image/x-icon"]');
    if (!icoLink) {
      icoLink = document.createElement('link');
      icoLink.rel = 'icon';
      icoLink.type = 'image/x-icon';
      document.head.appendChild(icoLink);
    }
    icoLink.href = `/favicon-${theme}.ico`;
  }

  // Method to manually set theme (for custom theme toggles)
  setTheme(theme) {
    this.updateTheme(theme);
  }
}

// Initialize
const faviconManager = new FaviconManager();

// Export for manual theme switching
window.faviconManager = faviconManager;

Metoda 3: Integracja z frameworkami

Nowoczesne frameworki oferują eleganckie sposoby obsługi stylizacji favicony. Oto jak wdrożyć adaptacyjne favicony w najpopularniejszych frameworkach JavaScript.

Implementacja React

import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';

function AdaptiveFavicon() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    // Check system preference
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    setTheme(mediaQuery.matches ? 'dark' : 'light');

    // Listen for changes
    const handleChange = (e) => {
      setTheme(e.matches ? 'dark' : 'light');
    };

    mediaQuery.addEventListener('change', handleChange);
    return () => mediaQuery.removeEventListener('change', handleChange);
  }, []);

  return (
    <Helmet>
      <link rel="icon" type="image/x-icon" href={`/favicon-${theme}.ico`} />
      <link rel="icon" type="image/png" sizes="32x32" href={`/favicon-${theme}-32x32.png`} />
      <link rel="apple-touch-icon" sizes="180x180" href={`/apple-touch-icon-${theme}.png`} />
    </Helmet>
  );
}

Implementacja Vue 3

<template>
  <div>
    <!-- Your app content -->
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'
import { useHead } from '@unhead/vue'

const isDark = ref(false)

const updateFavicon = () => {
  const theme = isDark.value ? 'dark' : 'light'

  useHead({
    link: [
      { rel: 'icon', type: 'image/x-icon', href: `/favicon-${theme}.ico` },
      { rel: 'icon', type: 'image/png', sizes: '32x32', href: `/favicon-${theme}-32x32.png` },
      { rel: 'apple-touch-icon', sizes: '180x180', href: `/apple-touch-icon-${theme}.png` }
    ]
  })
}

onMounted(() => {
  // Check system preference
  if (window.matchMedia) {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
    isDark.value = mediaQuery.matches

    // Listen for changes
    mediaQuery.addEventListener('change', (e) => {
      isDark.value = e.matches
    })
  }

  updateFavicon()
})

watch(isDark, updateFavicon)
</script>

Implementacja Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          innerHTML: `
            (function() {
              const updateFavicon = (isDark) => {
                const theme = isDark ? 'dark' : 'light';
                const links = [
                  { rel: 'icon', type: 'image/x-icon', href: \`/favicon-\${theme}.ico\` },
                  { rel: 'icon', type: 'image/png', sizes: '32x32', href: \`/favicon-\${theme}-32x32.png\` }
                ];

                links.forEach(linkData => {
                  let link = document.querySelector(\`link[rel="\${linkData.rel}"][sizes="\${linkData.sizes || 'any'}"]\`);
                  if (!link) {
                    link = document.createElement('link');
                    Object.assign(link, linkData);
                    document.head.appendChild(link);
                  } else {
                    link.href = linkData.href;
                  }
                });
              };

              if (window.matchMedia) {
                const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
                updateFavicon(mediaQuery.matches);
                mediaQuery.addEventListener('change', e => updateFavicon(e.matches));
              }
            })();
          `
        }
      ]
    }
  }
})

Metoda 4: Favicona CSS-in-JS (zaawansowane)

Generowanie favicony dynamicznie za pomocą Canvas i kolorów CSS:

class DynamicFaviconGenerator {
  constructor() {
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d');
    this.canvas.width = 32;
    this.canvas.height = 32;
  }

  generateFavicon(theme) {
    const colors = {
      light: { bg: '#ffffff', text: '#000000' },
      dark: { bg: '#000000', text: '#ffffff' }
    };

    const { bg, text } = colors[theme];

    // Clear canvas
    this.ctx.clearRect(0, 0, 32, 32);

    // Draw background
    this.ctx.fillStyle = bg;
    this.ctx.fillRect(0, 0, 32, 32);

    // Draw border
    this.ctx.strokeStyle = text;
    this.ctx.lineWidth = 2;
    this.ctx.strokeRect(2, 2, 28, 28);

    // Draw icon (example: letter or symbol)
    this.ctx.fillStyle = text;
    this.ctx.font = 'bold 20px Arial';
    this.ctx.textAlign = 'center';
    this.ctx.textBaseline = 'middle';
    this.ctx.fillText('🌙', 16, 16);

    return this.canvas.toDataURL('image/png');
  }

  updateFavicon(theme) {
    const dataUrl = this.generateFavicon(theme);

    let link = document.querySelector('link[rel="icon"]');
    if (!link) {
      link = document.createElement('link');
      link.rel = 'icon';
      link.type = 'image/png';
      document.head.appendChild(link);
    }

    link.href = dataUrl;
  }
}

// Usage
const generator = new DynamicFaviconGenerator();
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

generator.updateFavicon(mediaQuery.matches ? 'dark' : 'light');
mediaQuery.addEventListener('change', e => {
  generator.updateFavicon(e.matches ? 'dark' : 'light');
});

Najlepsze praktyki projektowe

Tworzenie skutecznych adaptacyjnych favicony wymaga starannej dbałości o zasady projektowe i doświadczenie użytkownika.

Kontrast kolorów i widoczność

Projekt favicony dla trybu jasnego:

  • Używaj ciemnych elementów (tekst, ikony) na przezroczystym lub jasnym tle
  • Dąż do współczynnika kontrastu WCAG AA (minimum 4,5:1)
  • Testuj wygląd na białych kartach przeglądarki i paskach zakładek
  • Zapewnij czytelność w 16x16 pikseli (najmniejszy powszechny rozmiar)

Projekt favicony dla trybu ciemnego:

  • Używaj jasnych elementów na przezroczystym lub ciemnym tle
  • Testuj widoczność na ciemnych motywach przeglądarki
  • Unikaj czystego białego (#ffffff) — używaj złamanego białego (#f0f0f0) dla lepszej równowagi
  • Rozważ subtelne cienie lub kontury dla definicji

Wskazówki dotyczące spójności projektowej

  1. Zachowaj rozpoznawalność marki — Utrzymuj spójność podstawowych elementów projektowych
  2. Testuj w wielu rozmiarach — 16x16, 32x32 i 180x180 pikseli
  3. Używaj prostych kształtów — Złożone detale znikają w małych rozmiarach
  4. Pamiętaj o daltonistach — Nie polegaj wyłącznie na kolorze w rozróżnianiu

Konwencja nazewnictwa plików

Organizuj pliki favicony z przejrzystym nazewnictwem:

/public/
├── favicon-light.ico
├── favicon-dark.ico
├── favicon-light-16x16.png
├── favicon-dark-16x16.png
├── favicon-light-32x32.png
├── favicon-dark-32x32.png
├── apple-touch-icon-light.png
├── apple-touch-icon-dark.png
└── favicon-adaptive.svg

Kompatybilność przeglądarek

Wsparcie nowoczesnych przeglądarek dla adaptacyjnych favicony

Przeglądarka Obsługa zapytań medialnych Uwagi
Chrome 76+ Pełne wsparcie Działa idealnie
Firefox 67+ Pełne wsparcie Doskonała implementacja
Safari 12.1+ Pełne wsparcie W tym iOS Safari
Edge 79+ Pełne wsparcie Edge oparty na Chromium
Internet Explorer Brak wsparcia Użyj awaryjnego JavaScriptu

Pokrycie rynku: Te wersje obejmują ~95% globalnego użycia przeglądarek w 2025 roku.

Strategia awaryjna

<!-- Always provide fallbacks -->
<link rel="icon" href="/favicon-light.ico" type="image/x-icon">

<!-- Enhanced support for modern browsers -->
<link rel="icon" href="/favicon-light.ico" type="image/x-icon" media="(prefers-color-scheme: light)">
<link rel="icon" href="/favicon-dark.ico" type="image/x-icon" media="(prefers-color-scheme: dark)">

<!-- JavaScript fallback for older browsers -->
<script>
  if (!window.matchMedia || !CSS.supports('(prefers-color-scheme: dark)')) {
    // Load favicon based on time of day or other heuristics
    const hour = new Date().getHours();
    const isDark = hour < 6 || hour > 18;
    document.querySelector('link[rel="icon"]').href =
      isDark ? '/favicon-dark.ico' : '/favicon-light.ico';
  }
</script>

Testowanie i walidacja

Ręczna lista kontrolna testów

  • [ ] Test w trybie jasnym (preferencje systemowe)
  • [ ] Test w trybie ciemnym (preferencje systemowe)
  • [ ] Weryfikacja natychmiastowej zmiany favicony przy przełączeniu motywu
  • [ ] Sprawdzenie w różnych przeglądarkach (Chrome, Firefox, Safari, Edge)
  • [ ] Test na urządzeniach mobilnych
  • [ ] Walidacja zachowania awaryjnego w starszych przeglądarkach

Testy automatyczne

// Test script for favicon theme switching
function testFaviconThemes() {
  const tests = [
    { theme: 'light', expected: '/favicon-light.ico' },
    { theme: 'dark', expected: '/favicon-dark.ico' }
  ];

  tests.forEach(({ theme, expected }) => {
    // Mock media query
    Object.defineProperty(window, 'matchMedia', {
      writable: true,
      value: jest.fn().mockImplementation(query => ({
        matches: query.includes('dark') ? theme === 'dark' : theme === 'light',
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
      })),
    });

    // Trigger update
    updateFavicon(theme);

    // Assert
    const favicon = document.querySelector('link[rel="icon"]');
    expect(favicon.href).toContain(expected);
  });
}

Optymalizacja wydajności

Preload favicony motywów

<!-- Preload both theme favicons for instant switching -->
<link rel="preload" as="image" href="/favicon-light.ico">
<link rel="preload" as="image" href="/favicon-dark.ico">

Minimalizacja rozmiarów plików

  • Utrzymuj pliki ICO poniżej 1 KB
  • Optymalizuj pliki PNG narzędziami jak TinyPNG
  • Używaj SVG dla prostych geometrycznych projektów
  • Rozważ format WebP dla nowoczesnych przeglądarek

Strategia buforowania

# Nginx configuration for favicon caching
location ~* \.(ico|png|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary "Accept-Encoding";
}

Rozwiązywanie typowych problemów

Favicona nie przełącza się między motywami

Objawy: Favicona pozostaje taka sama niezależnie od zmiany motywu systemowego

Typowe przyczyny i rozwiązania:

  1. Problemy z pamięcią podręczną przeglądarki

    <!-- Add cache-busting parameters -->
    <link rel="icon" href="/favicon-light.ico?v=2025" media="(prefers-color-scheme: light)">
    <link rel="icon" href="/favicon-dark.ico?v=2025" media="(prefers-color-scheme: dark)">
    
  2. Nieprawidłowa składnia zapytania medialnego

    <!-- ❌ Wrong -->
    <link rel="icon" href="/favicon-dark.ico" media="dark">
    
    <!-- ✅ Correct -->
    <link rel="icon" href="/favicon-dark.ico" media="(prefers-color-scheme: dark)">
    

Wiele favicony ładuje się jednocześnie

Objawy: Karta Network pokazuje wiele żądań favicony

Rozwiązanie: Użyj JavaScriptu do zastępowania zamiast dodawania:

function replaceFavicon(href) {
  // Remove all existing favicon links
  document.querySelectorAll('link[rel*="icon"]').forEach(link => link.remove());

  // Add new favicon
  const link = document.createElement('link');
  link.rel = 'icon';
  link.type = 'image/x-icon';
  link.href = href;
  document.head.appendChild(link);
}

Favicony SVG się nie wyświetlają

Objawy: Favicona SVG działa w niektórych przeglądarkach, ale nie w innych

Przyczyna: Ograniczone wsparcie favicony SVG w starszych przeglądarkach

Rozwiązanie: Zawsze zapewnij awaryjne PNG:

<!-- Modern browsers: SVG with media queries -->
<link rel="icon" type="image/svg+xml" href="/favicon-adaptive.svg">

<!-- Fallback: PNG for older browsers -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-dark-32x32.png" media="(prefers-color-scheme: dark)">

Zaawansowane techniki

Plakietki powiadomień z uwzględnieniem motywu

class NotificationFavicon {
  constructor() {
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d');
    this.canvas.width = 32;
    this.canvas.height = 32;
    this.baseIcons = {
      light: '/favicon-light-32x32.png',
      dark: '/favicon-dark-32x32.png'
    };
  }

  async drawWithBadge(theme, count) {
    const baseIcon = new Image();
    baseIcon.src = this.baseIcons[theme];

    return new Promise(resolve => {
      baseIcon.onload = () => {
        this.ctx.clearRect(0, 0, 32, 32);
        this.ctx.drawImage(baseIcon, 0, 0, 32, 32);

        if (count > 0) {
          // Draw notification badge
          const badgeSize = 12;
          const x = 32 - badgeSize;
          const y = 0;

          // Badge background
          this.ctx.fillStyle = '#ff4444';
          this.ctx.beginPath();
          this.ctx.arc(x + badgeSize/2, y + badgeSize/2, badgeSize/2, 0, 2 * Math.PI);
          this.ctx.fill();

          // Badge text
          this.ctx.fillStyle = 'white';
          this.ctx.font = '8px Arial';
          this.ctx.textAlign = 'center';
          this.ctx.textBaseline = 'middle';
          this.ctx.fillText(
            count > 9 ? '9+' : count.toString(),
            x + badgeSize/2,
            y + badgeSize/2
          );
        }

        resolve(this.canvas.toDataURL());
      };
    });
  }

  async updateWithNotification(count = 0) {
    const theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    const dataUrl = await this.drawWithBadge(theme, count);

    let link = document.querySelector('link[rel="icon"]');
    if (!link) {
      link = document.createElement('link');
      link.rel = 'icon';
      document.head.appendChild(link);
    }
    link.href = dataUrl;
  }
}

// Usage
const notificationFavicon = new NotificationFavicon();
notificationFavicon.updateWithNotification(3); // Show badge with count 3

Podsumowanie i kolejne kroki

Adaptacyjne favicony reprezentują mały, ale znaczący sposób na poprawę doświadczenia użytkownika. Świadczą o dbałości o detale i szacunku dla preferencji użytkownika, przyczyniając się do bardziej dopracowanej i profesjonalnej witryny.

Wybierz odpowiednią metodę dla swojego projektu

Metoda Najlepsza do Złożoność Wydajność
Wyłącznie HTML Strony statyczne, blogi, strony marketingowe Niska Doskonała
JavaScript SPA, niestandardowe motywy, dynamiczne aktualizacje Średnia Dobra
Integracja z frameworkiem Aplikacje React/Vue/Nuxt Średnia Dobra
Zaawansowane techniki Systemy powiadomień, aktualizacje w czasie rzeczywistym Wysoka Zmienna

Lista kontrolna implementacji

Przed wdrożeniem systemu adaptacyjnych favicony:

  • [ ] Stwórz obie wersje — jasną i ciemną
  • [ ] Przetestuj w wielu przeglądarkach (Chrome, Firefox, Safari, Edge)
  • [ ] Zweryfikuj przełączanie przy zmianach motywu systemowego
  • [ ] Przetestuj na urządzeniach mobilnych (iOS Safari, Android Chrome)
  • [ ] Zoptymalizuj rozmiary plików (utrzymuj poniżej 1 KB dla plików ICO)
  • [ ] Dodaj odpowiednie rozwiązania awaryjne dla starszych przeglądarek
  • [ ] Zwaliduj implementację narzędziami jak Favicon.im

Wpływ na wydajność

Prawidłowo wdrożone adaptacyjne favicony mają minimalny wpływ na wydajność:

  • Metoda wyłącznie HTML: Zero narzutu JavaScript
  • Wpływ na rozmiar pliku: ~2-4 KB łącznie (wersje jasna + ciemna)
  • Czas ładowania: Pomijalny przy prawidłowym buforowaniu

Idąc dalej

Rozważ te zaawansowane optymalizacje:

  • Preloaduj krytyczne zasoby favicony dla natychmiastowego przełączania
  • Użyj formatu WebP dla nowoczesnych przeglądarek (z awaryjnym PNG)
  • Wdróż dynamiczne plakietki favicony dla powiadomień
  • Dodaj animacje favicony na specjalne okazje lub statusy

Wdrażając adaptacyjne favicony z namysłem, tworzysz bardziej spójne i przyjazne doświadczenie webowe, które dostosowuje się do nowoczesnych preferencji użytkowników.

Check Your Favicon

Use favicon.im to quickly check if your favicon is configured correctly. Our free tool ensures your website's favicon displays properly across all browsers and devices.

Free Public Service

Favicon.im is a completely free public service trusted by developers worldwide.

15M+
Monthly Favicon Requests
100%
Free Forever