Search code examples
performancefrontendflagscountry

What is the best performant way to show country flag icons on a web page?


Imagine a website with >100k daily visitors using any platform worldwide... As part of the design you need to show the country flag, prepending some information (product origin, phone number, office/shop/warehouse location, etc.)

What is the best way to do this and to keep users (e.g. Lighthouse score) and developers (proud of their results) happy at the same time?

Note, we can adapt any solution to our stack, just curious what is the best choice which can be done without benchmarking and why it is so? Typically, we can have a dozen of flags visible. However, if we have a product from a new country, it should be not that hard to extend the flag set...

Few options that can be used (for ease of comparison I stick to 16px flag width, for devs it would be nice to have an option inserting needed height. There are also a number of flags with complex graphics, I've checked KZ for example) :

  1. *.png sprite with CSS selector rules ~(50kB png + 10kB css) for 16px height
  2. *.png sprite with JS selector ~27kB png for 16px + 0.5kB JS(before minification and compression)
  3. React way ~1.3MB bundle, uses svg inline. However, e.g. kz.svg is ~10kB - is it optimized somehow for 16px width in production?
  4. Vue way kz.svg is optimized to be and icon ~1kB.
  5. Bootstrap way kz flag looks good enough
  6. Emoji way just few bytes for any flag, may look a bit different on different platforms. Seems to need a fallback solution for MS Windows
  7. For svg solutions you might also want to consider SVGO minification of svg images
  8. Lazy-loading is already implemented and can be used if needed.
  9. Not sure, but the best way may depend on if we use SPA, PWA, SSG, SSR, etc.

Solution

  • Best way differs based on what you are looking for.

    I would consider ease of development, relatively good performance and ease of refactoring and expansion as worthy metrics.

    Considering the metrics my suggestion is having an object with country codes as keys for nested objects including a link to image of the flag for different resolutions (could be one in the beginning) with webp format. WEBP has around 97% browser support as of today, and it will only grow further, if you are thinking about that 3%, you might want to keep using png.

    Sample

    {
    "uk":{
        "16":"/static/flags/16/uk.webp"
      }
    }
    

    Also remember to lazy-load flags in the webpage.

    I would also make sure that server is sending proper caching headers to the browser and CDN you're using (check the difference of maxage and s-maxage).

    If you want to take things one level ahead, you can use your service worker to cache flags permanently.

    This might not be the most efficient way on the paper but can give you the good enough result and help you avoid micro optimization hell.

    Now in this answer i assumed there is not going to be hundreds of flags visible to user in first page load. if that is the case using sprites is the way to go.