angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Utiliser les icônes de votre site web Flask et réduire "First Contentful Paint".

Utilisez une macro d'icône Jinja pour mettre des icônes sur vos pages et utilisez <symbol> pour définir des icônes une fois et les utiliser plusieurs fois sur la même page.

29 mai 2020
Dans Icons, Jinja2
post main image
https://unsplash.com/@codingtim

Il existe de nombreux types d'icônes vectorielles. Dans cet article, je ne regarde que les icônes SVG, et je me limite aux icônes de navigation, parfois aussi appelées icônes d'interface. Ces icônes ne sont pas seulement esthétiques sur les sites web, elles ont aussi la même couleur et la même échelle que les polices de caractères. Et elles sont très fonctionnelles. Imaginez un bouton avec le texte "Edit" dedans. Remplacez ce texte par une icône en forme de crayon et vous obtenez plus d'espace sur la page tout en sachant très clairement ce qui se passera lorsque vous cliquerez sur le bouton.

Un autre exemple est la page de contact. Au lieu d'indiquer un numéro de téléphone, une adresse électronique et une adresse de visite sous forme de texte uniquement, vous pouvez les faire précéder d'icônes, ce qui en facilite la lecture et l'utilisation.

Les icônes les plus connues sont probablement l'icône de recherche et l'icône de connexion/compte (personne). Sur l'écran de votre téléphone portable, il n'y a pas autant de place que sur un ordinateur desktop . Dans de nombreux cas, la barre de menu change sur un téléphone et les éléments du menu horizontal sont placés dans un menu déroulant qui peut être activé en cliquant sur l'icône d'un hamburger. Pour que les fonctions de recherche et de connexion / compte restent toujours accessibles, la boîte de recherche est souvent remplacée par une icône de recherche et les textes de connexion / compte sont remplacés par une icône de personne.

Comment ajouter des icônes à votre site web

Le moyen le plus simple est d'ajouter des icônes comme police de caractères. Vous téléchargez la police (nous n'utilisons pas de CDN pour des raisons de confidentialité), vous ajoutez la famille de polices et le tour est joué. Lorsque j'ai lancé ce site web, j'ai choisi Font Awesome. Pourquoi ? J'ai cherché sur Internet des icônes de bootstrap et de nombreuses réponses mentionnant Font Awesome ont été obtenues. Font Awesome propose vraiment un très bel ensemble d'icônes gratuites. Il est facile de les ajouter à vos pages. Par exemple, pour ajouter une icône user, vous devez ajouter le code :

	<i class="fas fa-user"></i>

Une autre façon d'ajouter des icônes est en ligne. Au lieu d'ajouter un code pour sélectionner une icône dans la police Font Awesome , nous ajoutons le code réel de l'icône SVG. Vous pouvez télécharger le code de l'icône SVG sur le site web de la police Font Awesome , le code de l'icône user :

	<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="user" class="svg-inline--fa fa-user  fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z"></path></svg>

Il existe d'autres moyens, mais la plupart d'entre eux vous font perdre la capacité de colorier et d'échelonner. Une belle vue d'ensemble est présentée dans l'article "Utilisation de SVG", voir les liens ci-dessous.

Icônes et temps de chargement des pages

Lorsque vous construisez un site web, l'un des aspects les plus importants est le temps qu'il faut pour qu'une page apparaisse à l'écran. De nombreux moteurs de recherche ont fait du temps de chargement de votre site web un facteur de classement. Chromium Developer Tools dispose d'un bel outil pour mesurer ce temps, appelé "Audits". Il s'agit du programme Lighthouse qui vous donne des notes pour la performance, l'accessibilité, les meilleures pratiques et le référencement. Pour la performance, le programme "First Contentful Paint" est très important.

Lighthouse m'a montré que le chargement et le rendu des fichiers Font Awesome était responsable de près d'une seconde ! Si vous consultez le site web de Font Awesome , vous verrez qu'il y a environ 1500 icônes gratuites dans la police. C'est très bien, mais je n'en utilise que 25.

Comme je voulais réduire le temps de chargement, j'ai envisagé d'utiliser une police d'icône personnalisée. Par exemple, Icomoon, voir les liens ci-dessous, vous permet de créer une police d'icônes avec uniquement les icônes que vous utilisez. C'est très bien, mais j'ai décidé d'opter pour des icônes en ligne car cela évite de charger des fichiers supplémentaires. L'inconvénient est que la taille de la page augmente. Vous trouverez une discussion intéressante sur les aspects de performance dans l'article "Inline SVG vs Icon Fonts [CAGEMATCH]", voir les liens ci-dessous.

Utilisez une macro Jinja pour mettre des icônes sur la page

En pensant aux icônes, c'est probablement une bonne idée de garder à l'esprit que vous voulez changer les icônes demain. Ou même que vous voulez maintenir plusieurs jeux d'icônes. A titre de test, j'ai sélectionné les nouvelles icônes Bootstrap 5 comme second jeu d'icônes. Pour prendre en charge les deux jeux d'icônes, j'ai créé la macro Jinja suivante :

{%- macro icon(icon_name, fill=false, collection=none, inline=false) -%}

	{%- if not collection %}
		{%- set collection = 'fontawesome' -%}
	{%- endif %}

	{%- if collection == 'fontawesome' -%}

		{%- if icon_name in ['angle_up', 'chevron_up'] -%}
				
			{%- if inline -%}
				<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="angle-up" class="svg-inline--fa fa-angle-up fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"></path></svg>
			{%- else -%}
				<i class="fas fa-angle-up"></i>
			{%- endif -%}

		{%- elif icon_name in ['arrow_clockwise', 'redo'] -%}
		...

	{%- endif -%}


	{%- if collection == 'bootstrap5' -%}

		{%- if icon_name in ['angle_up', 'chevron_up'] -%}

			{%- if inline -%}
				<svg class="bi bi-chevron-up" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/></svg>			{%- else -%}
			{%- else -%}

			{%- endif -%}

		{%- elif icon_name in ['arrow_clockwise', 'redo'] -%}
		...

	{%- endif -%}

{%- endmacro -%}

Je peux utiliser cette macro à la fois avec les icônes Font Awesome et Bootstrap 5. En outre, je peux spécifier si je veux l'icône de type de remplissage, et si je veux l'icône SVG en ligne. En modifiant la macro, je peux également afficher l'icône Font Awesome et l'icône Bootstrap 5 pour un contrôle visuel. L'utilisation de cette macro est très simple, dans votre page vous pouvez utiliser :

	{{ icon('home') }} Hoogerheid, NL

Empêcher les icônes identiques en ligne SVG

Un test rapide m'a montré que les icônes en ligne SVG ont effectivement réduit "First Contentful Paint" de près d'une seconde. Génial ! Mais parfois, une icône se trouvait plusieurs fois sur une page. Avec une taille moyenne de 400 à 600 caractères par icône SVG, cela peut avoir un impact sérieux sur le temps de chargement de la page. Un exemple est une section de commentaires où chaque commentaire a une icône de calendrier et une icône @ et où il y a une centaine de commentaires.

Heureusement, il existe un moyen de définir un bloc d'icônes sur une page et de les utiliser plus tard. Pour ce faire, nous utilisons les balises <svg> et <symbol> :

<svg class="d-none">
	<symbol id="icon-angle-up" viewBox="0 0 16 16">
		<title>angle-up</title>
		<path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/>
	</symbol>
	<symbol id="icon-arrow-clockwise" viewBox="0 0 16 16">
		<title>arrow-clockwise</title>
		<path fill-rule="evenodd" d="M3.17 6.706a5 5 0 0 1 7.103-3.16.5.5 0 1 0 .454-.892A6 6 0 1 0 13.455 5.5a.5.5 0 0 0-.91.417 5 5 0 1 1-9.375.789z"/><path fill-rule="evenodd" d="M8.147.146a.5.5 0 0 1 .707 0l2.5 2.5a.5.5 0 0 1 0 .708l-2.5 2.5a.5.5 0 1 1-.707-.708L10.293 3 8.147.854a.5.5 0 0 1 0-.708z"/>
	</symbol>
	...
</svg>

Plus d'informations dans l'article 'SVG 'symbol' a Good Choice for Icons', voir les liens ci-dessous. Nous avons mis ce bloc juste en dessous de la balise <body>. Notez que nous ne mettons que les chemins d'une icône dans la définition. Le titre est facultatif. Pour utiliser l'icône, il suffit de spécifier son identifiant :

	<svg class="svg-icon"><use xlink:href="#icon-calendar"></use>

On peut aussi l'envelopper dans un <span> avec une classe, par exemple pour changer sa taille.

Mise en œuvre

Il y a deux choses qui doivent être modifiées lors de l'ajout d'une nouvelle icône :

  • le jeu d'icônes de symboles
  • la macro icône

En outre, je veux le code HTML que je peux mettre sur une page pour une inspection visuelle rapide. Très vite, je me suis lassé de l'édition et j'ai décidé d'écrire un script qui peut être utilisé pour générer ces données. J'ai également décidé de n'utiliser que les icônes Bootstrap 5, je les ai préférées, elles sont sous licence MIT et ont toutes la même viewBox. Le script a été écrit très rapidement, alors ne me tirez pas dessus :

import sys

class  SVGIcon():

    def __init__(self,
        icon_collection=None,
        icon_name=None,
        icon_id=None,
        svg_class=None,
        svg_fill=None,
        svg_view_box=None,
        svg_path=None,
        symbol_title=None
        ):

        self.icon_collection = icon_collection
        self.icon_name = icon_name
        self.icon_id = icon_id
        self.svg_class = svg_class
        self.svg_fill = svg_fill
        self.svg_view_box = svg_view_box
        self.svg_path = svg_path
        self.symbol_title = symbol_title


def doit():
    
    svg_icons = []

    icon_name2icon_details = {
        'angle_up': {
            'refs': ['angle_up', 'chevron_up'],
            'svg_path': '<path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/>',
        },
        'arrow_clockwise': {
            'refs': ['arrow_clockwise', 'redo', 'resend_mail'],
            'svg_path': '<path fill-rule="evenodd" d="M3.17 6.706a5 5 0 0 1 7.103-3.16.5.5 0 1 0 .454-.892A6 6 0 1 0 13.455 5.5a.5.5 0 0 0-.91.417 5 5 0 1 1-9.375.789z"/><path fill-rule="evenodd" d="M8.147.146a.5.5 0 0 1 .707 0l2.5 2.5a.5.5 0 0 1 0 .708l-2.5 2.5a.5.5 0 1 1-.707-.708L10.293 3 8.147.854a.5.5 0 0 1 0-.708z"/>',
        },
        ...
    }

    icon_collection = 'bootstrap5'
    svg_view_box = "0 0 16 16"
    svg_fill = "currentColor"

    for icon_name in icon_name2icon_details:
        icon_details = icon_name2icon_details[icon_name]
        svg_path = icon_details['svg_path']

        svg_icons.append(SVGIcon(
            icon_collection = icon_collection,
            icon_name = icon_name,
            icon_id = 'icon-'  +  icon_name.replace('_', '-'),
            svg_fill = svg_fill,
            svg_view_box = svg_view_box,
            svg_path = svg_path,
            symbol_title = icon_name.replace('_', '-'),
        ))

    # generate svg symbols list
     symbols_list_lines = []
     symbols_list_lines.append( '<svg class="d-none">' )

    for svg_icon in svg_icons:
         symbols_list_lines.append( "\t"  +  '<symbol id="'  +  svg_icon.icon_id  +  '" viewBox="'  +  svg_icon.svg_view_box  +  '">' )
         symbols_list_lines.append( "\t\t"  +  '<title>'  +  svg_icon.symbol_title  +  '</title>' )
         symbols_list_lines.append( "\t\t"  +  svg_icon.svg_path )
         symbols_list_lines.append( "\t"  +  '</symbol>' )

     symbols_list_lines.append( '</svg>' )
     symbols_list  = "\n".join(symbols_list_lines)

    # generate svg symbols preview
    preview_lines = []
    for svg_icon in svg_icons:
        preview_lines.append( 'abc'  +  ' '  +  '<span class="font-size: 1em;"><svg class="svg-icon">'  +  '<use xlink:href="#'  +  svg_icon.icon_id  +  '"></use></svg>'  +  '</span>'  +  ' '  +  svg_icon.icon_name )

     preview_list  = '<p>'  +  "</p>\n<p>".join(preview_lines)  +  '</p>'

    # generate icon macro code
    icon_macro_lines = []
    first = True        
    for icon_name in icon_name2icon_details:
        icon_details = icon_name2icon_details[icon_name]
        if 'refs' not in icon_details:
            print('refs missing for {}'.format(icon_name))
            sys.exit()
        refs = icon_details['refs']
        # get icon
        found = False
        for svg_icon in svg_icons:
            if svg_icon.icon_name == icon_name:
                found = True
                break
        if not found:
            print('cannot find icon, icon_name = {}'.format(icon_name))
            sys.exit()
                
        if_start = 'elif'
        if first:
            if_start = 'if'
            first = False

        # expand refs
        ref_items = []
        for ref in refs:
            ref_items.append( "'"  +  ref  +  "'" )
            ref_list = '['  +  ', '.join(ref_items)  +  ']'

        icon_macro_lines.append( "\t"  +  '{%- '  +  if_start  +  ' icon_name in '  +  ref_list  +  ' -%}' )
        icon_macro_lines.append( '<span class="font-size: 1em;"><svg class="svg-icon">'  +  '<use xlink:href="#'  +  svg_icon.icon_id  +  '"></use></svg>'  +  '</span>' )

    icon_macro_lines.append( "\t"  +  '{%- endif -%}' )
     icon_macro_list  = "\n".join(icon_macro_lines)

    print('symbols_list:')
    print('{}'.format(symbols_list))
    print('preview_list:')
    print('{}'.format(preview_list))
    print('icon_macro_list:')
    print('{}'.format(icon_macro_list))

Ensuite, il suffit de copier-coller les parties symbols_list, preview_list et icon_macro_list dans le modèle de base, le fichier de prévisualisation et le fichier de la macro.

Quelques problèmes

Dans mes tableaux de listes, les colonnes qui peuvent être triées avaient l'icône de tri attachée au dernier mot du nom de la colonne. Lorsqu'une colonne devient plus petite, je veux que l'icône reste attachée au dernier mot. Cela ne fonctionne plus. Je n'ai pas encore trouvé de solution à ce problème, mais je n'ai pas étudié la question en détail.

Une autre chose est le positionnement vertical des icônes. Il existe des solutions pour cela, l'une d'entre elles est décrite dans "Align SVG Icons to Text and Say Goodbye to Font Icons", voir les liens ci-dessous. Après avoir commencé à utiliser les icônes Bootstrap 5 comme décrit ci-dessus, il est apparu qu'il n'était pas nécessaire de procéder à un positionnement, mais vous pourriez vouloir y jeter un coup d'œil.

Résumé

L'utilisation des icônes SVG permet d'améliorer l'apparence d'un site web et la navigation. Comme je n'utilise que 25 icônes, j'ai décidé d'utiliser la méthode des symboles SVG pour inclure les icônes sur les pages, ce qui ajoute 11,5 Ko supplémentaires. Par rapport à la solution Font Awesome , le 'First Contentful Paint' a diminué de presque une seconde ! Et l'utilisation d'une macro icône Jinja () me donne la possibilité de changer les icônes à un seul endroit au lieu de devoir mettre à jour toutes les pages. Pour l'instant, toutes les icônes sont chargées dans chaque page. À l'avenir, je pourrai optimiser ce processus en n'incluant que les icônes utilisées sur une page.

Liens / crédits

Align SVG Icons to Text and Say Goodbye to Font Icons
https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4

Blog Optimization: Replacing Font Awesome with SVG
https://www.wouterbulten.nl/blog/tech/blog-optimization-replacing-font-awesome-with-svg/

Flask | JINJA 2: render_template_string() with macro imported in context
https://stackoverflow.com/questions/61338841/flask-jinja-2-render-template-string-with-macro-imported-in-context

Icomoon
https://icomoon.io

Inline SVG vs Icon Fonts [CAGEMATCH]
https://css-tricks.com/icon-fonts-vs-svg/

Insert image after each list item
https://stackoverflow.com/questions/946403/insert-image-after-each-list-item

Is there a way to use SVG as content in a pseudo element :before or :after
https://stackoverflow.com/questions/19255296/is-there-a-way-to-use-svg-as-content-in-a-pseudo-element-before-or-after

Lighthouse | Tools for Web Developers | Google Developers
https://developers.google.com/web/tools/lighthouse

SVG 'symbol' a Good Choice for Icons
https://css-tricks.com/svg-symbol-good-choice-icons/

Using SVG
https://css-tricks.com/using-svg/

En savoir plus...

Flask Icons Jinja2

Laissez un commentaire

Commentez anonymement ou connectez-vous pour commenter.

Commentaires

Laissez une réponse

Répondez de manière anonyme ou connectez-vous pour répondre.