1<!DOCTYPE html> 2<html lang="en"><!-- 3 __ __ __ __ 4/\ \/\ \ /\ \ __ /\ \ 5\ \ \_\ \ __ __ \_\ \ __ /\_\ __ ___ \ \ \/'\ 6 \ \ _ \ /\ \/\ \ /'_` \ /'__`\ \/\ \ /'__`\ /'___\\ \ , < 7 \ \ \ \ \\ \ \_\ \ /\ \L\ \ /\ __/ \ \ \ /\ \L\.\_ /\ \__/ \ \ \\`\ 8 \ \_\ \_\\/`____ \\ \___,_\\ \____\ _\ \ \\ \__/.\_\\ \____\ \ \_\ \_\ 9 \/_/\/_/ `/___/> \\/__,_ / \/____//\ \_\ \\/__/\/_/ \/____/ \/_/\/_/ 10 /\___/ \ \____/ 11 \/__/ \/___/ 12 13Powered by Hydejack v9.2.1 <https://hydejack.com/> 14--><head><title>Blog | Paul Calvano</title><meta name="generator" content="Jekyll v4.4.1" /><meta property="og:title" content="Blog" /><meta name="author" content="Paul Calvano" /><meta property="og:locale" content="en" /><meta name="description" content="Paul Calvanoâs Blog" /><meta property="og:description" content="Paul Calvanoâs Blog" /><link rel="canonical" href="https://paulcalvano.com/" /><meta property="og:url" content="https://paulcalvano.com/" /><meta property="og:site_name" content="Paul Calvano" /><link rel="next" href="https://paulcalvano.com/2/" /><meta name="twitter:card" content="summary" /><meta property="twitter:title" content="Blog" />
14<script type="application/ld+json"> {"name":"Paul Calvano","author":{"@type":"Person","name":"Paul Calvano"},"@type":"WebSite","publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://paulcalvano.com/assets/img/paulcalvano.jpg"},"name":"Paul Calvano"},"description":"Paul Calvanoâs Blog","url":"https://paulcalvano.com/","headline":"Blog","dateModified":"2020-07-28T02:33:16+00:00","@context":"https://schema.org"}</script>
14<meta name="keywords" content="web performance,webperf,optimization,html,javascript,http archive,bigquery"><meta name="color-scheme" content="light"><meta name="theme-color" content="rgb(8,46,57)"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-title" content="Paul Calvano"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="application-name" content="Paul Calvano"><meta name="generator" content="Hydejack v9.2.1" /><link rel="alternate" href="https://paulcalvano.com/" hreflang="en"><link type="application/atom+xml" rel="alternate" href="https://paulcalvano.com/feed.xml" title="Paul Calvano" /><link rel="shortcut icon" href="/assets/icons/favicon.ico"><link rel="apple-touch-icon" href="/assets/icons/icon-192x192.png"><link rel="manifest" href="/assets/site.webmanifest"><link rel="dns-prefetch" href="/assets/bower_components/katex/dist/katex.min.css" id="_katexPreload">
14<script>((r,a)=>{function d(e,t,n,o){e.addEventListener?e.addEventListener(t,n,o):e.attachEvent?e.attachEvent("on"+t,n):e["on"+t]=n}r.loadJS=function(e,t){var n=a.createElement("script"),e=(n.src=e,t&&d(n,"load",t,{once:!0}),a.scripts[0]);return e.parentNode.insertBefore(n,e),n},r._loaded=!1,r.loadJSDeferred=function(e,t){var n=a.createElement("script");function o(){r._loaded=!0,t&&d(n,"load",t,{once:!0});var e=a.scripts[0];e.parentNode.insertBefore(n,e)}return n.src=e,r._loaded?o():d(r,"load",o,{once:!0}),n},r.setRel=r.setRelStylesheet=function(e){d(a.getElementById(e),"load",function(){this.rel="stylesheet"},{once:!0})}})(window,document); !function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b}("undefined"!=typeof global?global:this); !function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}}(this); !function(w) { w._baseURL = '/'; w._publicPath = '/assets/js/'; w._noPushState = true; w._noDrawer = true; w._noNavbar = true; w._noToc = false; w._noSearch = false; w._search = { DATA_URL: '/assets/sitedata.json?no-cache', STORAGE_KEY: 'mini-search/', INDEX_KEY: 'index--2026-09-05T15:05:08+00:00', }; w._clapButton = false; }(window);</script>
14 <!--[if gt IE 8]><!----><style id="_styleInline"> .clearfix,.sidebar-social::after{content:"";display:table;clear:both}.color-transition,.content .avatar,.nav-btn,.nav-btn-bar,.navbar,.message,.note-sm,#markdown-toc,.note,.hr-bottom,.hr-after::after,hr,.hr,p,body{transition:none}#_dark-mode{font-size:1.25rem}@media screen{body,body.light-mode{--body-color: #333;--body-bg: #fff;--border-color: #ebebeb;--gray: #777;--gray-bg: rgba(0, 0, 0, 0.025);--gray-text: #666;--menu-text: #bbb;--inv-body-color: #ccc;--inv-body-bg: var(--dark-mode-body-bg)}body .content,body.light-mode .content{-webkit-font-smoothing:initial;-moz-osx-font-smoothing:initial}body.dark-mode{--body-color: #ccc;--body-bg: var(--dark-mode-body-bg);--border-color: var(--dark-mode-border-color);--gray: rgba(255,255,255,.5);--gray-bg: rgba(255,255,255,.033);--gray-text: rgba(255,255,255,.625);--menu-text: rgba(255,255,255,.25);--inv-body-color: #333;--inv-body-bg: #fff}body.dark-mode .content{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}}html{--font-family: Noto Sans, Helvetica, Arial, sans-serif;--font-family-heading: Roboto Slab, Helvetica, Arial, sans-serif;--code-font-family: Fira Code, Menlo, Monaco, Consolas, monospace;--root-font-size: 15px;--root-font-size-medium: 16px;--root-font-size-large: 17px;--root-font-size-print: 8pt;--root-line-height: 1.75;--font-weight: 400;--font-weight-bold: 700;--font-weight-heading: 700;--content-width-5: 54rem;--content-margin-5: 4rem;--sidebar-width: 21rem;--half-content: 31rem;--break-point-3: 64em;--break-point-5: 86em;--break-point-dynamic: 104rem}*{box-sizing:border-box}html,body{margin:0;padding:0}html{font-family:var(--font-family);font-size:var(--root-font-size);line-height:var(--root-line-height)}body{color:var(--body-color);background-color:var(--body-bg);font-weight:var(--font-weight);overflow-y:scroll}.content img,.img,.content video,.video{max-width:100%;height:auto}.lead{margin-left:-1rem;margin-right:-1rem;margin-bottom:1.5rem}img.lead,video.lead{display:block;max-width:calc(100% + 2rem);width:calc(100% + 2rem);height:auto}.heading,.f6,h6,.h6,.f5,h5,.h5,.f4,.sidebar-nav-item,h4,.h4,.post-date,.f3,h3,.h3,.f2,h2,.h2,.f1,h1,.h1{font-family:var(--font-family-heading);font-weight:var(--font-weight-heading)}.f1,h1,.h1{font-size:2rem;line-height:1.3}.f2,h2,.h2{font-size:1.5rem;line-height:1.4}.f3,h3,.h3{font-size:1.2em;line-height:1.5}.f4,.sidebar-nav-item,h4,.h4,.post-date{font-size:1.08rem;line-height:1.6}.f5,h5,.h5{font-size:1.04rem;line-height:1.7}.f6,h6,.h6{font-size:1rem}.content h1>a,.content .h1>a{text-decoration:none;border-bottom:none}@media screen and (max-width: 42em){.content h1,.content .h1{font-size:1.7rem;line-height:1.35}}@media screen and (min-width: 86em){.content h1,.content .h1{font-size:2.4rem;line-height:1.25}}@media screen and (min-width: 104rem){body:not(.no-large-headings) .content h1,body:not(.no-large-headings) .content .h1{width:calc(100% + 50vw - 32rem);font-size:3rem;line-height:1.2}}@media screen and (min-width: 124em){body:not(.no-large-headings) .content h1,body:not(.no-large-headings) .content .h1{font-size:4rem;line-height:1.1}}h1,h2,h3,.h1,.h2,.h3{margin:4rem 0 1rem}h4,h5,h6,.h4,.post-date,.h5,.h6{margin:3rem 0 .5rem}p{margin-top:0;margin-bottom:1rem}p.lead{font-size:1.2em;margin-top:1.5rem;margin-bottom:1.5rem;padding:0 1rem}ul,ol,dl{margin-top:0;margin-bottom:1rem}ul,ol{padding-left:1.25rem}hr,.hr{border:0;margin:1rem 0;border-top:1px solid var(--border-color)}.hr-after::after{content:"";display:block;margin:1rem 0;border-top:1px solid var(--border-color)}.hr-bottom{border-bottom:1px solid var(--border-color);padding-bottom:.75rem;margin-bottom:1rem}.page{margin-bottom:3em}.page li+li{margin-top:.25rem}.page>header{position:relative;margin-bottom:2rem}@media screen and (min-width: 104rem){body:not(.no-third-column) .page>header>.lead+.note-sm,body:not(.no-third-column) .page>header>.lead+#markdown-toc,body:not(.no-third-column) .page>header>.lead+.note,body:not(.no-third-column) .page>header>a.no-hover+.note-sm,body:not(.no-third-column) .page>header>a.no-hover+#markdown-toc,body:not(.no-third-column) .page>header>a.no-hover+.note{position:absolute;right:-25rem;width:21rem;bottom:0;margin-bottom:0}}.page-title,.post-title{margin-top:0}.post-date{display:flex;justify-content:space-between;margin-top:-0.6rem;height:2rem;margin-bottom:.85rem;color:var(--gray)}.post-date>.ellipsis,.post-date#breadcrumbs>ul{cursor:pointer}.post-date [class^=icon-]{display:inline-block;font-size:smaller;margin-right:.25rem}.related-posts{padding-left:0;list-style:none;margin-bottom:2rem}.related-posts>li,.related-posts>li+li{margin-top:1rem}.message,.note-sm,#markdown-toc,.note{margin-bottom:1rem;padding:1rem;color:var(--gray-text);background-color:var(--gray-bg);margin-left:-1rem;margin-right:-1rem}.note-sm,#markdown-toc,.note{background:rgba(0,0,0,0);color:var(--body-color);font-size:smaller;border-left:1px solid var(--border-color);padding:1.2rem 1rem 0 1rem;margin:1rem -1rem;position:relative}.note-sm:before,#markdown-toc:before,.note:before{font-size:.667rem;font-weight:bold;font-style:normal;letter-spacing:.025rem;text-transform:uppercase;color:var(--menu-text);position:absolute;top:0}.note-sm[title]:before,[title]#markdown-toc:before,[title].note:before{content:attr(title) !important}.note{font-size:1rem}@media screen{body::before{content:"";width:.5rem;background:var(--gray-bg);position:fixed;left:0;top:0;bottom:0}}@media(min-width: 64em){body::before{width:21rem}}@media(min-width: 104rem){body::before{width:calc(50% - 31rem)}}@media screen and (min-width: 42em){html{font-size:var(--root-font-size-medium)}}@media screen and (min-width: 124em){html{font-size:var(--root-font-size-large)}}#breadcrumbs>ul{height:1rem;margin:-1.5rem 0 .5rem;padding:0;font-size:.667rem;color:var(--menu-text);text-transform:uppercase;width:100%;list-style:none}#breadcrumbs>ul>li{display:inline}#breadcrumbs>ul>li a{color:var(--gray);text-decoration:none;border-bottom:none}.fl{float:left}.fr{float:right}.mb4{margin-bottom:4rem}.mb6{margin-bottom:6rem}.mt0{margin-top:0}.mt1{margin-top:1rem}.mt2{margin-top:2rem}.mt3{margin-top:3rem}.mt4{margin-top:4rem}.pb0{padding-bottom:0}.ml1{margin-left:1rem}.mr1{margin-right:1rem}.sixteen-nine{position:relative}.sixteen-nine::before{display:block;content:"";width:100%;padding-top:56.25%}.sixteen-nine>*{position:absolute;top:0;left:0;right:0;bottom:0}.sixteen-ten{position:relative}.sixteen-ten::before{display:block;content:"";width:100%;padding-top:62.5%}.sixteen-ten>*{position:absolute;top:0;left:0;right:0;bottom:0}.four-three{position:relative}.four-three::before{display:block;content:"";width:100%;padding-top:75%}.four-three>*{position:absolute;top:0;left:0;right:0;bottom:0}.sr-only{display:none}.larger{font-size:larger}.smaller{font-size:smaller}.clearfix,.sidebar-social::after{content:"";display:table;clear:both}.ellipsis,#breadcrumbs>ul{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.border{border:1px solid var(--border-color)}@media(min-width: 42em){.border-radius,.lead,.page .aspect-ratio.sixteen-nine.lead{border-radius:.5rem}}.fallback-img{background-position:center;background-repeat:no-repeat;background-image:url("data:image/svg+xml;
14base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTYwIiBoZWlnaHQ9IjkwIiB2aWV3Qm94PSIwIDAgMTYwIDkwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxnIHRyYW5zZm9ybT0ibWF0cml4KDAuMDQ4ODI4LCAwLCAwLCAwLjA0Nzk5MSwgNTQuOTk5OTczLCAyMC40MjgxNDgpIj4KICAgIDxwYXRoIHN0eWxlPSJmaWxsOnJnYmEoMTI4LDEyOCwxMjgsLjMzKSIgZD0iTTk1OS44ODQgMTI4YzAuMDQwIDAuMDM0IDAuMDgyIDAuMDc2IDAuMTE2IDAuMTE2djc2Ny43N2MtMC4wMzQgMC4wNDAtMC4wNzYgMC4wODItMC4xMTYgMC4xMTZoLTg5NS43N2MtMC4wNDAtMC4wMzQtMC4wODItMC4wNzYtMC4xMTQtMC4xMTZ2LTc2Ny43NzJjMC4wMzQtMC4wNDAgMC4wNzYtMC4wODIgMC4xMTQtMC4xMTRoODk1Ljc3ek05NjAgNjRoLTg5NmMtMzUuMiAwLTY0IDI4LjgtNjQgNjR2NzY4YzAgMzUuMiAyOC44IDY0IDY0IDY0aDg5NmMzNS4yIDAgNjQtMjguOCA2NC02NHYtNzY4YzAtMzUuMi0yOC44LTY0LTY0LTY0djB6Ii8+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDpyZ2JhKDEyOCwxMjgsMTI4LC4zMykiIGQ9Ik04MzIgMjg4YzAgNTMuMDIwLTQyLjk4IDk2LTk2IDk2cy05Ni00Mi45OC05Ni05NiA0Mi45OC05NiA5Ni05NiA5NiA0Mi45OCA5NiA5NnoiLz4KICAgIDxwYXRoIHN0eWxlPSJmaWxsOnJnYmEoMTI4LDEyOCwxMjgsLjMzKSIgZD0iTTg5NiA4MzJoLTc2OHYtMTI4bDIyNC0zODQgMjU2IDMyMGg2NGwyMjQtMTkyeiIvPgogIDwvZz4KPC9zdmc+")}hy-push-state a{color:var(--body-color)}@supports not ((text-decoration-thickness: initial) and (text-underline-offset: initial)){hy-push-state a{text-decoration:none;border-bottom:2px solid}}@supports(text-decoration-thickness: initial) and (text-underline-offset: initial){hy-push-state a{text-decoration-style:solid;text-underline-offset:.35rem;text-decoration-thickness:2px}}hy-push-state a.no-hover{border-bottom:none;text-decoration-thickness:unset;text-underline-offset:unset}@supports(text-decoration-thickness: initial) and (text-underline-offset: initial){.content a:not(.btn):not(.no-hover){text-decoration-color:var(--accent-color-faded)}}.content a:not(.btn):not(.no-hover){border-color:var(--accent-color-faded)}.content .aspect-ratio{overflow:hidden}.content .aspect-ratio img{margin:0;width:100%;height:100%;background-color:var(--gray-bg)}hy-drawer{width:100%;position:relative;overflow:hidden;display:block;z-index:4}@media screen and (min-width: 64em){hy-drawer{position:fixed;width:21rem;top:0;left:0;bottom:0;margin-left:0}hy-drawer.cover{position:relative;width:100%}}@media screen and (min-width: 104rem){hy-drawer{width:calc(50% - 31rem)}}.sidebar{position:relative;display:flex;justify-content:center;align-items:center;color:rgba(255,255,255,.75);text-align:center;min-height:100vh}.sidebar.invert{color:rgba(32,32,32,.75)}.sidebar a{color:#fff;border-bottom-color:rgba(255,255,255,.2);text-decoration-color:rgba(255,255,255,.2)}.sidebar.invert a{color:#222;border-bottom-color:rgba(32,32,32,.2);text-decoration-color:rgba(32,32,32,.2)}.sidebar-bg{position:absolute;top:0;left:calc(50% - 50vw);width:100vw;height:100%;background:#202020 center/cover}.sidebar-bg::after{content:"";position:absolute;top:0;left:0;bottom:0;right:0;background:rgba(0,0,0,.05)}.sidebar-bg.sidebar-overlay::after{background:linear-gradient(to bottom, rgba(32, 32, 32, 0) 0%, rgba(32, 32, 32, 0.5) 50%, rgba(32, 32, 32, 0) 100%)}.sidebar-sticky{position:relative;z-index:3;max-width:21rem;padding:1.5rem;contain:content}.sidebar-about .avatar{margin-bottom:1.5rem}.sidebar-about>a.sidebar-title{text-decoration:none}.sidebar-about>a.sidebar-title>h2{margin:0;padding-bottom:.5rem}.sidebar-about>a.sidebar-title::after{content:"";display:block;border-bottom:2px solid;margin:0 auto .5rem;width:4rem;border-color:rgba(255,255,255,.2);transition:border-color 250ms}.sidebar-about>a.sidebar-title:hover::after{border-color:#fff;transition:border-color 50ms}.sidebar.invert .sidebar-about>a.sidebar-title::after{border-color:rgba(32,32,32,.2)}.sidebar.invert .sidebar-about>a.sidebar-title:hover::after{border-color:#222}.sidebar-nav>ul{list-style:none;padding-left:0}.sidebar-nav-item{display:inline-block;margin-bottom:.5rem}@media(min-width: 64em){#_main.no-drawer #_menu{display:none}#_main.no-drawer .nav-btn-bar>:nth-child(2){border:none}}.sidebar-social>ul{display:inline-block;list-style:none;padding-left:0;margin-bottom:0}.sidebar-social>ul>li{float:left}.sidebar-social>ul>li>a{display:inline-block;text-align:center;font-size:1.4rem;width:3rem;height:4rem;padding:.5rem 0;line-height:3rem;text-decoration:none;border-bottom-width:2px;border-bottom-style:solid}.sidebar-social>ul li+li{margin-top:0}.fixed-common,.fixed-bottom,.fixed-top{position:fixed;left:0;width:100%;z-index:2}.fixed-top{top:0}.fixed-bottom{bottom:0}.navbar>.content{position:relative;padding-top:0;padding-bottom:0;min-height:0;max-height:5rem}.nav-btn-bar{margin:0 -1rem;background-color:#fff;background-color:var(--body-bg);height:5rem;display:flex;align-items:center;position:relative}.nav-btn-bar>:first-child,.nav-btn-bar>:last-child{border:none}.nav-btn{background:none;border:none;text-decoration:none;display:flex;align-items:center;justify-content:center;width:3.25rem;height:5rem;color:var(--menu-text);border-right:1px solid var(--border-color);border-left:1px solid var(--border-color);margin-left:-1px}
14#markdown-toc{margin:2rem -1rem 2rem calc(-1rem + 1px);padding-left:2.5rem;padding-bottom:.5rem}#markdown-toc:before{left:1rem}@media screen and (min-width: 104rem){body:not(.no-toc) #markdown-toc{position:absolute;z-index:4;width:20.5rem;right:0;margin:auto;overflow:auto}}@media screen and (min-width: 104rem){body.no-break-layout:not(.no-toc) #markdown-toc{width:calc(50% - 31rem)}}.content{margin-left:auto;margin-right:auto;padding:8rem 1rem 12rem}@media screen{.content{padding-left:1.5rem;min-height:100vh}}@media screen and (min-width: 42em){.content{max-width:42rem}}@media screen and (min-width: 54em){.content{max-width:48rem}}@media screen and (min-width: 64em){.content{padding-left:1rem;margin-left:24rem;margin-right:3rem}}@media screen and (min-width: 86em){.content{padding-top:9rem;margin-left:25rem;margin-right:4rem;max-width:54rem}}@media screen and (min-width: 104rem){.content{margin:auto}}.large-only{display:none}@media screen and (min-width: 104rem){.large-only{display:block}}.avatar{width:7rem;height:7rem;border-radius:100%;overflow:hidden;display:inline-block}.avatar img{width:100%}.content .avatar{float:right;box-sizing:content-box;border:1rem solid var(--body-bg);transition:border-color 1s ease;margin-top:-1.5rem;margin-right:-1rem}.sidebar a{text-shadow:rgba(0,0,0,.25) .1rem .1rem .15rem}#_navbar{display:none}.icon-bsky{display:inline-block;width:1.25em;min-width:1.25em;height:1.25em;min-height:1.25em;background:url("/assets/icons/bluesky.svg") center/contain no-repeat !important;visibility:visible;opacity:1;filter:grayscale(1) brightness(0) invert(1);vertical-align:-0.125em}.icon-bsky::before{content:none}#_main .sidebar-social .icon-bsky{background-image:url("/assets/icons/bluesky-black.svg") !important;filter:none}.note:before{content:"Note"}.page>header>.note-sm:before,.page>header>.note:before,.page>header>#markdown-toc:before{content:"Description"}#markdown-toc:before{content:"Table of Contents"}.layout-resume .note-sm:before,.layout-resume .note:before,.layout-resume #markdown-toc:before{content:"Summary"}</style><link rel="preload" as="style" href="/assets/css/hydejack-9.2.1.css" id="_stylePreload"><link rel="preload" as="style" href="/assets/icomoon/style.css" id="_iconsPreload">
14<script> setRel('_stylePreload'); setRel('_iconsPreload'); /**/ </script>
14 <noscript><link rel="stylesheet" href="/assets/css/hydejack-9.2.1.css"><link rel="stylesheet" href="/assets/icomoon/style.css"> </noscript><style id="_pageStyle"> html{--accent-color: rgb(79,177,186);--accent-color-faded: rgba(79, 177, 186, 0.5);--accent-color-highlight: rgba(79, 177, 186, 0.1);--accent-color-darkened: rgb(25.0432172869%, 60.6118447379%, 63.8783513405%);--theme-color: rgb(8,46,57);--dark-mode-body-bg: hsl(193.4693877551, 9.4230769231%, 17.5%);--dark-mode-border-color: hsl(193.4693877551, 9.4230769231%, 22.5%)}</style><!--<![endif]--><style> .icon-bsky { display: inline-block; width: 1.25em; min-width: 1.25em; height: 1.25em; min-height: 1.25em; background: url("/assets/icons/bluesky.svg") center / contain no-repeat !important; visibility: visible; opacity: 1; filter: grayscale(1) brightness(0) invert(1); vertical-align: -0.125em; } .icon-bsky::before { content: none; } #_main .sidebar-social .icon-bsky { background-image: url("/assets/icons/bluesky-black.svg") !important; filter: none; }</style><body class="no-break-layout no-drawer"> <hy-push-state id="_pushState" replace-selector="#_main" link-selector="a[href]:not([href^='/assets/']):not(.external):not(.no-push-state)" script-selector="script" duration="500" hashchange ><div id="_navbar" class="navbar fixed-top"><div class="content"> <span class="sr-only">Jump to:</span><div class="nav-btn-bar"> <a id="_menu" class="nav-btn no-hover" href="#_drawer--opened"> <span class="sr-only">Navigation</span> <span class="icon-menu"></span> </a><div class="nav-span"></div></div></div></div><hr class="sr-only" hidden /><main id="_main" class="content layout-blog" role="main" ><article id="post-resource-age-and-its-impact-on-cacheability" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2026-09-05-resource-age-and-its-impact-on-cacheability/" class="flip-title"> Resource Age and Its Impact on Cacheability </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2026-09-05T04:00:00+00:00">05 Sep 2026</time> </span></div><div class="hr pb0"></div></header><p>When deciding how long to cache a response, itâs important to consider how often the response may change as well as the cost of revalidation. A resource that is updated frequently would benefit from a short cache duration, which offloads the origin while ensuring content freshness. Likewise, a resource that rarely or never changes would benefit from a longer or even immutable cache duration. In HTTP, cache freshness lifetimes are typically configured with the <code class="language-plaintext highlighter-rouge">max-age</code> directive in the <code class="language-plaintext highlighter-rouge">Cache-Control</code> response header, which indicate how long a resource can be served from a cache.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2026-09-05-resource-age-and-its-impact-on-cacheability/">Resource Age and Its Impact on Cacheability</a></footer></article><article id="post-serving-static-content-with-cloud-storage-dont-forget-the-cdn" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2026-02-09-serving-static-content-with-cloud-storage-dont-forget-the-cdn/" class="flip-title"> Serving Static Content with Cloud Storage? Don't Forget the CDN! </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2026-02-09T04:00:00+00:00">09 Feb 2026</time> </span></div><div class="hr pb0"></div></header><p>Many websites use cloud storage as part of how they deliver static content to end users. However using these services without a CDN in front of them has the potential to negatively impact performance. You might be surprised by how many sites do just that - about 8.5% of websites that use a CDN for their primary content, based on <a href="https://httparchive.org/">HTTP Archive</a> data from January 2026!<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2026-02-09-serving-static-content-with-cloud-storage-dont-forget-the-cdn/">Serving Static Content with Cloud Storage? Don't Forget the CDN!</a></footer></article><article id="post-third-parties-and-single-points-of-failure" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2025-12-29-third-parties-and-single-points-of-failure/" class="flip-title"> Third Parties and Single Points of Failure </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2025-12-29T04:00:00+00:00">29 Dec 2025</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 07 Feb 2026"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2026-02-07T18:51:58+00:00">2026-02-07</time> </span></div><div class="hr pb0"></div></header><p>Youâve heard it many times - third party content can easily cause an otherwise well performing website to become sluggish and slow. And depen
14ding on how this content is loaded, it can also introduce single points of failure (SPOFs). When a large cloud provider or content delivery network (CDN) experiences a disruption, their impacts are felt across the world and often triggers headlines about the many websites that were affected. However, there are numerous secondary impacts triggered by third party content, which can be disruptive even to companies that donât use the affected provider.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2025-12-29-third-parties-and-single-points-of-failure/">Third Parties and Single Points of Failure</a></footer></article><article id="post-ai-bots-and-robots-txt" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2025-08-21-ai-bots-and-robots-txt/" class="flip-title"> AI Bots and Robots.txt </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2025-08-21T04:00:00+00:00">21 Aug 2025</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 01 Sep 2025"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2025-09-01T15:16:23+00:00">2025-09-01</time> </span></div><div class="hr pb0"></div></header><p>Thereâs been a lot of discussion lately around AI crawlers and bots, which are used to train LLMs and/or fetch content on behalf of their users. In the past few weeks Iâve seen blog posts about the amount of traffic from these crawlers, techniques and products to control how and what they can crawl, reports of misbehaving crawlers and more. Ironically, thereâs even AI based services to mitigate AI crawler bots! Given how much interest there is, I thought Iâd try and explore some <a href="https://httparchive.org/" target="_blank">HTTP Archive</a> data to see how sites are using robots.txt to state their preferences on AI crawling.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2025-08-21-ai-bots-and-robots-txt/">AI Bots and Robots.txt</a></footer></article><article id="post-discovering-third-party-performance-risks" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2024-09-03-discovering-third-party-performance-risks/" class="flip-title"> Discovering Third Party Performance Risks </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2024-09-03T04:00:00+00:00">03 Sep 2024</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 04 Sep 2024"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2024-09-04T11:06:33+00:00">
142024-09-04</time> </span></div><div class="hr pb0"></div></header><p>It likely comes as no surprise that third party content can be a significant contributor to slow loading websites and poor user experience. As performance engineers, we often need to find ways to balance requirements for their features with the strain that they can put on user experience. Unfortunately, for many sites this becomes a reaction to slowdowns and failures detected in production.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2024-09-03-discovering-third-party-performance-risks/">Discovering Third Party Performance Risks</a></footer></article><article id="post-third-parties-and-certificate-revocations" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2024-08-04-third-parties-and-certificate-revocations/" class="flip-title"> Third Parties and Certificate Revocations </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2024-08-04T04:00:00+00:00">04 Aug 2024</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 05 Aug 2024"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2024-08-05T03:12:24+00:00">2024-08-05</time> </span></div><div class="hr pb0"></div></header><p>On Monday July 29th, DigiCert <a href="https://www.digicert.com/support/certificate-revocation-incident">announced</a> the need to revoke a large number of certificates due to a bug in domain validation. The CA/B Forumâs <a href="https://cabforum.org/working-groups/server/baseline-requirements/documents/">strict requirements</a> to revoke these certificates within 24 hours resulted in a pretty busy Monday and Tuesday for a lot of folks. For some others, the deadline was moved to August 3rd due to exceptional circumstances. What remained a mystery was how many sites and third parties would be affected, how many would be prepared in time and what the impact of a mass revocation might look like across the web. In this blog post weâll use the <a href="https://httparchive.org/">HTTP Archive</a> to explore the impact.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2024-08-04-third-parties-and-certificate-revocations/">Third Parties and Certificate Revocations</a></footer></article><article id="post-choosing-between-gzip-brotli-and-zstandard-compression" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2024-03-19-choosing-between-gzip-brotli-and-zstandard-compression/" class="flip-title"> Choosing Between gzip, Brotli and zStandard Compression </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2024-03-19T04:00:00+00:00">19 Mar 2024</time> </span></div><div class="hr pb0"></div></header><p>HTTP compression is a mechanism that allows a web server to deliver text based content using less bytes, and itâs been supported on the web for a very long time. In fact the first web browser to support gzip compression was <a href="https://web.archive.org/web/19990824044001/https://www.desy.de/web/mosaic/help-on-version-2.1.html">NCSA Mosaic v2.1</a> way back in 1993! The web has obviously come a long way since then, but today pretty much every web server and browser still supports gzip compression.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2024-03-19-choosing-between-gzip-brotli-and-zstandard-compression/">Choosing Between gzip, Brotli and zStandard Compression</a></footer></article><article id="post-identifying-font-subsetting-opportunities" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2024-02-16-identifying-font-subsetting-opportunities/" class="flip-title"> Identifying Font Subsetting Opportunities with Web Font Analyzer </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2024-02-16T14:00:00+00:00">16 Feb 2024</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 17 Feb 2024"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2024-02-17T19:20:07+00:00">2024-02-17</time> </span></div><div class="hr pb0"></div></header><p>10 years ago, custom web fonts were a niche feature <a href="https://almanac.httparchive.org/en/2022/fonts#fig-1">used by ~10% of websites</a>
14. Today they are used by over 83% of websites! Fonts are generally loaded as a <a href="https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit#">high priority resource</a>, and some sites use techniques such as <a href="https://web.dev/articles/codelab-preload-web-fonts">preload</a> and <a href="https://developer.chrome.com/docs/web-platform/early-hints">early hints</a> to get them to load as quickly as possible. Custom web fonts are important to many sites, since rendering with a specific typography is often preferred from a design perspective. However, this can easily become a performance issue when a large amount of fonts are loaded.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2024-02-16-identifying-font-subsetting-opportunities/">Identifying Font Subsetting Opportunities with Web Font Analyzer</a></footer></article><article id="post-internet-explorer-decline-in-2021" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2022-01-31-internet-explorer-decline-in-2021/" class="flip-title"> Internet Explorer's Decline in Usage in 2021 </a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2022-01-31T14:00:00+00:00">31 Jan 2022</time> </span></div><div class="hr pb0"></div></header><p>In May 2021 Microsoft <a href="https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/">announced</a> that it would be officially retiring Internet Explorer in favor of the Chromium based <a href="https://www.microsoft.com/en-us/edge">Microsoft Edge</a>. Usage for the legacy browser had been very low over the past few years, although many websites have still maintained polyfills for the older browser. In fact a number of my clients have recently told me that supporting IE 11 is required by their business, and is still a consideration when adding new features to their sites. Iâm sure that the official retirement of Internet Explorer will help numerous organizations embrace modern web features and move on from some expensive <a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfills</a>. The official retirement date is June 15, 2022.<footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2022-01-31-internet-explorer-decline-in-2021/">Internet Explorer's Decline in Usage in 2021</a></footer></article><article id="post-page-visibility-if-a-tree-falls-in-the-forest" class="page post mb6" role="article"><header><h1 class="post-title flip-project-title"> <a href="/2021-12-31-page-visibility-if-a-tree-falls-in-the-forest/" class="flip-title"> Page Visibility: If a tree falls in the forest⦠</a></h1><div class="post-date"> <span class="ellipsis mr1"> <time datetime="2021-12-31T16:30:00+00:00">31 Dec 2021</time> </span> <span class="ellipsis" data-tippy-content="Last modified at: 02 Jan 2022"> <span class="sr-only">Last modified at:</span> <span class="icon-history"></span> <time datetime="2022-01-02T19:43:14+00:00">2022-01-02</time> </span></div><div class="hr pb0"></div></header><p><img src="/assets/img/blog/page-visibility-if-a-tree-falls-in-the-forest/image12.jpg" alt="Picture of a tree falling in a forest" loading="lazy" /><footer><p class="read-more"> Continue reading <a class="heading flip-title" href="/2021-12-31-page-visibility-if-a-tree-falls-in-the-forest/">Page Visibility: If a tree falls in the forestâ¦</a></footer></article><h2 class="sr-only">Pagination</h2><nav class="pagination heading clearfix" role="navigation"><ul><li class="pagination-item older" > <a class=" " href="/2/" rel="next" >Older</a><li class="pagination-item newer" > <span class=" ">Newer</span></ul></nav><footer class="content" role="contentinfo"><hr/><p><small class="copyright">© 2026 Paul Calvano. All rights reserved. </small><p><small>Powered by <a class="external" href="https://hydejack.com/">Hydejack</a> v<span id="_version">9.2.1</span></small><hr class="sr-only"/></footer></main><hy-drawer id="_drawer" class="" side="left" threshold="10" noscroll ><header id="_sidebar" class="sidebar" role="banner"><div class="sidebar-bg sidebar-overlay" style="background-color:rgb(8,46,57);background-image:url(/assets/img/sidebar-bg.jpg)"></div><div class="sidebar-sticky"><div class="sidebar-about"> <a class="no-hover" href="/" tabindex="-1"> <img src="/assets/img/paulcalvano.jpg" class="avatar" alt="Paul Calvano" width="120" height="120" loading="lazy" />
14 </a> <a class="sidebar-title" href="/"><h2 class="h1">Paul Calvano</h2></a><p class=""> Hi! Iâm a web performance architect, and have been making websites load faster for over 25 years!</div><nav class="sidebar-nav heading" role="navigation"> <span class="sr-only">Navigation:</span><ul><li> <a id="_drawer--opened" href="/writing/" class="sidebar-nav-item " > Writing </a><li> <a href="/speaking/" class="sidebar-nav-item " > Speaking </a><li> <a href="/tools/" class="sidebar-nav-item " > Tools </a><li> <a href="/about/" class="sidebar-nav-item " > About </a></ul></nav><div class="sidebar-social"> <span class="sr-only">Social:</span><ul><li> <a href="https://www.linkedin.com/in/<paulcalvano>" title="LinkedIn" class="no-mark-external"> <span class="icon-linkedin2"></span> <span class="sr-only">LinkedIn</span> </a><li> <a href="https://bsky.app/profile/paulcalvano.bsky.social" title="BlueSky" class="no-mark-external"> <span class="icon-bsky"></span> <span class="sr-only">BlueSky</span> </a><li> <a href="https://github.com/paulcalvano" title="GitHub" class="no-mark-external"> <span class="icon-github"></span> <span class="sr-only">GitHub</span> </a><li> <a href="mailto:<[email protected]>" title="Email" class="no-mark-external"> <span class="icon-mail"></span> <span class="sr-only">Email</span> </a></ul></div><p class="loadtime"></div>
14<script> window.addEventListener('load',() => { var loadTime = document.getElementsByClassName('loadtime'); var duration = (performance.timing.loadEventStart - performance.timing.navigationStart)/1000;; [].forEach.call(loadTime,(el) => {el.innerText = `This page loaded in ${duration.toFixed(2)}s`}) } ) </script>
14</header></hy-drawer><hr class="sr-only" hidden /> </hy-push-state> <!--[if gt IE 10]><!---->
14<script nomodule>(()=>{var t,n=document.createElement("script");!("noModule"in n)&&"onbeforeload"in n&&(t=!1,document.addEventListener("beforeload",function(e){if(e.target===n)t=!0;else if(!e.target.hasAttribute("nomodule")||!t)return;e.preventDefault()},!0),n.type="module",n.src=".",document.head.appendChild(n),n.remove())})(); </script>
14
14<script src="/assets/js/hydejack-9.2.1.js" type="module"></script>
14
14<script src="/assets/js/LEGACY-hydejack-9.2.1.js" nomodule defer></script>
14 <!--<![endif]--> <!-- Code for integrating CloudFlare's email protection with Hydejack's single page app loading. -->
14<script> function openExternalLinksInNewTab() { document.querySelectorAll('a[href]').forEach(function (link) { var url = new URL(link.href, window.location.origin); if ((url.protocol === 'http:' || url.protocol === 'https:') && url.host !== window.location.host) { link.target = '_blank'; link.rel = 'noopener noreferrer'; } }); } openExternalLinksInNewTab(); document.getElementById('_pushState').addEventListener('hy-push-state-after', openExternalLinksInNewTab); document.getElementById('_pushState').addEventListener('hy-push-state-after', function (e) { function e(e){ (console.error?console.error:console.log).call(console,e) } function t(e){ return l.innerHTML='<a href="'+e.replace(/"/g,""")+'"></a>',l.childNodes[0].getAttribute("href") } function r(e,t){ var r=e.substr(t,2);return parseInt(r,16) } function n(e,n){ for(var o="",c=r(e,n),a=n+2;a<e.length;a+=2){ var l=r(e,a)^c; o+=String.fromCharCode(l) } return t(o) } var o="/cdn-cgi/l/email-protection#", c=".__cf_email__", a="data-cfemail", l=document.createElement("div"); !function(){ for(var t=document.getElementsByTagName("a"),r=0;r<t.length;r++) try{ var c=t[r],a=c.href.indexOf(o); a>-1&&(c.href="mailto:"+n(c.href,a+o.length)) }catch(t){ e(t) } }(), function(){ for(var t=document.querySelectorAll(c),r=0;r<t.length;r++) try{ var o=t[r],l=n(o.getAttribute(a),0),i=document.createTextNode(l); o.parentNode.replaceChild(i,o) }catch(t){ e(t) } }() }); </script>
vendor: 64 bytes, line 14
14 <script defer src="https://www.googletagmanager.com/gtag/js?id=
14UA-115745483-1
vendor: 12 bytes, line 14
14"></script>
14<script>
vendor: 127 bytes, line 14
14window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '
14UA-115745483-1
vendor: 4 bytes, line 14
14');
14</script>
14<div hidden><h2 class="sr-only">Templates (for web app):</h2><template id="_animation-template"><div class="animation-main fixed-top"><div class="content"><div class="page"></div></div></div></template> <template id="_loading-template"><div class="loading nav-btn fr"> <span class="sr-only">Loadingâ¦</span> <span class="icon-cog"></span></div></template> <template id="_error-template"><div class="page"><h1 class="page-title">Error</h1><p class="lead"> Sorry, an error occurred while loading <a class="this-link" href=""></a>.</div></template> <template id="_permalink-template"> <a href="#" class="permalink"> <span class="sr-only">Permalink</span> <span class="content-hash"></span> </a> </template> <template id="_dark-mode-template"> <button id="_dark-mode" class="nav-btn no-hover" > <span class="sr-only">Dark Mode</span> <span class="icon-brightness-contrast"></span> </button> </template></div></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.