Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                

<nav id="navbar">

  <header>Progressive Web Apps</header>
  <ul>
    <li><a class="nav-link" href="#What_is_a_Progressive_Web_App?">What is a Progressive Web App?</a></li>

    <li><a class="nav-link" href="#What_makes_an_app_a_PWA">What makes an app a PWA</a></li>

    <li><a class="nav-link" href="#Is_it_worth_doing_all_that?">Is it worth doing all that?</a></li>

    <li><a class="nav-link" href="#Browser_support">Browser support</a></li>

    <li><a class="nav-link" href="#An_example_application">An example application</a></li>

    <li><a class="nav-link" href="#Architecture_of_an_app">Architecture of an app</a></li>

    <li><a class="nav-link" href="#App_shell">App shell</a></li>

    <li><a class="nav-link" href="#Why_should_I_use_it?">Why should I use it?</a></li>

    <li><a class="nav-link" href="#Being_linkable,_progressive_and_responsive_by_design">Being linkable, progressive and responsive by design</a></li>

    <li><a class="nav-link" href="#Different_concept:_streams">Different concept: streams</a></li>

    <li><a class="nav-link" href="#Structure_of_our_example_application">Structure of our example application</a></li>

    <li><a class="nav-link" href="#The_HTML">The HTML</a></li>

    <li><a class="nav-link" href="#The_CSS">The CSS</a></li>

    <li><a class="nav-link" href="#The_main_app_JavaScript">The main app JavaScript</a></li>

    <li><a class="nav-link" href="#The_service_worker">The service worker</a></li>

    <li><a class="nav-link" href="#The_JavaScript_Data">The JavaScript Data</a></li>

    <li><a class="nav-link" href="#References">References</a></li>

  </ul>
</nav>
<main id="main-doc">
  <section class="main-section" id="What_is_a_Progressive_Web_App?">
    <header>What is a Progressive Web App?</header>
    <article>
      <p>
        PWAs are web apps developed using a number of specific technologies and standard patterns to allow them to take advantage of both web and native app features. </p>
      <p>
        For example, web apps are more discoverable — it's a lot easier and faster to visit a website than install an application, and you can also share web apps via a link. </p>
      <p>
        For example, web apps are more discoverable — it's a lot easier and faster to visit a website than install an application, and you can also share web apps via a link. </p>
      <p>
        On the other hand, native apps are better integrated with the operating system and therefore offer a more seamless experience for the users. You can install a native app so that it works offline, and users love tapping their homescreen icons to easily
        access their favorite apps, rather than navigating to it using a browser. </p>
      <p>
        PWAs give us the ability to create web apps that can enjoy these same advantages. </p>
      <p>
        It's not a brand new concept — such ideas have been revisited many times on the web platform with various approaches in the past. Progressive Enhancement and responsive design already allow us to build mobile friendly websites. Working offline and installing
        apps was possible in the Firefox OS ecosystem a few years ago.</p>
      <p>
        PWAs, however, provide all this and more, without getting rid of any of the existing features that make the web great.</p>
      </artictle>
  </section>
  <section class="main-section" id="What_makes_an_app_a_PWA">
    <header>What makes an app a PWA</header>
    <article>
      <p>
        As we hinted at above, PWAs are not created with a single technology. They represent a new philosophy for building web apps, involving some specific patterns, APIs, and other features. It's not that obvious if a web app is a PWA or not from first glance.
        An app could be considered a PWA when it meets certain requirements, or implements a set of given features: works offline, is installable, is easy to synchronize, can send push notifications, etc.</p>
      <p>
        In addition, there are tools to measure the completeness of an app in percentages. (Lighthouse is currently the most popular one.) By implementing various technological advantages, we can make an app more progressive, thus ending up with a higher Lighthouse
        score. But this is only a rough indicator. </p>
      <p>
        There are some key principles a web app should try to observe to be identified as a PWA. It should be:
      </p>
      <ul>
        <li>
          Discoverable, so the contents can be found through search engines.
        </li>
        <li>
          Installable, so it's available on the device's home screen.
        </li>
        <li>
          Linkable, so you can share it by simply sending a URL.
        </li>
        <li>
          Network independent, so it works offline or with a poor network connection.
        </li>
        <li>
          Progressive, so it's still usable on a basic level on older browsers, but fully-functional on the latest ones.
        </li>
        <li>
          Re-engageable, so it's able to send notifications whenever there's new content available.
        </li>
        <li>
          Responsive, so it's usable on any device with a screen and a browser — mobile phones, tablets, laptops, TVs, fridges, etc.
          <li>
            <li>
              Safe, so the connection between you and the app is secured against any third parties trying to get access to your sensitive data.
            </li>
      </ul>
    </article>
  </section>
  <section class="main-section" id="Is_it_worth_doing_all_that?">
    <header>Is it worth doing all that?</header>
    <article>
      <p>
        Absolutely! With a relatively small amount of effort required to implement the core PWA features, the benefits are huge. For example:
      </p>
      <ul>
        <li>
          A decrease in loading times after the app has been installed, thanks to caching with Service Workers, along with saving precious bandwidth and time. PWAs have near-instantaneous loading (from the second visit).</li>
        <li>
          The ability to update only the content that has changed when an app update is available. In contrast, with a native app, even the slightest modification can force the user to download the entire application again.</li>
        <li>
          A look and feel that is more integrated with the native platform — app icons on the homescreen, apps that run fullscreen, etc.</li>
        <li>
          Re-engaging with users via system notifications and push messages, leading to more engaged users and better conversion rates.</li>
      </ul>
      <p>
        There are many success stories of companies trying the PWA route, opting for an enhanced website experience rather than a native app, and seeing significant measurable benefits as a result. The website PWA Stats shares many case studies that indicate
        these benefits.
      </p>
      <p>
        The best-known success story is probably Flipkart Lite — India's largest e-commerce site rebuilt as a progressive web app in 2015, which resulted in 70% increase in conversions. The AliExpress PWA has also seen much better results than the web or native
        app, with a 104% increase in conversion rates for new users. Given their profit increase, and the relatively low amount of work required for the conversion to PWAs, the advantage is clear.
      </p>
      <p>
        Early stage emerging startups like couponmoto have also started using progressive web apps to drive more consumer engagement, showing that they can help small as well as big companies to (re-)engage users more effectively.
      </p>
      <p>
        You can check the list at pwa.rocks for more examples. Particularly worth mentioning is the hnpwa.com page — this lists an example implementation of the Hacker News website (instead of the usual TodoMVC app), in which you can see the use of various front-end
        frameworks.
      </p>
      <p>
        You can even generate PWAs online using the PWABuilder website.
      </p>
      <p>
        For service worker- and push- specific information, be sure to check the Service Worker Cookbook, a collection of recipes using service workers in modern sites. </p>
      <p>
        It's well worth trying out a PWA approach, so you can see for yourself if it works for your app.
      </p>
    </article>
  </section>
  <section class="main-section" id="Browser_support">
    <header>Browser support</header>
    <article>
      <p>
        As mentioned before, PWAs don't depend on a single API, but rather using various technologies to achieve the goal of delivering the best web experience possible.</p>
      <p>
        The key ingredient required for PWAs is service worker support. Thankfully service workers are now supported on all major browsers on desktop and mobile.</p>
      <p>
        Other features such as Web App Manifest, Push, Notifications, and Add to Home Screen functionality have wide support too. Currently, Safari has limited support for Web App Manifest and Add to Home Screen and no support for web push notifications. However,
        other major browsers support all these features.</p>
      <p>
        Some of these APIs are experimental, with the documentation still in draft, but seeing success stories like those of Flipkart and AliExpress should convince you to try and implement some of the PWA features in your web app already.</p>
      <p>
        Above all you should follow the progressive enhancement rule — use the technologies that provide such enhancements only where they are supported, but still offer the basic functionality of your app if it isn't. This way everybody will be able to use it,
        but those with modern browsers will benefit from PWA features even more.</p>
    </article>
  </section>
  <section class="main-section" id="An_example_application">
    <header>An example application</header>
    <article>
      <p>
        In this series of articles we will examine the source code of a super simple website that lists information about games submitted to the A-Frame category in the js13kGames 2017 competition. You don't have to think about what the actual content on the
        website is — the main point is to learn how to use PWA features in your own projects.</p>
      <p>
        You can find the online version at mdn.github.io/pwa-examples/js13kpwa (also see the source code), which we will be carefully explaining in the next few articles.</p>
      <p>
        Now, let's move to the second part of this series, where we’ll be looking at the structure of our example app.</p>
    </article>
  </section>

  <section class="main-section" id="Architecture_of_an_app">
    <header>Architecture of an app</header>
    <article>
      <p>
        There are two main, different approaches to rendering a website — on the server or on the client. They both have their advantages and disadvantages, and you can mix the two approaches to some degree.</p>
      <ul>
        <li>
          Server-side rendering (SSR) means a website is rendered on the server, so it offers quicker first load, but navigating between pages requires downloading new HTML content. It works great across browsers, but it suffers in terms of time navigating between
          pages and therefore general perceived performance — loading a page requires a new round trip to the server.</li>
        <li>
          Client-side rendering (CSR) allows the website to be updated in the browser almost instantly when navigating to different pages, but requires more of an initial download hit and extra rendering on the client at the beginning. The website is slower on
          an initial visit, but can be faster to navigate.</li>
      </ul>
      <p>
        Mixing SSR with CSR can lead to the best results — you can render a website on the server, cache its contents, and then update the rendering on the client-side as and when needed. The first page load is quick because of the SSR, and the navigation between
        pages is smooth because the client can re-render the page with only the parts that have changed.</p>

      <p>
        PWAs can be built using any approach you like, but some will work better than the others. The most popular approach is the "app shell" concept, which mixes SSR and CSR in exactly the way described above, and in addition follows the "offline first" methodology
        which we will explain in detail in upcoming articles and use in our example application. There is also a new approach involving the Streams API, which we'll mention briefly. </p>
    </article>
  </section>

  <section class="main-section" id="App_shell">
    <header>App shell</header>
    <article>
      <p>
        The App shell concept is concerned with loading a minimal user interface as soon as possible and then caching it so it is available offline for subsequent visits before then loading all the contents of the app. That way, the next time someone visits the
        app from the device, the UI loads from the cache immediately and any new content is requested from the server (if it isn’t available in the cache already).</p>
      <p>
        This structure is fast, and also feels fast as the user sees "something" instantly, instead of a loading spinner or a blank page. It also allows the website to be accessible offline if the network connection is not available.</p>
      <p>
        We can control what is requested from the server and what is retrieved from the cache with a service worker, which will be explained in detail in the next article — for now let's focus on the structure itself.</p>
    </article>
  </section>
  <section class="main-section" id="Why_should_I_use_it?">
    <header>Why should I use it?</header>
    <article>
      <p>
        This architecture allows a website to benefit the most from all the PWA features — it caches the app shell and manages the dynamic content in a way that greatly improves the performance. In addition to the basic shell, you can add other features such
        as add to home screen or push notifications, safe in the knowledge that the app will still work OK if they are not supported by the user's browser — this is the beauty of progressive enhancement.</p>
      <p>
        The website feels like a native app with instant interaction and solid performance while keeping all the benefits of the web.</p>
    </article>
  </section>
  <section class="main-section" id="Being_linkable,_progressive_and_responsive_by_design">
    <header>Being linkable, progressive and responsive by design</header>
    <article>
      <p>
        It's important to remember the PWA advantages and keep them in mind when designing the application. The app shell approach allows websites to be:</p>
      <ul>
        <li>
          Linkable: Even though it behaves like a native app, it is still a website — you can click on the links within the page and send a URL to someone if you want to share it.</li>
        <li>
          Progressive: Start with the "good, old basic website” and progressively add new features while remembering to detect if they are available in the browser and gracefully handle any errors that crop up if support is not available. For example, an offline
          mode with the help of service workers is just an extra trait that makes the website experience better, but it's still perfectly usable without it.</li>
        <li>
          Responsive: Responsive web design also applies to progressive web apps, as both are mainly for mobile devices. There are so many varied devices with browsers — it's important to prepare your website so it works on different screen sizes, viewports or
          pixel densities, using technologies like viewport meta tag, CSS media queries, Flexbox, and CSS Grid.</li>
      </ul>
    </article>
  </section>
  <section class="main-section" id="Different_concept:_streams">
    <header>Different concept: streams</header>
    <article>
      <p>
        An entirely different approach to server- or client-side Rendering can be achieved with the Streams API. With a little help from service workers, streams can greatly improve the way we parse content.</p>
      <p>
        The app shell model requires all the resources to be available before the website can start rendering. It's different with HTML, as the browser is actually streaming the data already and you can see when the elements are loaded and rendered on the website.
        To have the JavaScript "operational", however, it has to be downloaded in its entirety.</p>
      <p>
        The Streams API allows developers to have direct access to data streaming from the server — if you want to perform an operation on the data (for example, adding a filter to a video), you no longer need to wait for all of it to be downloaded and converted
        to a blob (or whatever) — you can start right away. It provides fine-grained control — the stream can be started, chained with another stream, cancelled, checked for errors, and more.</p>
      <p>
        In theory, streaming is a better model, but it's also more complex, and at the time of writing (March 2018) the Streams API is still a work-in-progress and not yet fully available in any of the major browsers. When it is available, it will be the fastest
        way of serving the content — the benefits are going to be huge in terms of performance.</p>
      <p>
        For working examples and more information, see the Streams API documentation.</p>
    </article>
  </section>
  <section class="main-section" id="Structure_of_our_example_application">
    <header>Structure of our example application</header>
    <article>
      <p>
        The js13kPWA website structure is quite simple: it consists of a single HTML file (index.html) with basic CSS styling (style.css), and a few images, scripts, and fonts. The folder structure looks like this: </p>
      <img src="https://mdn.mozillademos.org/files/15925/js13kpwa-directory.png" alt="folder structure">
    </article>
  </section>

  <section class="main-section" id="The_HTML">
    <header>The HTML</header>
    <article>
      <p>
        From the HTML point of view, the app shell is everything outside the content section:</p>

      <pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
	&lt;meta charset="utf-8"&gt;
	&lt;title&gt;js13kGames A-Frame entries&lt;/title&gt;
	&lt;meta name="description" content="A list of A-Frame entries submitted to the js13kGames 2017 competition, used as an example for the MDN articles about Progressive Web Apps."&gt;
	&lt;meta name="author" content="end3r"&gt;
	&lt;meta name="theme-color" content="#B12A34"&gt;
	&lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
	&lt;meta property="og:image" content="icons/icon-512.png"&gt;
	&lt;link rel="shortcut icon" href="favicon.ico"&gt;
	&lt;link rel="stylesheet" href="style.css"&gt;
	&lt;link rel="manifest" href="js13kpwa.webmanifest"&gt;
	&lt;script src="data/games.js" defer&gt;&lt;/script&gt;
	&lt;script src="app.js" defer&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header&gt;
	&lt;p&gt;&lt;a class="logo" href="http://js13kgames.com"&gt;&lt;img src="img/js13kgames.png" alt="js13kGames"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/header&gt;
&lt;main&gt;
	&lt;h1&gt;js13kGames A-Frame entries&lt;/h1&gt;
	&lt;p class="description"&gt;List of games submitted to the &lt;a href="http://js13kgames.com/aframe"&gt;A-Frame category&lt;/a&gt; in the &lt;a href="http://2017.js13kgames.com"&gt;js13kGames 2017&lt;/a&gt; competition. You can &lt;a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa"&gt;fork js13kPWA on GitHub&lt;/a&gt; to check its source code.&lt;/p&gt;
	&lt;button id="notifications"&gt;Request dummy notifications&lt;/button&gt;
	&lt;section id="content"&gt;
		// Content inserted in here
	&lt;/section&gt;
&lt;/main&gt;
&lt;footer&gt;
	&lt;p&gt;© js13kGames 2012-2018, created and maintained by &lt;a href="http://end3r.com"&gt;Andrzej Mazur&lt;/a&gt; from &lt;a href="http://enclavegames.com"&gt;Enclave Games&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>

      <p>
        The <code>&lt;head&gt;</code></a> section contains some basic info like title, description and links to CSS, web manifest, games content JS file, and app.js — that's where our JavaScript application is initialized. The <code>&lt;body&gt;</code>        is split into the <code>&lt;header&gt;</code><code>&lt;main&gt;</code><code>&lt;footer&gt;</code> (copy and links).</p>

      <p>The app's only job is to list all the A-Frame entries from the js13kGames 2017 competition. As you can see it is a very ordinary, one page website — the point is to have something simple so we can focus on the implementation of the actual PWA features.</p>
    </article>
  </section>

  <section class="main-section" id="The_CSS">
    <header>The CSS</header>
    <article>

      <p>The CSS is also as plain as possible: it uses <code>@font-face</code> to load and use a custom font, and it applies some simple styling of the HTML elements. The overall approach is to have the design look good on both mobile (with a responsive
        web design approach) and desktop devices.
      </p>
    </article>
  </section>
  <section class="main-section" id="The_main_app_JavaScript">
    <header>The main app JavaScript</header>
    <article>
      <p>
        The app.js file does a few things we will look into closely in the next articles. First of all it generates the content based on this template</p>
      <pre class="brush: js">var template = "&lt;article&gt;\n\
    &lt;img src='data/img/SLUG.jpg' alt='NAME'&gt;\n\
    &lt;h3&gt;#POS. NAME&lt;/h3&gt;\n\
    &lt;ul&gt;\n\
    &lt;li&gt;&lt;span&gt;Author:&lt;/span&gt; &lt;strong&gt;AUTHOR&lt;/strong&gt;&lt;/li&gt;\n\
    &lt;li&gt;&lt;span&gt;Twitter:&lt;/span&gt; &lt;a href='https://twitter.com/TWITTER'&gt;@TWITTER&lt;/a&gt;&lt;/li&gt;\n\
    &lt;li&gt;&lt;span&gt;Website:&lt;/span&gt; &lt;a href='http://WEBSITE/'&gt;WEBSITE&lt;/a&gt;&lt;/li&gt;\n\
    &lt;li&gt;&lt;span&gt;GitHub:&lt;/span&gt; &lt;a href='https://GITHUB'&gt;GITHUB&lt;/a&gt;&lt;/li&gt;\n\
    &lt;li&gt;&lt;span&gt;More:&lt;/span&gt; &lt;a href='http://js13kgames.com/entries/SLUG'&gt;js13kgames.com/entries/SLUG&lt;/a&gt;&lt;/li&gt;\n\
    &lt;/ul&gt;\n\
&lt;/article&gt;";
var content = '';
for(var i=0; i&lt;games.length; i++) {
    var entry = template.replace(/POS/g,(i+1))
        .replace(/SLUG/g,games[i].slug)
        .replace(/NAME/g,games[i].name)
        .replace(/AUTHOR/g,games[i].author)
        .replace(/TWITTER/g,games[i].twitter)
        .replace(/WEBSITE/g,games[i].website)
        .replace(/GITHUB/g,games[i].github);
    entry = entry.replace('&lt;a href=\'http:///\'&gt;&lt;/a&gt;','-');
    content += entry;
};
document.getElementById('content').innerHTML = content;</pre>

      <p>Next, it registers a service worker:</p>

      <pre class="brush: js">if('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/pwa-examples/js13kpwa/sw.js');
};</pre>

      <p>The next code block requests permission for notifications when a button is clicked:</p>

      <pre class="brush: js">var button = document.getElementById("notifications");
button.addEventListener('click', function(e) {
    Notification.requestPermission().then(function(result) {
        if(result === 'granted') {
            randomNotification();
        }
    });
});</pre>

      <p>The last block creates notifications that display a randomly-selected item from the games list:</p>

      <pre class="brush: js">function randomNotification() {
    var randomItem = Math.floor(Math.random()*games.length);
    var notifTitle = games[randomItem].name;
    var notifBody = 'Created by '+games[randomItem].author+'.';
    var notifImg = 'data/img/'+games[randomItem].slug+'.jpg';
    var options = {
        body: notifBody,
        icon: notifImg
    }
    var notif = new Notification(notifTitle, options);
    setTimeout(randomNotification, 30000);
}</pre>
    </article>
  </section>
  <section class="main-section" id="The_service_worker">
    <header>The service worker</header>
    <article>
      <p>
        The last file we will quickly look at is the service worker: sw.js — it first imports data from the games.js file:</p>
      <pre class="brush: js">self.importScripts('data/games.js');</pre>
      <p>
        Next, it creates a list of all the files to be cached, both from the app shell and the content:</p>
      <pre class="brush: js">var cacheName = 'js13kPWA-v1';
var appShellFiles = [
  '/pwa-examples/js13kpwa/',
  '/pwa-examples/js13kpwa/index.html',
  '/pwa-examples/js13kpwa/app.js',
  '/pwa-examples/js13kpwa/style.css',
  '/pwa-examples/js13kpwa/fonts/graduate.eot',
  '/pwa-examples/js13kpwa/fonts/graduate.ttf',
  '/pwa-examples/js13kpwa/fonts/graduate.woff',
  '/pwa-examples/js13kpwa/favicon.ico',
  '/pwa-examples/js13kpwa/img/js13kgames.png',
  '/pwa-examples/js13kpwa/img/bg.png',
  '/pwa-examples/js13kpwa/icons/icon-32.png',
  '/pwa-examples/js13kpwa/icons/icon-64.png',
  '/pwa-examples/js13kpwa/icons/icon-96.png',
  '/pwa-examples/js13kpwa/icons/icon-128.png',
  '/pwa-examples/js13kpwa/icons/icon-168.png',
  '/pwa-examples/js13kpwa/icons/icon-192.png',
  '/pwa-examples/js13kpwa/icons/icon-256.png',
  '/pwa-examples/js13kpwa/icons/icon-512.png'
];
var gamesImages = [];
for(var i=0; i&lt;games.length; i++) {
  gamesImages.push('data/img/'+games[i].slug+'.jpg');
}
var contentToCache = appShellFiles.concat(gamesImages);</pre>
      <p>
        The next block installs the service worker, which then actually caches all the files contained in the above list:</p>
      <pre class="brush: js">self.addEventListener('install', function(e) {
  console.log('[Service Worker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[Service Worker] Caching all: app shell and content');
      return cache.addAll(contentToCache);
    })
  );
});</pre>
      <p>
        Last of all, the service worker fetches content from the cache if it is available there, providing offline functionality:</p>
      <pre class="brush: js">self.addEventListener('fetch', function(e) {
  e.respondWith(
    caches.match(e.request).then(function(r) {
      console.log('[Service Worker] Fetching resource: '+e.request.url);
      return r || fetch(e.request).then(function(response) {
        return caches.open(cacheName).then(function(cache) {
          console.log('[Service Worker] Caching new resource: '+e.request.url);
          cache.put(e.request, response.clone());
          return response;
        });
      });
    })
  );
});</pre>
    </article>
  </section>

  <section class="main-section" id="The_JavaScript_Data">
    <header>The JavaScript Data</header>
    <article>
      <p>
        The games data is present in the data folder in a form of a JavaScript object (games.js):</p>

      <pre class="brush: js">var games = [
    {
        slug: 'lost-in-cyberspace',
        name: 'Lost in Cyberspace',
        author: 'Zosia and Bartek',
        twitter: 'bartaz',
        website: '',
        github: 'github.com/bartaz/lost-in-cyberspace'
    },
    {
        slug: 'vernissage',
        name: 'Vernissage',
        author: 'Platane',
        twitter: 'platane_',
        website: 'github.com/Platane',
        github: 'github.com/Platane/js13k-2017'
    },
// ...
    {
        slug: 'emma-3d',
        name: 'Emma-3D',
        author: 'Prateek Roushan',
        twitter: '',
        website: '',
        github: 'github.com/coderprateek/Emma-3D'
    }
];</pre>

      <p>Every entry has its own image in the data/img folder. This is our content, loaded into the content section with JavaScript.</p>
    </article>
  </section>
  <section class="main-section" id="References">
    <header>References</header>
    <article>
      <ul>
        <li>
          All documentation on thia page is copied from
          <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Introduction" target="_blank">MDN web docs</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/App_structure" target="_blank">MDN Progressive Web Apps</a>
        </li>
      </ul>
    </article>
  </section>
</main>
              
            
!

CSS

              
                html,
body {
  min-width: 290px;
  color: #4d4e53;
  background-color: #ffffff;
  font-family: "Open Sans", Arial, sans-serif;
  line-height: 1.5;
}
#navbar {
  position: fixed;
  min-width: 290px;
  top: 0px;
  left: 0px;
  width: 300px;
  height: 100%;
  border-right: solid;
  border-color: rgba(0, 22, 22, 0.4);
}

header {
  color: black;
  margin: 10px;
  text-align: center;
  font-size: 1.8em;
  font-weight: thin;
}

#main-doc header {
  text-align: left;
  margin: 0px;
}
#navbar ul {
  height: 88%;
  padding: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

#navbar li {
  color: #4d4e53;
  border-top: 1px solid;
  list-style: none;
  position: relative;
  width: 100%;
}

#navbar a {
  display: block;
  padding: 10px 30px;
  color: #4d4e53;
  text-decoration: none;
  cursor: pointer;
}

#main-doc {
  position: absolute;
  margin-left: 310px;
  padding: 20px;
  margin-bottom: 110px;
}
.main-section { 
 border: solid;
}

section li {
  margin: 15px 0px 0px 20px;
}

code {
  display: block;
  text-align: left;
  white-space: pre;
  position: relative;
  word-break: normal;
  word-wrap: normal;
  line-height: 2;
  background-color: #f7f7f7;
  padding: 15px;
  margin: 10px;
  border-radius: 5px;
}


@media only screen and (max-width: 815px) {
  /* For mobile phones: */
  #navbar ul {
    border: 1px solid;
    height: 207px;
  }

  #navbar {
    background-color: white;
    position: absolute;
    top: 0;
    padding: 0;
    margin: 0;
    width: 100%;
    max-height: 275px;
    border: none;
    z-index: 1;
    border-bottom: 2px solid;
  }

  #main-doc {
    position: relative;
    margin-left: 0px;
    margin-top: 270px;
  }
}

@media only screen and (max-width: 400px) {
  #main-doc {
    margin-left: -10px;
  }

  code {
    margin-left: -20px;
    width: 100%;
    padding: 15px;
    padding-left: 10px;
    padding-right: 45px;
    min-width: 233px;
  }
}

              
            
!

JS

              
                
              
            
!
999px

Console