perf(core): replace lazysizes with browser-level lazy loading (#1267)

This commit is contained in:
Cotes Chung 2023-09-27 04:44:32 +08:00 committed by GitHub
parent 5015fdecf3
commit bf3a34d054
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 171 additions and 226 deletions

View file

@ -35,8 +35,9 @@ magnific-popup:
css: /assets/lib/magnific-popup/magnific-popup.css css: /assets/lib/magnific-popup/magnific-popup.css
js: /assets/lib/magnific-popup/jquery.magnific-popup.min.js js: /assets/lib/magnific-popup/jquery.magnific-popup.min.js
lazysizes: lazy-polyfill:
js: /assets/lib/lazysizes/lazysizes.min.js css: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.min.css
js: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.umd.min.js
clipboard: clipboard:
js: /assets/lib/clipboard/clipboard.min.js js: /assets/lib/clipboard/clipboard.min.js

View file

@ -46,8 +46,9 @@ magnific-popup:
css: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/magnific-popup.min.css css: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/magnific-popup.min.css
js: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/jquery.magnific-popup.min.js js: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/jquery.magnific-popup.min.js
lazysizes: lazy-polyfill:
js: https://cdn.jsdelivr.net/npm/lazysizes@5.3.2/lazysizes.min.js css: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.min.css
js: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.umd.min.js
clipboard: clipboard:
js: https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js js: https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js

View file

@ -1,4 +1,7 @@
<iframe class="embed-video twitch lazyload" <iframe
class="embed-video twitch"
src="https://player.twitch.tv/?video={{ include.id }}&parent={{ site.url | split: '://' | last | remove: '/' }}" src="https://player.twitch.tv/?video={{ include.id }}&parent={{ site.url | split: '://' | last | remove: '/' }}"
frameborder="0" allowfullscreen="true" frameborder="0"
scrolling="no"></iframe> allowfullscreen="true"
scrolling="no"
></iframe>

View file

@ -1,6 +1,9 @@
<iframe class="embed-video youtube lazyload" <iframe
class="embed-video youtube"
loading="lazy"
src="https://www.youtube.com/embed/{{ include.id }}" src="https://www.youtube.com/embed/{{ include.id }}"
title="YouTube video player" title="YouTube video player"
frameborder="0" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe> allowfullscreen
></iframe>

View file

@ -80,6 +80,10 @@
<link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}"> <link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}">
{% endif %} {% endif %}
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
<link rel="stylesheet" href="{{ site.data.origin[type]['lazy-polyfill'].css | relative_url }}">
{% endif %}
{% if page.layout == 'page' or page.layout == 'post' %} {% if page.layout == 'page' or page.layout == 'post' %}
<!-- Manific Popup --> <!-- Manific Popup -->
<link rel="stylesheet" href="{{ site.data.origin[type].magnific-popup.css | relative_url }}"> <link rel="stylesheet" href="{{ site.data.origin[type].magnific-popup.css | relative_url }}">

View file

@ -12,7 +12,7 @@
<!-- layout specified --> <!-- layout specified -->
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %} {% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
{% assign urls = urls | append: ',' | append: site.data.origin[type].lazysizes.js %} {% assign urls = urls | append: ',' | append: site.data.origin[type]['lazy-polyfill'].js %}
{% unless page.layout == 'home' %} {% unless page.layout == 'home' %}
<!-- image lazy-loading & popup & clipboard --> <!-- image lazy-loading & popup & clipboard -->

View file

@ -30,6 +30,7 @@
{% endif %} {% endif %}
<!-- Change the icon of checkbox --> <!-- Change the icon of checkbox -->
{% if _content contains '<input type="checkbox"' %} {% if _content contains '<input type="checkbox"' %}
{% assign _content = _content {% assign _content = _content
| replace: '<input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />', | replace: '<input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />',
@ -39,7 +40,8 @@
%} %}
{% endif %} {% endif %}
<!-- images --> <!-- Handle images -->
{% assign IMG_TAG = '<img ' %} {% assign IMG_TAG = '<img ' %}
{% if _content contains IMG_TAG %} {% if _content contains IMG_TAG %}
@ -79,8 +81,6 @@
{% assign _left = _left | remove: ' /' | replace: ' w=', ' width=' | replace: ' h=', ' height=' %} {% assign _left = _left | remove: ' /' | replace: ' w=', ' width=' | replace: ' h=', ' height=' %}
{% assign _attrs = _left | split: '" ' %} {% assign _attrs = _left | split: '" ' %}
{% assign _width = null %}
{% assign _height = null %}
{% assign _lqip = null %} {% assign _lqip = null %}
{% assign _class = null %} {% assign _class = null %}
@ -94,10 +94,6 @@
{% capture _value %}{{ _pair | last | remove: '"' }}{% endcapture %} {% capture _value %}{{ _pair | last | remove: '"' }}{% endcapture %}
{% case _key %} {% case _key %}
{% when 'width' %}
{% assign _width = _value %}
{% when 'height' %}
{% assign _height = _value %}
{% when 'src' %} {% when 'src' %}
{% assign _src = _value %} {% assign _src = _value %}
{% when 'lqip' %} {% when 'lqip' %}
@ -114,47 +110,33 @@
{% endif %} {% endif %}
{% assign _final_src = null %} {% assign _final_src = null %}
{% assign _lazyload = true %}
{% unless _src contains '//' %} {% unless _src contains '//' %}
{% assign _final_src = _path_prefix | append: _src %} {% assign _final_src = _path_prefix | append: _src %}
{% capture _src_from %}"{{ _src }}"{% endcapture %} {% assign _src_alt = 'src="' | append: _path_prefix %}
{% capture _src_to %}"{{ _final_src }}"{% endcapture %} {% assign _left = _left | replace: 'src="', _src_alt %}
{% assign _left = _left | replace: _src_from, _src_to %}
{% endunless %} {% endunless %}
{% if _lqip %} {% if _lqip %}
{% unless _lqip contains ':' %} {% if _lqip contains ':' %}
{% assign _final_lqip = _path_prefix | append: _lqip %} {% assign _lazyload = false %}
{% capture _lqip_from %}"{{ _lqip }}"{% endcapture %}
{% capture _lqip_to %}"{{ _final_lqip }}"{% endcapture %}
{% assign _left = _left | replace: _lqip_from, _lqip_to %}
{% endunless %}
{% endif %}
<!-- lazy-load images <https://github.com/aFarkas/lazysizes#readme> -->
{% assign _left = _left | replace: 'src=', 'data-src=' %}
{% if _left contains 'class=' %}
{% assign _left = _left | replace: 'class="', 'class="lazyload ' %}
{% else %} {% else %}
{% assign _left = _left | append: ' class="lazyload"' %} {% assign _lqip_alt = 'lqip="' | append: _path_prefix %}
{% assign _left = _left | replace: 'lqip="', _lqip_alt %}
{% endif %} {% endif %}
<!-- add image placeholder --> <!-- add image placeholder -->
{% if _lqip %} {% assign _left = _left | replace: 'src=', 'data-src=' | replace: ' lqip=', ' data-lqip="true" src=' %}
{% assign _left = _left | replace: ' lqip=', ' data-lqip="true" src=' %}
{% else %} {% else %}
{% if _width and _height %}
<!-- add SVG placehoder -->
{%- capture _svg -%}
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 {{ _width }} {{ _height }}'%3E%3C/svg%3E"
{%- endcapture -%}
{% assign _left = _svg | append: ' ' | append: _left %}
{% assign _class = _class | append: ' shimmer' %} {% assign _class = _class | append: ' shimmer' %}
{% endif %} {% endif %}
{% endif %}
<!-- Bypass the HTML-proofer test --> <!-- lazy-load images -->
{% assign _left = _left | append: ' data-proofer-ignore' %} {% if _lazyload %}
{% assign _left = _left | append: ' loading="lazy"' %}
{% endif %}
{% if page.layout == 'home' %} {% if page.layout == 'home' %}
<!-- create the image wrapper --> <!-- create the image wrapper -->
@ -174,6 +156,7 @@
class="img-link{% unless _lqip %} shimmer{% endunless %}" class="img-link{% unless _lqip %} shimmer{% endunless %}"
{% endcapture %} {% endcapture %}
{% assign _img_content = _img_content | slice: 0, _size | append: _class | append: '>' %} {% assign _img_content = _img_content | slice: 0, _size | append: _class | append: '>' %}
{% else %} {% else %}
<!-- create the image wrapper --> <!-- create the image wrapper -->
{% assign _wrapper_start = _final_src {% assign _wrapper_start = _final_src
@ -185,12 +168,12 @@
%} %}
{% assign _img_content = _img_content | append: _wrapper_start %} {% assign _img_content = _img_content | append: _wrapper_start %}
{% assign _right = _right | prepend: '></a' %} {% assign _right = '></a' | append: _right %}
{% endif %} {% endif %}
{% endif %} {% endif %}
<!-- combine --> <!-- combine -->
{% assign _img_content = _img_content | append: debug | append: IMG_TAG | append: _left | append: _right %} {% assign _img_content = _img_content | append: IMG_TAG | append: _left | append: _right %}
{% endfor %} {% endfor %}
{% if _img_content %} {% if _img_content %}

View file

@ -1,8 +1,8 @@
import { basic, initSidebar, initTopbar } from './modules/layouts'; import { basic, initSidebar, initTopbar } from './modules/layouts';
import { initLocaleDatetime, imgLazy } from './modules/plugins'; import { initLocaleDatetime, loadImg } from './modules/plugins';
basic(); basic();
initSidebar(); initSidebar();
initTopbar(); initTopbar();
initLocaleDatetime(); initLocaleDatetime();
imgLazy(); loadImg();

View file

@ -1,27 +0,0 @@
/**
* Set up image lazy-load
*/
function stopShimmer($node) {
$node.parent().removeClass('shimmer');
}
export function imgLazy() {
const $images = $('main img[data-src]');
if ($images.length <= 0) {
return;
}
/* Stop shimmer when image loaded */
document.addEventListener('lazyloaded', function (e) {
stopShimmer($(e.target));
});
/* Stop shimmer from cached images */
$images.each(function () {
if ($(this).hasClass('ls-is-cached')) {
stopShimmer($(this));
}
});
}

View file

@ -0,0 +1,31 @@
/**
* Setting up image lazy loading and LQIP switching
*/
export function loadImg() {
const $images = $('main img[loading="lazy"]');
const $lqip = $('main img[data-lqip="true"]');
if ($images.length > 0) {
$images.on('load', function () {
/* Stop shimmer when image loaded */
$(this).parent().removeClass('shimmer');
});
$images.each(function () {
/* Images loaded from the browser cache do not trigger the 'load' event */
if ($(this).prop('complete')) {
$(this).parent().removeClass('shimmer');
}
});
}
if ($lqip.length > 0) {
$lqip.each(function () {
/* Switch LQIP with real image url */
const dataSrc = $(this).attr('data-src');
$(this).attr('src', encodeURI(dataSrc));
$(this).removeAttr('data-src data-lqip');
});
}
}

View file

@ -1,6 +1,6 @@
export { categoryCollapse } from './components/category-collapse'; export { categoryCollapse } from './components/category-collapse';
export { initClipboard } from './components/clipboard'; export { initClipboard } from './components/clipboard';
export { imgLazy } from './components/img-lazyload'; export { loadImg } from './components/img-loading';
export { imgPopup } from './components/img-popup'; export { imgPopup } from './components/img-popup';
export { initLocaleDatetime } from './components/locale-datetime'; export { initLocaleDatetime } from './components/locale-datetime';
export { toc } from './components/toc'; export { toc } from './components/toc';

View file

@ -1,9 +1,9 @@
import { basic, initSidebar, initTopbar } from './modules/layouts'; import { basic, initSidebar, initTopbar } from './modules/layouts';
import { imgLazy, imgPopup, initClipboard } from './modules/plugins'; import { loadImg, imgPopup, initClipboard } from './modules/plugins';
basic(); basic();
initSidebar(); initSidebar();
initTopbar(); initTopbar();
imgLazy(); loadImg();
imgPopup(); imgPopup();
initClipboard(); initClipboard();

View file

@ -1,6 +1,6 @@
import { basic, initSidebar, initTopbar } from './modules/layouts'; import { basic, initSidebar, initTopbar } from './modules/layouts';
import { import {
imgLazy, loadImg,
imgPopup, imgPopup,
initLocaleDatetime, initLocaleDatetime,
initClipboard, initClipboard,
@ -10,7 +10,7 @@ import {
basic(); basic();
initSidebar(); initSidebar();
initTopbar(); initTopbar();
imgLazy(); loadImg();
imgPopup(); imgPopup();
initLocaleDatetime(); initLocaleDatetime();
initClipboard(); initClipboard();

View file

@ -1,6 +1,5 @@
--- ---
layout: compress layout: compress
# Default layout
--- ---
<!doctype html> <!doctype html>

View file

@ -39,10 +39,13 @@ layout: default
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% capture content %} {% capture _content %}
<div id="post-list" class="flex-grow-1 pe-xl-2">
{% for post in posts %} {% for post in posts %}
<article class="card-wrapper"> <article class="card-wrapper card">
<a href="{{ post.url | relative_url }}" class="card post-preview flex-md-row-reverse"> <a href="{{ post.url | relative_url }}" class="post-preview row g-0 flex-md-row-reverse">
{% assign card_body_col = '12' %}
{% if post.image %} {% if post.image %}
{% if post.image.lqip %} {% if post.image.lqip %}
{% capture lqip %}lqip="{{ post.image.lqip }}"{% endcapture %} {% capture lqip %}lqip="{{ post.image.lqip }}"{% endcapture %}
@ -55,13 +58,18 @@ layout: default
{% assign alt = post.image.alt | xml_escape | default: 'Preview Image' %} {% assign alt = post.image.alt | xml_escape | default: 'Preview Image' %}
<img src="{{ src }}" w="17" h="10" alt="{{ alt }}" {{ lqip }}> <div class="col-md-5">
<img src="{{ src }}" alt="{{ alt }}" {{ lqip }}>
</div>
{% assign card_body_col = '7' %}
{% endif %} {% endif %}
<div class="col-md-{{ card_body_col }}">
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<h1 class="card-title my-2 mt-md-0">{{ post.title }}</h1> <h1 class="card-title my-2 mt-md-0">{{ post.title }}</h1>
<div class="card-text content mt-0 mb-2"> <div class="card-text content mt-0 mb-3">
<p> <p>
{% include no-linenos.html content=post.content %} {% include no-linenos.html content=post.content %}
{{ content | markdownify | strip_html | truncate: 200 | escape }} {{ content | markdownify | strip_html | truncate: 200 | escape }}
@ -96,15 +104,15 @@ layout: default
<!-- .post-meta --> <!-- .post-meta -->
</div> </div>
<!-- .card-body --> <!-- .card-body -->
</div>
</a> </a>
</article> </article>
{% endfor %} {% endfor %}
{% endcapture %}
<div id="post-list" class="flex-grow-1 pe-xl-2">
{% include refactor-content.html content=content lang=lang %}
</div> </div>
<!-- #post-list --> <!-- #post-list -->
{% endcapture %}
{% include refactor-content.html content=_content lang=lang %}
{% if paginator.total_pages > 1 %} {% if paginator.total_pages > 1 %}
{% include post-paginator.html %} {% include post-paginator.html %}

View file

@ -71,54 +71,13 @@ a {
img { img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
transition: all 0.35s ease-in-out; transition: all 0.7s ease-in-out;
&[data-src] {
&[data-lqip='true'] { &[data-lqip='true'] {
&.lazyload, $blur: 20px;
&.lazyloading {
-webkit-filter: blur(20px);
filter: blur(20px);
}
}
&:not([data-lqip='true']) { -webkit-filter: blur($blur);
&.lazyload, filter: blur($blur);
&.lazyloading {
background: var(--img-bg);
}
&.lazyloaded {
-webkit-animation: fade-in 0.35s ease-in;
animation: fade-in 0.35s ease-in;
}
}
&.shadow {
-webkit-filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.08));
filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.08));
box-shadow: none !important; /* cover the Bootstrap 4.6.1 styles */
}
@extend %img-caption;
}
@-webkit-keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
} }
} }
@ -349,6 +308,29 @@ sup {
/* --- post --- */ /* --- post --- */
.preview-img {
aspect-ratio: 40 / 21;
width: 100%;
height: 100%;
overflow: hidden;
@extend %rounded;
&:not(.no-bg) {
img {
background: var(--img-bg);
}
}
img {
height: 100%;
-o-object-fit: cover;
object-fit: cover;
@extend %rounded;
}
}
.post-preview { .post-preview {
@extend %rounded; @extend %rounded;
@ -384,7 +366,6 @@ main {
} }
p { p {
> img[data-src],
> a.popup { > a.popup {
&:not(.normal):not(.left):not(.right) { &:not(.normal):not(.left):not(.right) {
@include align-center; @include align-center;
@ -538,8 +519,8 @@ main {
background: var(--shimmer-bg); background: var(--shimmer-bg);
height: 100%; height: 100%;
width: 100%; width: 100%;
-webkit-animation: shimmer 1s infinite; -webkit-animation: shimmer 1.3s infinite;
animation: shimmer 1s infinite; animation: shimmer 1.3s infinite;
} }
@-webkit-keyframes shimmer { @-webkit-keyframes shimmer {

View file

@ -6,8 +6,6 @@
margin-top: 2rem; margin-top: 2rem;
.card-wrapper { .card-wrapper {
display: block;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
} }
@ -18,27 +16,23 @@
} }
.card { .card {
border: 0;
background: none;
%img-radius { %img-radius {
border-radius: $base-radius $base-radius 0 0; border-radius: $base-radius $base-radius 0 0;
} }
.preview-img { .preview-img {
height: 10rem;
@extend %img-radius; @extend %img-radius;
img { img {
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
@extend %img-radius; @extend %img-radius;
} }
} }
.card-body { .card-body {
min-height: 10.5rem; height: 100%;
padding: 1rem; padding: 1rem;
.card-title { .card-title {
@ -136,20 +130,13 @@
/* Tablet */ /* Tablet */
@media all and (min-width: 768px) { @media all and (min-width: 768px) {
#post-list {
%img-radius { %img-radius {
border-radius: 0 $base-radius $base-radius 0; border-radius: 0 $base-radius $base-radius 0;
} }
#post-list {
.card { .card {
.preview-img {
width: 20rem;
height: 11.55rem; // can hold 2 lines each for title and content
}
.card-body { .card-body {
min-height: 10.75rem;
width: 60%;
padding: 1.75rem 1.75rem 1.25rem 1.75rem; padding: 1.75rem 1.75rem 1.25rem 1.75rem;
.card-text { .card-text {

View file

@ -26,26 +26,6 @@
color: var(--text-color); color: var(--text-color);
} }
.preview-img {
overflow: hidden;
aspect-ratio: 40 / 21;
@extend %rounded;
&:not(.no-bg) {
img.lazyloaded {
background: var(--img-bg);
}
}
img {
-o-object-fit: cover;
object-fit: cover;
@extend %rounded;
}
}
h1 + .post-meta { h1 + .post-meta {
> span + span::before { > span + span::before {
@include dot; @include dot;
@ -368,10 +348,6 @@ h1 + .post-meta {
} }
@media all and (max-width: 576px) { @media all and (max-width: 576px) {
.preview-img[data-src] {
margin-top: 2.2rem;
}
.post-tail-bottom { .post-tail-bottom {
flex-wrap: wrap-reverse !important; flex-wrap: wrap-reverse !important;
@ -396,9 +372,4 @@ h1 + .post-meta {
margin-left: -0.5rem; margin-left: -0.5rem;
margin-right: -0.5rem; margin-right: -0.5rem;
} }
.preview-img[data-src] {
max-width: 100vw;
border-radius: 0;
}
} }

@ -1 +1 @@
Subproject commit 6737eab720e4cdd8330d32053053356f200d8819 Subproject commit f80ba2f1616496cba34f3fd3eef1564d8fa843cd