Wydajność strony internetowej ma bezpośredni wpływ na doświadczenie użytkowników, konwersje i pozycje w wyszukiwarkach. Badania pokazują, że już 100ms opóźnienia może zmniejszyć konwersje o 7%. Poznaj sprawdzone techniki optymalizacji, które znacząco przyspieszą Twoją stronę.
📊 Core Web Vitals - Kluczowe metryki
Google wprowadził Core Web Vitals jako oficjalny czynnik rankingowy. To trzy kluczowe metryki, które mierzą rzeczywiste doświadczenie użytkowników:
Jak mierzyć Core Web Vitals?
- Google PageSpeed Insights - darmowe narzędzie z rekomendacjami
- Chrome DevTools - Performance tab do szczegółowej analizy
- Search Console - dane z rzeczywistego ruchu
- Web Vitals Extension - Chrome rozszerzenie
🖼️ Optymalizacja obrazów
Obrazy często stanowią 60-70% rozmiaru strony. Ich optymalizacja może drastycznie poprawić wydajność.
Nowoczesne formaty obrazów
<!-- Responsive images z nowoczesnymi formatami -->
<picture>
<source type="image/avif" srcset="image.avif">
<source type="image/webp" srcset="image.webp">
<img src="image.jpg"
alt="Description"
width="800"
height="600"
loading="lazy">
</picture>
<!-- Responsive images z różnymi rozmiarami -->
<img srcset="small.webp 400w,
medium.webp 800w,
large.webp 1200w"
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
800px"
src="medium.webp"
alt="Description"
loading="lazy">
Lazy Loading
/* CSS-based lazy loading */
.lazy-image {
opacity: 0;
transition: opacity 0.3s;
}
.lazy-image.loaded {
opacity: 1;
}
/* Intersection Observer dla custom lazy loading */
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.add('loaded');
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
💡 Kompresja obrazów
Używaj narzędzi do kompresji: ImageOptim, TinyPNG, Squoosh. AVIF oferuje o 50% lepszą kompresję niż JPEG przy podobnej jakości.
⚡ Optymalizacja zasobów
Minifikacja i kompresja
/* Gzip/Brotli compression w .htaccess */
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
/* Resource hints */
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://api.example.com">
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/hero-image.webp" as="image">
Critical CSS
<!-- Inline critical CSS -->
<style>
/* Critical above-the-fold styles */
body { margin: 0; font-family: system-ui; }
.header { height: 60px; background: #fff; }
.hero { min-height: 100vh; background: #3B82F6; }
</style>
<!-- Async load non-critical CSS -->
<link rel="preload" href="styles.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
<script>
// JavaScript fallback for CSS loading
if (!window.HTMLLinkElement || !HTMLLinkElement.prototype.hasOwnProperty('onload')) {
var links = document.querySelectorAll('link[rel="preload"][as="style"]');
links.forEach(function(link) {
link.rel = 'stylesheet';
});
}
</script>
🚀 JavaScript Performance
Code Splitting i Dynamic Imports
// Dynamic imports dla lazy loading modułów
async function loadComponent() {
const { default: Component } = await import('./Component.js');
return Component;
}
// Webpack code splitting
import(/* webpackChunkName: "chart" */ './chart.js')
.then(module => {
const chart = new module.Chart();
chart.render();
});
// Route-based code splitting w React
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Profile = lazy(() => import('./Profile'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
);
}
Optymalizacja JavaScript
// Debouncing dla input events
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
const optimizedSearch = debounce((query) => {
fetchSearchResults(query);
}, 300);
// Throttling dla scroll events
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
const optimizedScrollHandler = throttle(() => {
// Scroll handling logic
}, 100);
💾 Strategia cache'owania
HTTP Cache Headers
# Browser caching w .htaccess
<IfModule mod_expires.c>
ExpiresActive on
# Images
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
ExpiresByType image/avif "access plus 1 month"
# CSS and JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Fonts
ExpiresByType font/woff2 "access plus 1 year"
# HTML
ExpiresByType text/html "access plus 1 day"
</IfModule>
# Cache Control Headers
<IfModule mod_headers.c>
<filesMatch "\.(css|js|png|jpg|jpeg|gif|webp|avif|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>
<filesMatch "\.(html)$">
Header set Cache-Control "max-age=86400, public, must-revalidate"
</filesMatch>
</IfModule>
Service Worker dla zaawansowanego cache'owania
// Service Worker registration
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
// Service Worker - sw.js
const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/css/style.css',
'/js/script.js',
'/images/logo.webp'
];
// Cache resources
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
// Serve cached resources
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
}
)
);
});
📱 Mobile Performance
Touch Optimization
/* Touch-friendly buttons */
.button {
min-height: 44px;
min-width: 44px;
padding: 12px 24px;
touch-action: manipulation;
}
/* Reduce input latency */
input, button {
touch-action: manipulation;
}
/* Prevent zoom on input focus iOS */
input, select, textarea {
font-size: 16px;
}
/* Optimize scroll performance */
.scrollable {
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
}
Network Optimization dla mobile
// Adaptive loading based on connection
if ('connection' in navigator) {
const connection = navigator.connection;
if (connection.effectiveType === '4g') {
// Load high-quality assets
loadHighQualityImages();
} else {
// Load optimized assets for slower connections
loadOptimizedImages();
}
}
// Preload critical resources only on fast connections
if (navigator.connection && navigator.connection.effectiveType === '4g') {
const link = document.createElement('link');
link.rel = 'preload';
link.href = '/large-hero-image.webp';
link.as = 'image';
document.head.appendChild(link);
}
🔧 Narzędzia do monitorowania wydajności
Real User Monitoring (RUM)
// Performance API dla custom metrics
const perfObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'navigation') {
console.log('Page Load Time:', entry.loadEventEnd - entry.fetchStart);
}
if (entry.entryType === 'paint') {
console.log(entry.name, entry.startTime);
}
});
});
perfObserver.observe({entryTypes: ['navigation', 'paint']});
// Web Vitals measurement
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getFCP(console.log);
getLCP(console.log);
getTTFB(console.log);
🎯 Performance Budget
📏 Zalecane budżety wydajności
- JavaScript: < 170KB gzipped
- CSS: < 60KB gzipped
- Fonts: < 100KB total
- Images: < 500KB above-the-fold
- Total page weight: < 1MB
- HTTP requests: < 50 resources
🚀 Advanced Techniques
HTTP/2 Push i Server-Side Rendering
// HTTP/2 Server Push headers
Link: </css/critical.css>; rel=preload; as=style
Link: </js/app.js>; rel=preload; as=script
Link: </fonts/main.woff2>; rel=preload; as=font; crossorigin
// SSR z Next.js dla lepszego TTFB
export async function getServerSideProps(context) {
const data = await fetchCriticalData();
return {
props: {
data,
},
};
}
Edge Computing i CDN
// Cloudflare Workers dla edge processing
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
// Optimize images at the edge
if (request.url.includes('/images/')) {
return fetch(request.url + '?format=webp&quality=85');
}
return fetch(request);
}
📋 Performance Checklist
- ✅ Optymalizuj obrazy (WebP/AVIF, lazy loading)
- ✅ Implementuj critical CSS
- ✅ Minifikuj i kompresuj zasoby
- ✅ Używaj HTTP/2
- ✅ Skonfiguruj proper caching
- ✅ Zoptymalizuj JavaScript (code splitting)
- ✅ Monitoruj Core Web Vitals
- ✅ Testuj na rzeczywistych urządzeniach
- ✅ Ustaw performance budget
- ✅ Implementuj monitoring wydajności
🎉 Podsumowanie
Optymalizacja wydajności to ciągły proces, który wymaga systematycznego podejścia i regularnego monitorowania. Kluczem do sukcesu jest zrozumienie, które elementy mają największy wpływ na doświadczenie użytkowników i skupienie się na nich w pierwszej kolejności.
Pamiętaj, że każda sekunda ma znaczenie - użytkownicy oczekują błyskawicznych stron, a wyszukiwarki nagradzają szybkie witryny lepszymi pozycjami. Inwestowanie w wydajność to inwestowanie w sukces Twojego biznesu online.
Chcesz znacząco przyspieszyć swoją stronę internetową? Skontaktuj się z nami - przeprowadzimy kompleksowy audyt wydajności i wdrożymy optymalizacje, które realnie wpłyną na Twój biznes.