The pillars of creation

tagged with Accessibility Frontend Media Razor Sustainability

Introduction

There is an increasing emphasis on making services and products sustainable and driving business processes to ensure they are taking sustainability into account. Whether you’re a developer, agency owner or are involved in the development of websites we can all play our part in being more sustainable as a community by helping to build sustainable websites.

Typically when people think about sustainability, they think about the environment and making sure that they are being more "eco-friendly" or "green". However, sustainability focuses on more generally: "fulfilling the needs of current generations without compromising the needs of future generations, while ensuring a balance between economic growth, environmental care and social well being"

There are therefore multiple different areas that contribute towards being sustainable, best described using the 4 pillars of sustainability:

  • Human
  • Economic
  • Social
  • Environmental

Human

The Human pillar focuses on improving and maintaining human capital by being a member of society and focusing on people both directly or indirectly involved or affected by the products or services we deliver.

Key areas to focus on:

  • Accessibility
  • Ease of content-editing
  • Usability and User Experience
  • Resources
  • Training & Learning Opportunities

Accessibility

By building a website that can be accessed by all, not only are we able to share the content with a larger audience, we’re also creating an inclusive website so all users can use this despite any disabilities that may limit their internet use.

This is commonly overlooked by most developers and agencies, so below are some quick wins that can be implemented into your next Umbraco solution to improve the accessibility.

When building websites, it should be common practice to run a web accessibility tool such as the WAVE tool or WEBAIM tool against each page. This will check through the page to check for common accessibility faults, and give solutions to resolve these. Google Lighthouse also gives an accessibility score for website pages, however this report is not as detailed as some of the other accessibility tools.

Accessibility quick fixes:

  • DO use <h1> tag should be used as the main heading on the page
  • DO NOT skip heading levels
  • DO use HTML landmark elements such as <header>, <aside>, <footer>, <nav>, <main>, <section> etc. to build out an accessible content structure
  • DO use HTML lists e.g. <ol>, <ul> and <dl> to group items similar to each other
  • DO include a descriptive page <title>
  • DO add a language attribute e.g. <html lang="en">
  • DO add a title text property when using an <iframe>
  • DO NOT put informative images as background images
  • DO add alt text to informative and actionable images (use an empty alt attribute on non-descriptive images to make screen readers skip them)
  • DO check a user can navigate through the page using a screen reader
  • DO check the website page using an accessibility tool and resolve any issues

Social

This pillar focuses on the wider communities, which interact with you and the services you offer, this can be through the communities you’re a part of to improve social qualities.

Key areas to focus on:

  • Open source community
  • Recruitment
  • Inclusivity and Equality

Good news ! I’m sure you’re already aware of the Umbraco community and how great it is, well just by sharing knowledge or being friendly in the community you’re helping the community grow and improving the social sustainability of both your personal brand and the Umbraco community.

Environmental

Environmental sustainability focuses on preserving the environment and protection of natural resources.

We can improve our environmental sustainability, through some of the following:

  • Eco Hosting
  • Sustainable Web design
  • Image optimisation
  • Reducing page weight
  • Reducing 3rd party scripts

Eco Hosting

There are a number of different services available that offer Eco-hosting such as Azure and Umbhost.

Both of these services offer a Hosting solution that uses renewable energy to offset the amount of carbon produced through the running of the servers. This helps to reduce the impact on the environment through powering the servers off renewable energy such as wind and solar.

Image Optimisation

Not only is this a big issue for page weight and additional carbon production on a website there is also a massive impact on SEO rankings due to reduced page speeds.

I'm sure you've experienced a website that you've visited only to find the page loads slowly or some images just don't load at all.. frustrating right !

Luckily there's a few different ways we can prevent this…

The first solution is a code solution, which we can add into the website code and that's implementing WEBP images, Lazy Loading and Image Cropper all to ensure the images loaded are of the correct size and format.

WEBP images are preferred by browsers due to them implementing both lossy and lossless compression in order to reduce the image file size as much as possible without affecting the image quality. Implementing this with Image cropper helps to crop the image, so the correct size image is loaded in, this prevents loading a full-width image just for a thumbnail.

Lazy loading ensures that the images are loaded as the user scrolls down the page. The images above the fold, i,e. the images visible to the user, will be loaded initially. The other images on the page below the fold will then be loaded by the browser as the user scrolls to prevent the additional load time when loading the page initially. If a user clicks on the page and then navigates away without viewing the rest of the page, then the additional images below the fold are not loaded and therefore additional carbon is not produced to load them.


public static string GetCropUrlWithFormat(
    this IPublishedContent node,
    Enums.ImageCrops cropAlias,
    Enums.Media format = Enums.Media.None,
    int? quality = null,
    bool useCropDimensions = true,
    ImageCropMode? imageCropMode = null,
    ImageCropAnchor? imageCropAnchor = null)
{
    if (node == null) return null;

    if (node.Url().EndsWith(".svg"))
    {
        return node.Url();
    }

    if (cropAlias == Enums.ImageCrops.NoCrop)
        return node.GetCropUrl(
            furtherOptions: "&format=" + format,
            quality: quality
            );

    switch (format)
    {
        case Enums.Media.WebP:
            var webP = node.GetCropUrl(
                cropAlias: cropAlias.ToString(),
                furtherOptions: "&format=" + format,
                useCropDimensions: useCropDimensions,
                quality: quality,
                imageCropMode: imageCropMode,
                imageCropAnchor: imageCropAnchor);

            if (webP != null) return webP;
            break;
        default:
            var crop = node.GetCropUrl(
                cropAlias: cropAlias.ToString(),
                useCropDimensions: useCropDimensions,
                quality: quality,
                imageCropMode: imageCropMode,
                imageCropAnchor: imageCropAnchor);

            if (crop != null) return crop;
            break;
    }

    return node.Url();
}

public static string GetAltText(this IPublishedContent content, string altTextAlias = "altText")
    => content != null && content.HasValue(altTextAlias) ? content.Value<string>(altTextAlias) : string.Empty;

IPublishedContentExtension for WEBP Images with Image cropper


<picture>
    <source srcset="@Model.HeroImage.GetCropUrlWithFormat(Enums.ImageCrops.Hero, Enums.Media.WebP)" type="image/webp">
    <img src="@Model.HeroImage.GetCropUrlWithFormat(Enums.ImageCrops.Hero)" alt="@Model.HeroImage.GetAltText()">
</picture>

Code to render the WEBP cropped images

Despite this additional development work sometimes this is still not enough to reduce image sizes, especially when massive image files are uploaded by content editors. Well... there are many tools out there such as TinyPNG, which can be used to reduce the file size of an image without damaging the image quality to the human eye. This gives you a much smaller image to serve through Umbraco media and allows you to maximise the performance and minimise the page weight and load time of your site.

Reducing page weight
Another common cause of unnecessary page weight is rendering redundant CSS.

Firstly, when building out the front-end of the website, careful consideration needs to be made around which front-end framework to use e.g. Tailwind, Bootstrap, Foundation, Custom etc.

Although a front-end framework such as Bootstrap CSS greatly reduces the additional development time needed due to the preset styles. It adds lots of additional classes into the CSS, which may never be used on the site.

For example:
With Bootstrap, you're able to choose which features you'd like to import into the base stylesheet. For this you should only choose the classes you need to build the application. This can either be through @import statements when importing through SCSS files or in the Bootstrap website when generating a base Bootstrap CSS file.

With the increasing use of the Grid and Block List Editor this also presents an opportunity to reduce the CSS rendered on each page by only displaying the CSS for the Element Types chosen in the grid. Although this requires a bit of work to set up it can have a massive improvement on page weight and load time.

For this follow these steps:

Step 1: Componentising the front-end code

When building out the front-end for the website the CSS used for each element type should be split out into separate files, this is a very typical way of building out the front-end when using frameworks such as SCSS. These CSS files should be called the same as the alias of the element type.

For any page specific styles these can be included in a CSS file with the DocType alias.

Any styles that are needed throughout the site can be included in a base.css file and this will be rendered on all pages throughout the site.

Step 2: Add the CSS into the solution

Include the CSS files into the solution in the following folder structure:

  • Pages - /css/page/
  • Element Types / Components - /css/components/
  • Base - /css/base.css

Step 3: Add a ViewComponent to iterate through the BlockList

Add a ViewComponent including code to iterate through the BlockList included on the page, this should be called from the master template in the head.


public class RenderCSSViewComponent : ViewComponent
{
    private readonly ISmidgeRequire _smidgeHelper;

    public RenderCSSViewComponent(ISmidgeRequire smidgeHelper)
    {
        _smidgeHelper = smidgeHelper;
    }
    public async Task<IViewComponentResult> InvokeAsync(IPublishedContent model)
    {
        if (model == null) { return Content(string.Empty); }

        if (File.Exists("wwwroot/css/base.css"))
        {
            _smidgeHelper.RequiresCss("~/css/base.css");
        }

        if (!string.IsNullOrWhiteSpace(model?.ContentType?.Alias))
        {
            if (File.Exists(string.Format("wwwroot/css/page/{0}.css", model.ContentType.Alias)))
            {
                _smidgeHelper.RequiresCss(string.Format("~/css/page/{0}.css", model.ContentType.Alias));
            }
        }

        var blockList = model.Value<BlockListModel>("blockList");
        var blocks = new List<string>();

        if (blockList?.Any() != true) { return Content(string.Empty);  }

        foreach (var block in blockList)
        {
            if (block?.ContentUdi == null) { continue; }

            var alias = block?.Content?.ContentType?.Alias;
            if (!string.IsNullOrWhiteSpace(alias) && !blocks.Contains(alias))
            {
                blocks.Add(alias);
                if (File.Exists(string.Format("wwwroot/css/components/{0}.css", alias)))
                {
                    _smidgeHelper.RequiresCss(string.Format("~/css/components/{0}.css", alias));
                }
            }
        }
        return View("~/Views/Partials/RenderCSS.cshtml");
    }
}

Step 4: Render the minified CSS file

@await SmidgeHelper.CssHereAsync(debug: false)

This is of course a very simple implementation of rendering only the necessary CSS for the page, and this can be extended further for more complex implementations and for rendering only the necessary JS too.

Economic

The economic pillar focuses on being profitable over time, through the efficient use of resources. It is crucial that this pillar is met without compromising on the 3 other pillars, so finding a balance is key.

Summary

The above is just an overview of some of the ways we can be more sustainable across the board and how this can benefit both us, the business or clients we work for and also the communities we’re a part of. I hope this helps with understanding more around sustainability and helps to drive decisions when working on future projects.

Thank you for reading, and I wish you all a very Merry Christmas !!


Tech Tip: JetBrains Rider

Check it out here