Page jitter: setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);
Page Jitter: setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);
Page jitter is a common visual effect that creates a shaking sensation by rapidly altering an element's position. Combining setInterval
with a random number generator easily achieves this dynamic change. The following code adjusts the left margin of the body
element randomly every 50 milliseconds, producing a left-right wobbling visual effect:
setInterval(() => {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
}, 50);
Implementation Principle Analysis
This code revolves around three key points: timers, random number calculations, and style modifications. Math.random()
generates a floating-point number between 0 and 1. Multiplying it by 20 scales the range to 0-20, and subtracting 10 yields a range of -10 to 10. This ensures each execution produces a different negative or positive value:
// Breakdown of random number generation
const randomValue = Math.random(); // 0 ≤ x < 1
const scaledValue = randomValue * 20; // 0 ≤ x < 20
const finalValue = scaledValue - 10; // -10 ≤ x < 10
The timer interval of 50 milliseconds (i.e., 20 frames per second) ensures smooth animation. This frequency is close to the limit of human visual persistence, creating a continuous animation effect without appearing choppy.
Practical Application Scenarios
Though simple, this jitter effect is highly practical in specific scenarios:
- Enhanced Error Notifications: Lightly shake an input field when form validation fails.
function shakeElement(element) {
let count = 0;
const interval = setInterval(() => {
element.style.transform = `translateX(${Math.random() * 6 - 3}px)`;
if(++count >= 10) clearInterval(interval);
}, 50);
}
- Game Effects: Feedback when a character takes damage.
// Example of character jitter in games
const character = document.getElementById('game-character');
function takeDamage() {
const originalPosition = character.getBoundingClientRect().left;
const interval = setInterval(() => {
character.style.left = originalPosition + (Math.random() * 10 - 5) + 'px';
}, 30);
setTimeout(() => clearInterval(interval), 300);
}
- Attention Guidance: Draw user attention to specific interface elements.
function highlightElement(element) {
const originalMargin = element.style.marginLeft;
const interval = setInterval(() => {
element.style.marginLeft = (Math.random() * 15 - 7.5) + 'px';
}, 40);
// Stop after 3 seconds
setTimeout(() => {
clearInterval(interval);
element.style.marginLeft = originalMargin;
}, 3000);
}
Performance Optimization Solutions
The original implementation, while simple, has performance drawbacks. Here are optimization approaches:
- Replace
setInterval
withrequestAnimationFrame
function startShake() {
let lastTime = 0;
function shake(timestamp) {
if(timestamp - lastTime > 50) {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
lastTime = timestamp;
}
requestAnimationFrame(shake);
}
requestAnimationFrame(shake);
}
- CSS Animation Solution (Better Performance)
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake-element {
animation: shake 0.5s linear infinite;
}
- Limit Jitter Range to Avoid Layout Reflows
// Use transform instead of margin
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
}, 50);
Advanced Variants
More complex effects can be built upon the basic jitter:
- 3D Jitter (Add Y and Z-axis variations)
setInterval(() => {
const x = Math.random() * 10 - 5;
const y = Math.random() * 8 - 4;
document.body.style.transform = `translate3d(${x}px, ${y}px, 0)`;
}, 50);
- Decaying Jitter (Amplitude gradually decreases)
function decayingShake(element, duration = 1000) {
const startTime = Date.now();
const maxOffset = 15;
function update() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
const currentOffset = maxOffset * (1 - progress);
if(progress < 1) {
element.style.transform = `translateX(${(Math.random() * 2 - 1) * currentOffset}px)`;
requestAnimationFrame(update);
} else {
element.style.transform = '';
}
}
update();
}
- Rhythmic Jitter (Sync with music beats)
// Assuming audio analysis data is available
function beatShake(analyser) {
analyser.getByteFrequencyData(frequencyData);
const bass = frequencyData[0] / 255;
document.body.style.transform = `translateX(${bass * 20 - 10}px)`;
requestAnimationFrame(() => beatShake(analyser));
}
Browser Compatibility Considerations
Different browsers handle high-frequency style changes differently:
- Legacy IE Limitations:
// Special handling for IE9 and below
if(document.documentMode && document.documentMode < 10) {
// Simpler jitter approach
let toggle = false;
setInterval(() => {
document.body.style.marginLeft = toggle ? '5px' : '-5px';
toggle = !toggle;
}, 100);
} else {
// Standard implementation for modern browsers
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
}, 50);
}
- Mobile Optimization:
// Reduce amplitude on touch devices
const isTouchDevice = 'ontouchstart' in window;
const amplitude = isTouchDevice ? 5 : 10;
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * amplitude * 2 - amplitude}px)`;
}, 50);
Debugging Techniques
Debugging may be needed during development:
- Performance Analysis:
// Measure execution time
setInterval(() => {
const start = performance.now();
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
console.log('Execution time:', performance.now() - start);
}, 50);
- Amplitude Visualization:
// Add debug panel
const debugPanel = document.createElement('div');
debugPanel.style.position = 'fixed';
debugPanel.style.bottom = '0';
document.body.appendChild(debugPanel);
setInterval(() => {
const value = Math.random() * 20 - 10;
document.body.style.marginLeft = value + 'px';
debugPanel.textContent = `Current amplitude: ${value.toFixed(2)}px`;
}, 50);
- Frame Rate Monitoring:
let lastTime = performance.now();
let frameCount = 0;
setInterval(() => {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
frameCount++;
const now = performance.now();
if(now - lastTime >= 1000) {
console.log(`Current FPS: ${frameCount}`);
frameCount = 0;
lastTime = now;
}
}, 50);
Integration with Animation Libraries
Basic jitter can be integrated with professional animation libraries:
- GSAP Implementation:
import { gsap } from "gsap";
function gsapShake(element) {
gsap.to(element, {
x: () => Math.random() * 20 - 10,
duration: 0.05,
repeat: -1
});
}
- Anime.js Version:
import anime from 'animejs';
anime({
targets: document.body,
translateX: () => Math.random() * 20 - 10,
duration: 50,
loop: true
});
- React Component Encapsulation:
function ShakyComponent({ children, intensity = 10 }) {
const [offset, setOffset] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setOffset(Math.random() * intensity * 2 - intensity);
}, 50);
return () => clearInterval(interval);
}, [intensity]);
return (
<div style={{ transform: `translateX(${offset}px)` }}>
{children}
</div>
);
}
Physics Engine Simulation
More realistic jitter can incorporate physics parameters:
- Velocity Decay Model:
let velocity = 0;
let position = 0;
const friction = 0.9;
function physicsShake() {
// Apply random force
velocity += (Math.random() - 0.5) * 2;
// Apply physics
velocity *= friction;
position += velocity;
// Limit boundaries
if(Math.abs(position) > 15) {
position = Math.sign(position) * 15;
velocity *= -0.5;
}
document.body.style.transform = `translateX(${position}px)`;
requestAnimationFrame(physicsShake);
}
physicsShake();
- Spring Jitter Model:
let position = 0;
let velocity = 0;
const spring = 0.1;
const damping = 0.8;
function springShake() {
// Random target position
const target = Math.random() * 20 - 10;
// Spring physics
const acceleration = (target - position) * spring;
velocity += acceleration;
velocity *= damping;
position += velocity;
document.body.style.transform = `translateX(${position}px)`;
requestAnimationFrame(springShake);
}
springShake();
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn