Powering your website with Accelerated Mobile Pages (AMP)
Aug. 19, 2019
--
AMP S

Powering your website with Accelerated Mobile Pages (AMP)

Today's web admins are all about site performance, especially on mobile. Site performance on mobile is something important to take into account since it will boost your conversion rate, session duration and even your ranking in web searches.

According to recent research, more than half of your visitors will leave your site if it takes longer than three seconds to load. This will mean more than half of your visitors won't see what you have to offer if your web pages are slow!

What does all of this have to do with AMP?

Well, AMP solves the performance problem on mobile, while at the same time providing a framework for delivering engaging, media-rich, and lightning-fast web pages. AMP means Accelerated Mobile Pages.

An AMP page won't be faster than a hand-tooled page if the latter is really well optimised. But AMP is about implementing best practices so anyone can have faster than average webpages.

How does it improve performance?

By constraining the HTML, CSS, and JavaScript that you can use in your web pages, along with optimised resource management and smart caching.

HTML-based, AMP pages will run in any web browser, out of the box. Additionally, AMP-HTML is designed so that it can also be served from the AMP Cache, and when it is, further optimisations can be automatically applied.

The AMP-JS runtime calculates page size and converts your custom AMP-HTML tags into HTML that the browser understands. It also assumes control of the loading of resources from the browser, so that it can prioritise resources that are likely to be viewed by the user.

When AMP pages are served from the cache, they can be optimised even further. These optimisations include:

  • Reducing page size by resizing images to match the user's resolution, minification of HTML and CSS.

  • Reducing HTTP requests by inlining images and CSS.

  • Reducing page load time by preloading components and pre-rendering web pages in the background.

Is AMP limited to newspapers and blogs?

AMP isn't limited to static text and blog type pages: rich and interactive pages can also be built. AMP pages can include animated menus, accordions, carousels, image galleries, light boxes, embedded videos, and more. They also support analytics and ad providers.

There are some big names like ebay using AMP for e-commerce, including a horizontally scrolling carousel that is used to promote products.

AMP has features that are enough to create shopping carts, forms, lightboxes, search and dynamic listing, etc.

Do I really need AMP?

AMP is just another distribution format, but to maximise your reach you might need to use as many channels as possible.

And even if your website is already tuned to perform really well you can still take advantage of performance gains via the AMP Cache and its instant pre-rendering.

Additionally, Google, Bing and Baidu are already indexing and promoting AMP pages in their search results.

Using AMP with a CMS: Magnolia

If you already have a website running on Magnolia or even if you are thinking of creating a website with Magnolia in the future, there are big chances you will need a mobile version of your site and possibly an AMP version of it.

AMP templates

The main thing you need is templates for these AMP pages, since AMP is slightly different from standard HTML. So at the very least you will need a standard page template and some component templates.

You can use as a base a light module that is already available from the community on npmjs which will provide you a basic page template with all required AMP tags, plus two components for adding rich text and images to your page.

In this post I will show you a standard page template with a similar structure and resources as the Travel Standard page template in Magnolia's travel demo.

Standard page template

Lets start with the main AMP layout:

standard.ftl

JavaScript
  <!doctype html>
<html amp lang="${cmsfn.language()}">
<head>
    [@cms.page /]

    [@cms.area name="htmlHeader"/]

</head>
<body>

      [@cms.area name="navigation"/]

      [@cms.area name="main"/]

</body>
</html>

Notice the code is the same as a traditional HTML page but additionally including an "amp" attribute. The main difference will be inside the head tags though:

htmlHeader.ftl

JavaScript
  <meta charset="utf-8">
<!-- include dynamically from theme or make templating function for it -->
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-sidebar" src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js"></script>
<script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<title>${content.title!}</title>

[#if content.htmlPage?has_content]
    [#assign htmlLink = cmsfn.link(cmsfn.contentById(content.htmlPage))]
<link rel="canonical" href="${htmlLink}" />
[/#if]
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>


<style amp-custom>
    [#include "/travel-demo-amp/webresources/css/styles.css"]
    [#include "/travel-demo-amp/webresources/css/sidebar.css"]
</style>

There are some things like the link rel=cannonical and css files that will be explained further in sections below.

The navigation area will also be a bit different, since it's using the amp-sidebar extended component (included as a external script in the header).

navigation.ftl

JavaScript
  [#include "/mtk/templates/macros/navigation.ftl"]
[#assign navigationRootPage = navfn.rootPage(content)!]

<header class="headerbar">
    <div role="button" on="tap:sidebar1.toggle" tabindex="0" class="hamburger">☰</div>
    <a href="#">
        <amp-img class="home-button" src="${ctx.contextPath}/.resources/travel-demo-theme/img/logo-white.png" width="210" height="30"></amp-img>
    </a>
    <div class="site-name">${content.title!}</div>
</header>

<amp-sidebar id="sidebar1" layout="nodisplay" side="right">
    <div role="button" aria-label="close sidebar" on="tap:sidebar1.toggle" tabindex="0" class="close-sidebar">✕</div>
[@navigation navParentItem=navigationRootPage depth=1 expandAll=true navClass="sidebar" /]

</amp-sidebar>

As you can see, the area is using mtk and navigation templating functions so vey little code is needed to have a working navigation sidebar:

website-powering-amp1

Finally lets take a look at the template definition:

standard.yaml

JavaScript
  title: (AMP) Travel Standard
templateScript: /travel-demo-amp/templates/pages/standard.ftl
renderType: freemarker
dialog: travel-demo-amp:pages/standard
visible: true
areas:
  htmlHeader:
    createAreaNode: false
    renderType: freemarker
    templateScript: /travel-demo-amp/templates/pages/areas/htmlHeader.ftl
    type: noComponent
  navigation:
    createAreaNode: false
    renderType: freemarker
    templateScript: /travel-demo-amp/templates/pages/areas/navigation.ftl
    type: noComponent
  main:
    templateScript: /travel-demo/templates/pages/areas/contentContainer.ftl
    type: list
    parameters:
      cssClass: container
    availableComponents:
      jumbotron:
        id: travel-demo:components/jumbotron
      linkList:
        id: travel-demo:components/linkList
      teaser:
        id: travel-demo:components/teaser

As you can see, the definition is very similar to the travel's demo standard page definition. It's even using some of the travel components. This is possible because AMP accepts most HTML standard tags, so jumbotron, linkList and teaser (with no image) can be used.

Video component template

Standard HTML video tag is forbidden in AMP, so AMP provides its own amp-video tag. Lets see how can this be implemented in a template:

video.ftl

JavaScript
  [#-------------- INCLUDE AND ASSIGN PART --------------]
[#include "/mtk/templates/includes/init.ftl"]

[#-- CSS default --]
[#if !divClass?has_content]
    [#assign divClass = "video-container"]
[/#if]

[#assign layout = "layout='responsive'"]

[#assign video = damfn.getAsset(content.source)]

[#assign videoTitle = ""]
[#if video.title?has_content]
    [#assign videoTitle = video.title]
[/#if]

[#assign assetType = video.mimeType]
[#assign videoSrc = video.link]

[#if content.assetposter?has_content]
    [#assign assetPoster = damfn.getAsset(content.assetposter)!]
    [#if assetPoster?has_content]
        [#assign poster = 'poster="${assetPoster.link}"']
    [/#if]
[/#if]


[#-------------- RENDERING PART --------------]
[#-- Rendering: video item --]
<div ${divID!} class="${divClass}">
    <amp-video width="${content.width!480}" height="${content.height!270}" ${layout!} ${poster!} ${content.autoplay?string("autoplay","")} ${content.controls?string("controls","")} >
        <source src="${videoSrc}" type="${assetType}">
    </amp-video>
</div><!-- end ${divClass} -->

Where the dialog is:

video.yaml

JavaScript
  form:
  tabs:
    - name: tabMain
      fields:
        - name: source
          required: true
          class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
          targetWorkspace: dam
          appName: assets
          identifierToPathConverter:
            class: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator
          contentPreviewDefinition:
            contentPreviewClass: info.magnolia.dam.app.ui.field.DamFilePreviewComponent
        - name: autoplay
          class: info.magnolia.ui.form.field.definition.CheckboxFieldDefinition
          defaultValue: false
          type: Boolean
        - name: controls
          class: info.magnolia.ui.form.field.definition.CheckboxFieldDefinition
          defaultValue: true
          type: Boolean
        - name: poster
          class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
          targetWorkspace: dam
          appName: assets
          identifierToPathConverter:
            class: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator
          contentPreviewDefinition:
            contentPreviewClass: info.magnolia.dam.app.ui.field.DamFilePreviewComponent
        - name: width
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          required: true
          label: Width
        - name: height
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          required: true
          label: Height
 
actions:
  commit:
    class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
  cancel:
    class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition

Another important forbidden tag is the img tag but this component is already provided by the npm module mentioned before.

CSS styles

In AMP, you can't use external css files for styling your webpage. This means you need to add inline styles with the style amp-custom tag. You may have noticed this was already included in the standard page template:

standard.ftl

JavaScript
  <style amp-custom>
    [#include "/travel-demo-amp/webresources/css/styles.css"]
    [#include "/travel-demo-amp/webresources/css/sidebar.css"]
</style>

The content of the css files manually included contains standard css code with an exception: You need to remove any !important qualifier inside your styling. There are some other restrictions listed here.

Using similar styles as the travel demo, you can achieve an AMP version of the about page:

website-powering-amp2

Link rel tags

When you create an AMP version of an already-existing website, both should be linked.

This means that every HTML page will need a link to the matching AMP page:

htmlHeader-amp.ftl

JavaScript
  <link rel="amphtml" href="${ampLink}">  

Additionally the AMP page needs to link the matching HTML page with a canonical link:

htmlHeader.ftl

JavaScript
  <link rel="canonical" href="${htmlLink}">  

These could be configured manually by a dialog field or dynamically obtained from page variants. We will explain further in the next section.

One or multiple trees

There are basically 2 ways of providing AMP pages of your website:

  • Different trees with different layouts/templates/components. One tree contains HTML pages and the other tree contains AMP pages only. This way can be used when you have a rich website for desktop/mobile and a another website, possibly with simpler structure for AMP distribution on search engines. This way could be used, for example, by e-commerce or custom made websites in AMP.

  • One single tree with only one structure for all channels of distribution, which means HTML for desktop, HTML for mobile and AMP when needed. This way can be used when only few pages of your website need AMP distribution. This is commonly used by newspapers where only the news detail page has an "AMP variant". This will also apply with any other kind of page which is serving different contents, like news, products, etc.

For the first case, different trees, you just need a field in the page's dialog to link the AMP version of the page. For the second case, you can use personalisation variants to set this automagically.

Using personalisation for serving AMP pages

Personalisation is used to serve different versions of a page to the user based on traits. This mechanism can be easily used for serving AMP versions of an HTML page in a single tree website if you use the user's device as a trait and create a variation for smartphone & tablet audience.

Magnolia already provides a module for device detection so this trait can be easily implemented, but if you don't want or know how to make custom traits, you can find a device trait module here.

Once you have traits for smartphone/tablet, it's as easy as creating a variation of your page using "Any" of these traits:

website-powering-amp3

And then changing the template of the page to an AMP template:

website-powering-amp4

Finally, you might need to change your page contents if not-allowed elements like image or video are present. In this case we will remove the video component:

website-powering-amp5

Add an amp video component instead:

website-powering-amp6

And simplify the layout by removing the columns:

website-powering-amp7

Notice that you don't need to worry about internal links like "Our Company" since this page could also have an AMP variant and the link won't need to be changed: personalization will take care of serving the right version according to the user's device.

Travel demo in AMP

Finally, here you can find a module implementing the strategies described in this article in order to have AMP versions of the travel demo. (Note: this module is just a POC and shouldn't be used as it is for real projects.)

Über den autor

Edwin Guilbert

Consulting Manager, Magnolia Spain

Edwin Guilbert is a Consulting Manager at Magnolia in Madrid, Spain. He leads the Services team of Spain and he also acts as a solutions architect. He joined Magnolia in 2014, having worked almost 10 years in consultancy as an architect and functional analyst. He regularly trains developers worldwide as he creates and conducts custom on-site workshops at client locations. He is also constantly involved in pre-sales work, carrying out demos and POC developments for pre-sales.