Favicon und Apple Touch Icons mit Symfony und Imagine erstellen

Für die meisten Webentwickler waren Favicons schon immer ein leidiges Thema: Das ICO Format beherrschen nur wenige Grafikeditoren, Internet Explorer generierte 404 Fehler in den Logs und trotzdem gehört es zu jeder Webseite.

Mittlerweile hat sich einiges geändert: die modernen Webbrowser unterstützen PNG Icons mit eigenem Alpha Kanal für schöne, transparente Icons. Auf Retina Displays können Icons mit höherer Auflösung angezeigt werden. Apple’s Safari und iOS zeigen hochaufgelöste Apple Touch Icons an, Windows 10 verwendet Tiles und Theme-Colors.

Insgesamt werden Touch Icons in mehr als 15 verschiedenen Auflösungen benötigt! Es gibt mehrere Online Tools, um diese Vielzahl an Grafiken automatisch zu erzeugen. Bei dynamischen Inhalten eignet sich das allerdings aus praktischen Gründen nicht. Eine automatische Lösung musste her – dank LiipImagineBundle kein Problem.

Nachdem das Bundle installiert ist, müssen wir dafür zwei FilterSets in der config.yml anlegen:

liip_imagine:
    filter_sets:
        favicon:
            quality: 100
            filters:
                thumbnail: { size: [64, 64], mode: inset }
        touchicon:
            quality: 100
            filters:
                thumbnail: { size: [64, 64], mode: inset }
                background: { size: [64, 64], color: '#fff' }

Wir unterscheiden zwischen FavIcon und Touch-Icons, weil wir zwar im Browser transparente Icons haben möchten, in den Apple Touch Icons jedoch nicht. Diese würden von iOS durch einen schwarzen Hintergrund ersetzt werden.

{% block favicon %}
 {# apple touch icons #}
 <link rel="apple-touch-icon" sizes="57x57" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [57, 57], 'color':'#A0C528'}, 'thumbnail': {"size": [57, 57] }})) }}">
 <link rel="apple-touch-icon" sizes="60x60" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [60, 60], 'color':'#A0C528'}, 'thumbnail': {"size": [60, 60] }})) }}">
 <link rel="apple-touch-icon" sizes="72x72" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [72, 72], 'color':'#A0C528'}, 'thumbnail': {"size": [72, 72] }})) }}">
 <link rel="apple-touch-icon" sizes="76x76" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [76, 76], 'color':'#A0C528'}, 'thumbnail': {"size": [76, 76] }})) }}">
 <link rel="apple-touch-icon" sizes="114x114" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [114, 114], 'color':'#A0C528'}, 'thumbnail': {"size": [114, 114] }})) }}">
 <link rel="apple-touch-icon" sizes="120x120" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [120, 120], 'color':'#A0C528'}, 'thumbnail': {"size": [120, 120] }})) }}">
 <link rel="apple-touch-icon" sizes="144x144" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [144, 144], 'color':'#A0C528'}, 'thumbnail': {"size": [144, 144] }})) }}">
 <link rel="apple-touch-icon" sizes="152x152" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [152, 152], 'color':'#A0C528'}, 'thumbnail': {"size": [152, 152] }})) }}">
 <link rel="apple-touch-icon" sizes="180x180" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [180, 180], 'color':'#A0C528'}, 'thumbnail': {"size": [180, 180] }})) }}">
 {# retina fav icons #}
 <link rel="icon" type="image/png" sizes="192x192" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [192, 192], 'color':'#A0C528'}, 'thumbnail': {"size": [192, 192] }})) }}">
 <link rel="icon" type="image/png" sizes="32x32" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [32, 32], 'color':'#A0C528'}, 'thumbnail': {"size": [32, 32] }})) }}">
 <link rel="icon" type="image/png" sizes="96x96" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [96, 96], 'color':'#A0C528'}, 'thumbnail': {"size": [96, 96] }})) }}">
 <link rel="icon" type="image/png" sizes="16x16" href="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [16, 16], 'color':'#A0C528'}, 'thumbnail': {"size": [16, 16] }})) }}">
 {# windows tile #}
 <meta name="msapplication-TileImage" content="{{ asset('images/icon_large.png' | imagine_filter('touchicon', {'background': {"size": [144, 144], 'color':'#BC212A'}, 'thumbnail': {"size": [144, 144] }})) }}">
 <meta name="msapplication-TileColor" content="#A0C528">
 <meta name="theme-color" content="#A0C528">
{% endblock %}

Wir profitieren wir von der relativ neuen Möglichkeit Filter zur Laufzeit zu konfigurieren. Das gleiche Prinzip lässt sich auch anwenden, um die Vielzahl an benötigten Bildern für OpenGraph (Facebook), Twitter, Pinterest, Google News, Google Shopping Ads, Google Dynamic Retargeting Ads erzeugen.