Quick Start Labels
https://vanillawebdev.blogspot.com/search/label/coding-tips
Coding Tips
4
https://vanillawebdev.blogspot.com/search/label/project-setup
Project Setup
6
https://vanillawebdev.blogspot.com/search/label/starter-code
Starter Code
6
Reading List
https://jackwhiting.co.uk/posts/lazy-loading-vanilla-js-with-webpack-laravel-mix
https://medium.com/free-code-camp/reducing-css-bundle-size-70-by-cutting-the-class-names-and-using-scope-isolation-625440de600b
Libraries
https://github.com/verlok/vanilla-lazyload
Developer Resources
https://webpack.js.org/configuration/output/
https://web.dev/articles/preload-critical-assets
Reading List
https://www.codemzy.com/blog/how-to-name-webpack-chunk
How to name a webpack chunk (including split and common chunks)
Reading List
Featured Post
https://vanillawebdev.blogspot.com/2024/02/installable-web-app.html
Make Your Web App Installable
February 16, 2025How to make your web app installable.
true
https://vanillawebdev.blogspot.com/search/label/homepage
homepage
https://vanillawebdev.blogspot.com/search/label/project-setup
project-setup
Featured Post
Sidebar Labels
https://vanillawebdev.blogspot.com/search/label/app-component
App Component
1
https://vanillawebdev.blogspot.com/search/label/coding-tips
Coding Tips
4
https://vanillawebdev.blogspot.com/search/label/css-tips
CSS Tips
4
https://vanillawebdev.blogspot.com/search/label/data-server
Data Server
2
https://vanillawebdev.blogspot.com/search/label/layout
Layout
1
https://vanillawebdev.blogspot.com/search/label/project-setup
Project Setup
6
https://vanillawebdev.blogspot.com/2025/02/offline-first-experience-setup.html
https://vanillawebdev.blogspot.com/2025/02/overlay-sidebar.html
https://vanillawebdev.blogspot.com/
https://vanillawebdev.blogspot.com/2025/02/ripple-effect-css-js.html
Ripple Effect CSS JS
February 14, 2025
2025
February
14
11:26 PM
Ripple effect UI states with CSS and JavaScript.
HTML
<button class="_rippleFx">
[s 'Ripple Effect' ._label]
</button>
CSS
button {
position: relative;
overflow: hidden;
}
body {
background: dimgrey;
}
button {
position: relative;
color: #fff;
background-color: #6200ee;
padding: 1rem 2rem;
outline: 0;
border: 0;
}
span.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
animation: ripple 600ms linear;
background-color: rgba(255, 255, 255, 0.7);
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
JS
// @ts-check
function createRipple(event) {
let uiState = uiStates.createRippleState(event.target.closest('._rippleFx'));
uiState.createRipple(event);
}
const nodes = document.querySelectorAll('._rippleFx');
for (const node of nodes) {
node.addEventListener('click', createRipple);
}
let uiStates = (() => {
/**
@typedef {Object} RippleState
@property {HTMLElement[]} _pool
@property {HTMLElement} containerEl
@property {string} rippleClass - default: "ripple"
@property {function(MouseEvent): void} createRipple
@property {function(MouseEvent): void} _restoreToPool
*/
// # active class state
/** @type {RippleState} */
let rippleState = {
/** @private */
_pool: [
document.createElement('span'),
document.createElement('span'),
],
rippleClass: 'ripple',
containerEl: document.createElement('div'),
_restoreToPool(event) {
const rippleEl = /** @type {HTMLElement} */ (event.target);
this._pool.push(rippleEl)
rippleEl.remove();
},
createRipple(clickEvt) {
if (this._pool.length == 0) {
this._pool.push(document.createElement('span'))
};
const containerEl = this.containerEl;
const rippleEl = /** @type {HTMLElement} */ (this._pool.shift());
const diameter = Math.max(containerEl.clientWidth, containerEl.clientHeight);
const radius = diameter / 2;
rippleEl.style.width = rippleEl.style.height = `${diameter}px`;
rippleEl.style.left = `${clickEvt.clientX - (containerEl.offsetLeft + radius)}px`;
rippleEl.style.top = `${clickEvt.clientY - (containerEl.offsetTop + radius)}px`;
rippleEl.classList.add(this.rippleClass);
// add listener once
if (!rippleEl.onanimationend) {
rippleEl.addEventListener('animationend', this._restoreToPool.bind(this));
rippleEl.onanimationend = () => {}
}
containerEl.appendChild(rippleEl);
}
};
let SELF = {
createRippleState(containerEl) {
/** @type {RippleState} */
const uiState = Object.create(rippleState);
uiState.containerEl = containerEl;
return uiState;
},
}
return SELF;
})();
https://www.blogger.com/comment/fullpage/post/8166404610182826392/4500338749860945428
true
https://vanillawebdev.blogspot.com/search/label/%40lvc
@lvc
https://vanillawebdev.blogspot.com/search/label/Effects
Effects
https://vanillawebdev.blogspot.com/2025/02/offline-first-experience-setup.html
https://vanillawebdev.blogspot.com/2025/02/overlay-sidebar.html
https://vanillawebdev.blogspot.com/