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

Gebruik van pictogrammen op uw Flask website en verklein 'First Contentful Paint'.

Gebruik een Jinja pictogram macro om pictogrammen op uw pagina's te plaatsen en gebruik <symbol> om pictogrammen één keer te definiëren en meerdere keren op dezelfde pagina te gebruiken.

29 mei 2020
post main image
https://unsplash.com/@codingtim

Er zijn vele soorten vectoriconen. In dit bericht kijk ik alleen naar SVG-iconen, en beperk me tot navigatiepictogrammen, soms ook wel interface-iconen genoemd. Deze iconen zien er niet alleen mooi uit op websites, ze kleuren en schalen ook als lettertypes. En ze zijn zeer functioneel. Stel je een knop voor met de tekst 'Edit' erin. Vervang deze tekst door een potlood-icoon en je krijgt meer ruimte op de pagina terwijl het nog steeds heel duidelijk is wat er gebeurt als je op de knop klikt.

Een ander voorbeeld is de contactpagina. In plaats van een telefoonnummer, een e-mailadres en een bezoekadres alleen als tekst op te geven, kunt u er pictogrammen voor zetten en wordt het makkelijker te lezen en te gebruiken.

De meest bekende iconen zijn waarschijnlijk het zoekicoon en het login/account (persoon) icoon. Op het scherm van uw mobiele telefoon is niet zoveel ruimte als op een desktop computer. In veel gevallen verandert de menubalk op een telefoon en worden de horizontale menu-items in een dropdown menu geplaatst dat kan worden geactiveerd door op een hamburger-icoon te klikken. Om de zoek- en inlog-/accountfuncties altijd toegankelijk te houden, wordt vaak het zoekvak vervangen door een zoekicoon en worden de inlog-/accountteksten vervangen door een persoonscode.

Manieren om pictogrammen toe te voegen aan uw website

De eenvoudigste manier is om iconen als lettertype toe te voegen. U downloadt het lettertype (we gebruiken geen CDN om privacyredenen), voegt de lettertypefamilie toe en u bent klaar. Toen ik deze website begon heb ik gekozen voor Font Awesome. Waarom? Ik heb op het internet gezocht naar bootstrappictogrammen en er waren veel hits met vermelding van Font Awesome. Font Awesome heeft echt een hele mooie set vrije iconen. Het is eenvoudig om ze toe te voegen aan je pagina's. Om bijvoorbeeld een user-icoontje toe te voegen voeg je de code toe:

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

Een andere manier om iconen toe te voegen is inline. In plaats van code toe te voegen om een icoon uit het lettertype Font Awesome te selecteren, voegen we de eigenlijke SVG-icooncode toe. U kunt de SVG-icooncode downloaden van de Font Awesome -website, de code voor de user-icoon:

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

Er zijn meer manieren, maar met de meeste verlies je de mogelijkheid om te kleuren en te schalen. Een mooi overzicht is te vinden in het artikel 'Using SVG', zie onderstaande links.

Iconen en laadtijd van de pagina

Bij het bouwen van een website is een van de belangrijkste aspecten de tijd die nodig is om een pagina op het scherm te laten verschijnen. Veel zoekmachines hebben van de laadtijd van uw website een rangschikkingsfactor gemaakt. Chromium Developer Tools heeft een mooie tool om deze tijd te meten, genaamd 'Audits'. Dit is het Lighthouse programma dat u beoordelingen geeft voor Prestaties, Toegankelijkheid, Best Practices en SEO. Voor prestaties is 'First Contentful Paint' erg belangrijk.

Lighthouse liet me zien dat het laden en renderen van de Font Awesome bestanden bijna een seconde duurde! Als je de Font Awesome website bekijkt zie je dat er zo'n 1500 vrije iconen in het lettertype zitten. Heel mooi, maar ik gebruik er maar 25.

Omdat ik de laadtijd wilde verkorten, heb ik overwogen om een aangepast pictogramlettertype te gebruiken. Bijvoorbeeld, Icomoon, zie onderstaande links, stelt u in staat om een pictogramlettertype te maken met alleen de pictogrammen die u gebruikt. Erg leuk, maar ik heb besloten om te gaan voor inline iconen omdat dit het laden van extra bestanden elimineert. Het nadeel is dat de paginagrootte toeneemt. Een leuke discussie over performance-aspecten is te vinden in het artikel 'Inline SVG vs Icon Fonts [CAGEMATCH]', zie onderstaande links.

Gebruik een Jinja -macro om pictogrammen op de pagina te zetten.

Als je denkt aan pictogrammen, is het waarschijnlijk een goed idee om in gedachten te houden dat je de pictogrammen morgen wilt veranderen. Of zelfs meerdere iconensets wilt onderhouden. Als test heb ik de nieuwe Bootstrap 5 iconen als tweede iconenset geselecteerd. Om beide iconensets te ondersteunen heb ik de volgende Jinja macro gemaakt:

{%- 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 -%}

Ik kan deze macro zowel met Font Awesome als met Bootstrap 5 pictogrammen gebruiken. Daarnaast kan ik aangeven of ik het vultype-icoontje wil en of ik het SVG-icoontje inline wil hebben. Door de macro te wijzigen kan ik ook zowel het pictogram Font Awesome als het pictogram Bootstrap 5 voor visuele inspectie uitvoeren. Het gebruik van deze macro is zeer eenvoudig, in uw pagina kunt u deze gebruiken:

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

Voorkomen van identieke inline SVG-iconen

Een snelle test liet me zien dat inline SVG iconen inderdaad 'First Contentful Paint' met bijna een seconde reduceerden. Geweldig! Maar soms stond een icoontje meerdere malen op een pagina. Met een gemiddelde grootte van 400 - 600 karakters per SVG-icoon kan dit een serieuze impact hebben op de laadtijd van de pagina. Een voorbeeld is een commentaarsectie waarbij elk commentaar een kalender-icoontje en een @-icoontje heeft en er honderd commentaren zijn.

Gelukkig is er een manier om een blok met pictogrammen op een pagina te definiëren en deze later te gebruiken. We doen dit met behulp van de <svg> en <symbol> tags:

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

Meer informatie in het artikel 'SVG 'symbol' a Good Choice for Icons', zie onderstaande links. We zetten dit blok direct onder de <body> tag. Merk op dat we alleen de paden van een icoon in de definitie plaatsen. De titel is optioneel. Om het icoontje te gebruiken hoeven we alleen de id ervan te specificeren:

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

We kunnen het ook in een <span> verpakken met een klasse om bijvoorbeeld de grootte te veranderen.

Uitvoering

Er zijn twee dingen die bewerkt moeten worden bij het toevoegen van een nieuw pictogram:

  • de pictogrammenset
  • het pictogram macro

Daarnaast wil ik HTML-code die ik op een pagina kan zetten voor een snelle visuele inspectie. Al snel werd ik moe van het bewerken en besloot ik een script te schrijven dat gebruikt kan worden om deze gegevens te genereren. Ik besloot ook te gaan voor de Bootstrap 5 iconen alleen, ik vond ze leuker, ze zijn MIT gelicenseerd en hebben allemaal dezelfde viewBox. Het script is zeer snel geschreven, dus schiet me niet neer:

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))

Daarna kopieer ik gewoon de onderdelen symbols_list, preview_list en icon_macro_list in het basissjabloon, het voorbeeldbestand en het macrobestand.

Enkele problemen

In mijn lijsttabellen hebben kolommen die gesorteerd kunnen worden het sort-icoontje bij het laatste woord van de kolomnaam. Als een kolom kleiner wordt, wil ik dat het icoontje bij het laatste woord blijft. Dit werkt niet meer. Ik heb hier nog geen oplossing voor gevonden, maar heb hier niet in detail op ingegaan.

Een ander ding is de verticale positionering van de pictogrammen. Hier zijn oplossingen voor, een daarvan wordt beschreven in 'Align SVG Icons to Text and Say Goodbye to Font Icons', zie onderstaande links. Na het gebruik van de Bootstrap 5 iconen zoals hierboven beschreven, bleek dat het niet nodig was om een positionering te doen, maar dat je er misschien wel naar wilt kijken.

Samenvatting

Het gebruik van SVG-icons zorgt ervoor dat een website er beter uitziet en beter navigeert. Omdat ik slechts 25 iconen gebruik heb ik besloten om de SVG-symbol methode te gebruiken om de iconen op de pagina's op te nemen die een extra 11,5 KB toevoegen. In vergelijking met de Font Awesome -oplossing is de 'First Contentful Paint' bijna een seconde naar beneden gegaan! En het gebruik van een Jinja macro-icoontje() geeft me de flexibiliteit om de icoontjes op één plaats te veranderen in plaats van alle pagina's te moeten updaten. Op dit moment worden alle iconen in elke pagina geladen. In de toekomst kan ik dit optimaliseren door alleen de gebruikte iconen op een pagina op te nemen.

Links / credits

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/

Laat een reactie achter

Reageer anoniem of log in om commentaar te geven.

Opmerkingen

Laat een antwoord achter

Antwoord anoniem of log in om te antwoorden.