The Secrets of Web Design Performance

the art of performance
Paul Li

About me

Paul Li
HTML / CSS / JavaScript / ActionScript

work @
  • Yahoo!

facebook:
http://www.facebook.com/mei.studio.li

Agenda

  • Requests
  • DOM
  • CSS
  • JavaScript
  • Navigation Timing
  • Web Storage
  • Pre Party
  • Q & A
  • References

Start you Engine

Use browser devTool

We can use some front end performance test site or browser extension. Such as WebPageTest, yslow...etc.

There is a more convenient way for us to test. Wonder what that is ? Yes. It's browser native devTool. All we need to do is just turn it on.

The following are test tool links:

Chrome devTool

Firefox devTool

IE devTool

devTool

Requests

Requests

Requests is the most expensive cost for pege render. That's why almost every performance tuning rules will ask you reduce the total requests first.


request detail

Avoid 404 response

Make sure all request we send can get response as soon as possible and avoid 404 response happen.

One more thing we need to consider is favicon setting. It should be place in root, such as Yahoo Auction - favicon.

Or place it with the following html code.

<link rel="shortcut icon" href="/img/favicon.ico">

HTML Structure

<html>
<head>
    <link rel="stylesheet" href="a.css">
    <link rel="stylesheet" href="b.css">
    <link rel="stylesheet" href="c.css">
    <link rel="stylesheet" href="d.css">
    <script src="jquery.js"></script>
    <script src="yui.js"></script>
    <script src="prototype.js"></script>
    <script src="vanilla.js"></script>
</head>
<body>
......
</body>
</html>

Merge CSS files

According Page flow, we can sort same flow pages' CSS. Then merge them into 1 file to reduce request amount.


<link rel="stylesheet" href="a.css">
<link rel="stylesheet" href="b.css">
<link rel="stylesheet" href="c.css">
<link rel="stylesheet" href="d.css">

merge above into one file


<link rel="stylesheet" href="combo.css">

checkout flow - cart

checkout flow - ship fill

checkout flow - order complete

Merge JavaScript files

According Page flow, we can sort same flow pages' JavaScript. Then merge them into 1 file to reduce request amount.


<script src="shoppingCart.js">
<script src="fillShip.js">
<script src="checkout.js">
<script src="orderComplete.js">

merge above into one file


<script src="checkoutFlow.js">

the Ultimate Solution ?

<style>
body{background-color:#f00;}
p{font-size:4vmin;}
......
footer small{color:#ccc;}
</style>

<script>
var ele = document.querySelector('.mei');
......
......
ele.classList.toggle("visible");
</script>

No cache no performance

The Ultimate Solution might relly reduce the request amount to 0, but ... it can't enjoy the browser cache benefit. If we can use the browser cache, same flow pages will enjoy the benefit and reduce the request amount.

How to turn browser cache on ?


  • Cache-Control:max-age=86400
  • ETag:e3233407de946ca06fa46227a8d79e5a
  • Expires:Thu, 17 Dec 2015 06:15:17 GMT

CSS Sprites

For more vivid interactions or some status notify, we will use many images as icon.

CSS Sprites - Step1

We can collect whole site or specfic modules's images then put them in 1 image.


CSS Sprites - Step2

Use CSS background attribute to set image position and display it.

.css-sprite {
    background-image:url(sprites-image.png);
    background-repeat:no-repeat;    
}
.left-arrow {
    width:10px;
    height:10px;
    background-position:-10px -10px;
}

data URIs

We can convert some files into base64-encoded binary data, such as images or font. check the following syntax:

data:[<mediatype>][;base64]

That means we can do some inline soultion to save request.

CSS Sprites - Step3

Use data URI format to convert image into string. (optional)

.css-sprite {
    background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjwAAAakr93t8fVzOa0WbJ20hXr+fjwePeGd2ZOTMadN/+nHPPMTK73+
...
...
...
/4yj8tRS8VAACAp8RWKdv5I5m+8k8rffBWyUmV
); background-repeat:no-repeat; }

Icon font

There is another solution for icons - icon font. Font icons are vector and resolution independent. They look good on both high and low PPI displays, on both mobile and desktop devices.

All we need to do are:

  • define icons you like.
  • import and convert them into web font
  • Use CSS to require font

Icon font - circularNav

Icon font - CSS

<style>
@font-face {
    font-family: 'icomoon';
    src: url('fonts/icomoon.eot');
    src: url('fonts/icomoon.eot') format('embedded-opentype'),
           url('fonts/icomoon.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;     
}
.icon1,icon2 { font-family:'icomoon';}
.icon1:before { content: "\ea8c"; }
.icon2:before { content: "\e901"; }
</style>
IcoMoon

image lazyLoad

image lazyLoad

image lazyLoad

image lazyLoad

Remove <img> src and put them into attribute data-lazyload; Use JavaScript to caculate what image in current viewPort and execute them alive when scrolling.

<img data-lazyload="img/image0.jpg">

JavaScript listen scroll event and judge


<img src="img/image0.jpg">

Minimize cookie

Each request will bring cookie with it go & back. We could minimize cookie to save bandwidth.

Extend Max parallel HTTP request

There are concurrent request limit in each browser. The limit might be 2, 4 or 6. Lets's see what how it effect with Network timeline.

Extend Max parallel HTTP request

This concurrent request limit is based on same domain. That means we might set different domain for file path and we could extend max parallel HTTP request.

Such as:

  • farm1.staticflickr.com
  • farm2.staticflickr.com
  • farm3.staticflickr.com
  • farm4.staticflickr.com
  • farm5.staticflickr.com

Y! flickr

DOM

DOM

The Document Object Model (DOM) is a programming interface for HTML, XML and SVG documents. It provides a structured representation of the document (a tree) and it defines a way that the structure can be accessed from programs so that they can change the document structure, style and content.

<script>
var nodeList;
document.body.className = 'mweb';
nodeList = document.querySelectorAll('a');
nodeList[0].textContent = 'Show me the money';
</script>

Remove useless DOM

Remove useless DOM - Before

<div class="irens">
    <img class="canvas" src="img/cropper.jpg">
    <div class="overlay"></div>
    <div class="frame maneuver">
        <div class="lens">
            <div class="col line">
                <div>col line1</div>
                <div>col line2</div>
            </div>
            <div class="row line">
                <div>row line1</div>
                <div>row line2</div>
            </div>
        </div>
        ......
    </div>
</div>

Remove useless DOM

Apply CSS pseudo-elements for vivid decoration.

Such as:

  • ::before
  • ::after
<style>
.irens:before{...}
.lens .col:after{...}
.lens .row:after{...}
</style>

Remove useless DOM - After

<div class="irens">
    <img class="canvas" src="img/cropper.jpg">
    <div class="overlay"></div>
    <div class="frame maneuver">
        <div class="lens">
            <div class="col line">
                <div>col line1</div>
                <div>col line2</div>
            </div>
            <div class="row line">
                <div>row line1</div>
                <div>row line2</div>                
            </div>
        </div>
        ......
    </div>
</div>

Generate DOM when need them

DOM tree should be slim and graceful. For this purpose we could remove some DOM at first and generate them when we really need them.

Here comes some solution:

  • gen elements by DOM APIs.
  • put DOM at somewhere.
    • <script type="text/x-handlebars-template"><script>
    • <template>

DOM APIs - native

<script>
var ul = document.createElement('ul');
for (var i=-1,l=10;++i<l;) {
    var li = document.createElement('li');
    li.textContent = 'list - ' + i;
    ul.appendChild(li);
}
document.body.appendChild(ul);
</script>

Store DOM in somewhere

<textarea id="storage">
    <ul>
        <li>list - 1</li>
        <li>list - 2</li>
        ......
        ......
        <li>list - 10</li>
    </ul>
</textarea>

<script>
var ul = document.querySelector('#storage').value;
document.body.append(ul);
</script>

SEO - Structure data

Schema.org is sponsored by Google, Microsoft, Yahoo and Yandex. A shared vocabulary makes it easier for webmasters and developers to decide on a schema and get the maximum benefit for their efforts.

Without markup:

<div>
    <h1>Avatar</h1>
    Director: James Cameron (born August 16, 1954)
    <span>Science fiction</span>
    <a href="trailer.html">Trailer</a>
</div>

Microdata

<div itemscope itemtype="http://schema.org/Movie">
    <h1 itemprop="name">Avatar</h1>
    <div itemprop="director" itemscope itemtype="http://schema.org/Person">
        Director: 
        <span itemprop="name">James Cameron</span>
        (born <span itemprop="birthDate">August 16, 1954</span>)
    </div>
    <span itemprop="genre">Science fiction</span>
    <a href="trailer.html" itemprop="trailer">Trailer</a>
</div>

JSON-LD

<script type="application/ld+json">
{
    "@context": "http://schema.org",
    "@type": "Movie",
    "name": "Avatar",
    "director": {
        "@type": "Person",
        "name": "James Cameron",
        "birthDate": "August 16, 1954"
    },
    "genre": "Science fiction",
    "trailer": "Trailer"
}
</script>
Structure data testing tool

Yahoo Auction

CSS

Avoid「FOUC」

FOUC」 might occur in page render when there is no CSS resource available.

Where I place css

<!DOCTYPE html>
<html lang="en">
<head>
<meta>
......
<title>Modern Web</title>
<link rel="stylesheet" href="combo.css">
</head>
<body>
......
......
</body>
</html>

Shorten「REFLOW」time

the past

#mweb .listing li a img+p { font-size:5vmin; color:#fff; }


the future

#mweb .li-a-img-p { font-size:5vmin; color:#fff; }

Screen Render flow

Enhance composite for Render

Enhance composite for Render

CSS attribute: will-change

.moving-element {
    will-change: transform;
}

Not support browser

.moving-element {
    transform: translateZ(0);
}

Diverging advance and converging attack

JavaScript

JavaScript & Parser

<html>
<head>
    <script src="jquery.js"></script>
    <script src="masonry.js"></script>
    <script src="yui.js"></script>
    <script src="flickr-editor.js"></script>
    <script src="calendar.js"></script>
    <script src="cropper.js"></script>
</head>
<body>
</body>
</html>

timeline

Script DOM Element

<script>
(function(){
    var s, fjs;
    s = document.createElement('script');
    fjs = document.getElementsByTagName('script');
    s.async = true;
    s.src = 'combo.js';
    fjs.parentNode.insertBefore(s, fjs);
})();
</script>

pageRender

<script src="pagerender.js" data-source="jquery.js&masonry.js&yui.js&flickr-editor.js&calendar.js&cropper.js"></script>


Yahoo ServicePlus

Some tips

Here comes some tips for JavaScript. We might avoid or do some enhance in our website.


  • init when really need it.
  • Do not add too much event at same element.
  • Avoid too much DOM actions at the same time.

Remove Flash

Remove Flash content

HTML5 provided many vivid Web APIs. Some security & performance issue, we could just develop these features to replace Flash-only content.


  • multi-upload
  • video
  • webCam & Storage

muti-upload

video

webCam & storage

Navigation Timing API

Navigation Timing API

You can’t optimize what you can’t measure.

That's the main reason why W3C provide user timing API for more specific analyze. User Timing API privides high Resolution time & same measure method to make it easier.

<script>
var t = window.performance.timing;
console.log(t);
</script>

Navigation Timing API

Measure anything you like

<script>
performance.mark('start');
doSomething();
performance.mark('end');

performance.measure('module_track', 'start', 'end');
console.log(performance.getEntriesByName('module_track'));
</script>

Example: Measure Module

Web Storage

Web Storage

We can user web storage as client site cache system and support with AJAX.


  • web SQL Database
  • indexedDB
  • localStorage

Web Storage

Yahoo ServicePlus

Pre Party

Pre Party

Here comes same interesting & trick way for browser. These will help us to do some preload and bring wonderful user experience.

Check the following:

  • dns-prefetch
  • prefetch
  • prerender

Pre Party

<head>
...
<link rel="dns-prefetch" href="//tw.bid.yahoo.com">
<link rel="prefetch" href="//other-styles.css">
<link rel="prerender" href="//tw.serviceplus.yahoo.com/item/detail/100128073151">
</head>

Instant Page

<script>
function instantPage(uri) {
    var prerender = document.querySelector('#prerender');
    if (prerender) prerender.remove();
    prerender = document.createElement('link');
    prerender.setAttribute('id', 'prerender');
    prerender.setAttribute('rel', 'prerender');
    prerender.setAttribute('href', uri);
    document.head.appendChild(prerender);
}
</script>

Instant Page: Yahoo ServicePlus

Recap

  • Requests
  • DOM
  • CSS
  • JavaScript
  • Remove Flash
  • Navigation Timing
  • Web Storage
  • Pre Party

References

References

Q and A

Thank you