|
17 | 17 | </div> |
18 | 18 | </footer> |
19 | 19 |
|
20 | | -<!-- Critical JavaScript - Load Immediately via CDN with local fallback --> |
21 | | -<script defer src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js" |
22 | | - integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" |
23 | | - crossorigin="anonymous"></script> |
24 | | -<script>window.jQuery || document.write('<script src="{{ "/js/jquery.min.js" | prepend: site.baseurl }}"><\/script>')</script> |
| 20 | +<!-- Critical JavaScript - Load via CDN with proper fallback --> |
| 21 | +<script> |
| 22 | +(function() { |
| 23 | + var jq = document.createElement('script'); |
| 24 | + jq.src = 'https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js'; |
| 25 | + jq.integrity = 'sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8='; |
| 26 | + jq.crossOrigin = 'anonymous'; |
| 27 | + jq.onerror = function() { |
| 28 | + var fallback = document.createElement('script'); |
| 29 | + fallback.src = '{{ "/js/jquery.min.js" | prepend: site.baseurl }}'; |
| 30 | + document.head.appendChild(fallback); |
| 31 | + }; |
| 32 | + document.head.appendChild(jq); |
| 33 | +})(); |
| 34 | +</script> |
25 | 35 |
|
26 | 36 | <!-- Critical: Language Toggle Event Delegation (Must load before user interaction) --> |
27 | 37 | <script> |
|
490 | 500 | </script> |
491 | 501 | <!-- Original work by Jason's Blog --> |
492 | 502 |
|
493 | | -<!-- Google Analytics 4 - Deferred Loading --> |
| 503 | +<!-- Google Analytics 4 - Load after user interaction or idle time --> |
494 | 504 | {% if jekyll.environment == 'production' %} |
495 | 505 | <script> |
496 | | - // Load Google Analytics after page is interactive |
497 | | - window.addEventListener('load', function() { |
498 | | - setTimeout(function() { |
499 | | - var gaScript = document.createElement('script'); |
500 | | - gaScript.src = 'https://www.googletagmanager.com/gtag/js?id={{ site.ga_track_id }}'; |
501 | | - gaScript.async = true; |
502 | | - document.head.appendChild(gaScript); |
503 | | - |
| 506 | + // Load GA only when browser is idle or user interacts |
| 507 | + (function() { |
| 508 | + var gaLoaded = false; |
| 509 | + function loadGA() { |
| 510 | + if (gaLoaded) return; |
| 511 | + gaLoaded = true; |
| 512 | + var s = document.createElement('script'); |
| 513 | + s.src = 'https://www.googletagmanager.com/gtag/js?id={{ site.ga_track_id }}'; |
| 514 | + s.async = true; |
| 515 | + document.head.appendChild(s); |
504 | 516 | window.dataLayer = window.dataLayer || []; |
505 | 517 | function gtag(){dataLayer.push(arguments);} |
506 | 518 | gtag('js', new Date()); |
507 | 519 | gtag('config', '{{ site.ga_track_id }}', { |
508 | 520 | cookie_flags: 'SameSite=Strict;Secure', |
509 | 521 | anonymize_ip: true |
510 | 522 | }); |
511 | | - }, 1000); // Delay 1s to prioritize rendering |
512 | | - }); |
| 523 | + } |
| 524 | + // Load on user interaction or after 3s idle |
| 525 | + if ('requestIdleCallback' in window) { |
| 526 | + requestIdleCallback(loadGA, { timeout: 3000 }); |
| 527 | + } else { |
| 528 | + setTimeout(loadGA, 3000); |
| 529 | + } |
| 530 | + ['scroll', 'click', 'touchstart'].forEach(function(e) { |
| 531 | + window.addEventListener(e, loadGA, { once: true, passive: true }); |
| 532 | + }); |
| 533 | + })(); |
513 | 534 | </script> |
514 | 535 | {% endif %} |
0 commit comments