top of page

WE LOVE... bike, bike, bike :)

Subscribe Form

Thanks for submitting!

©2023 by VELOV.ch - Proudly created by Velolove

bottom of page
// ===================================================================== // VELOV — Performance Patch v1.0 // Install: Wix Editor → Settings → Custom Code → + Add Custom Code // Place code in: BODY END // Apply to: All pages // ===================================================================== // What this does: // 1. Adds loading="lazy" to every img below the fold (CWV improvement) // 2. Adds decoding="async" to all images (parallel decode) // 3. Promotes hero image (first img with class .hero or first viewport img) // to fetchpriority="high" for faster LCP // 4. Adds rel="noopener noreferrer" to external links missing it (security) // 5. Auto-adds aria-label to icon-only buttons (a11y + SEO) // ===================================================================== (function () { 'use strict'; // Wait for DOM (Wix renders progressively) var ready = function (fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); }; ready(function () { // ----- 1. LAZY-LOAD IMAGES BELOW FOLD ----- var foldHeight = window.innerHeight || 800; var imgs = document.querySelectorAll('img'); var firstImage = null; imgs.forEach(function (img, idx) { // Skip if already has loading attribute if (!img.hasAttribute('loading')) { var rect = img.getBoundingClientRect(); var isAboveFold = rect.top < foldHeight && rect.top >= -50; img.setAttribute('loading', isAboveFold ? 'eager' : 'lazy'); } // Decoding async on everything if (!img.hasAttribute('decoding')) { img.setAttribute('decoding', 'async'); } // Track first image for fetchpriority if (idx === 0 && !firstImage) firstImage = img; }); // ----- 2. HERO IMAGE = FETCHPRIORITY HIGH ----- var hero = document.querySelector('img.hero, [class*="hero"] img, .Hero img, header img') || firstImage; if (hero && !hero.hasAttribute('fetchpriority')) { hero.setAttribute('fetchpriority', 'high'); hero.setAttribute('loading', 'eager'); } // ----- 3. EXTERNAL LINKS: noopener ----- var anchors = document.querySelectorAll('a[target="_blank"]'); anchors.forEach(function (a) { var rel = a.getAttribute('rel') || ''; if (!/noopener/.test(rel) || !/noreferrer/.test(rel)) { a.setAttribute('rel', (rel + ' noopener noreferrer').trim()); } }); // ----- 4. ICON-ONLY BUTTONS GET ARIA-LABEL ----- var buttons = document.querySelectorAll('button, a[role="button"]'); buttons.forEach(function (btn) { var text = (btn.textContent || '').trim(); var hasLabel = btn.hasAttribute('aria-label') || btn.hasAttribute('aria-labelledby'); if (!text && !hasLabel) { var titleAttr = btn.getAttribute('title'); if (titleAttr) { btn.setAttribute('aria-label', titleAttr); } } }); // ----- 5. PRECONNECT TO WHATSAPP (warm connection) ----- var hasWaPreconnect = document.querySelector('link[rel="preconnect"][href*="wa.me"]'); if (!hasWaPreconnect) { var link = document.createElement('link'); link.rel = 'preconnect'; link.href = 'https://wa.me'; document.head.appendChild(link); } // ----- 6. GA4 EVENT TRACKING (fires only if gtag present) ----- function trackEvent(eventName, params) { if (typeof window.gtag === 'function') { window.gtag('event', eventName, params || {}); } } // WhatsApp clicks document.addEventListener('click', function (e) { var target = e.target.closest('a[href*="wa.me"], a[href*="whatsapp"]'); if (target) { trackEvent('whatsapp_click', { link_url: target.href, link_text: target.textContent.trim().slice(0, 100) }); } }); // Phone clicks document.addEventListener('click', function (e) { var target = e.target.closest('a[href^="tel:"]'); if (target) { trackEvent('phone_click', { link_url: target.href }); } }); // Pannendienst CTAs document.addEventListener('click', function (e) { var target = e.target.closest( 'a[href*="pannendienst"], a[href*="notfall"], button[data-cta="pannendienst"]' ); if (target) { trackEvent('pannendienst_cta', { source: window.location.pathname }); } }); // Booking form submit document.addEventListener('submit', function (e) { var form = e.target; if (form.matches('form[data-booking], form[id*="book"], form[class*="booking"]')) { trackEvent('booking_form_submit', { form_id: form.id || 'unknown' }); } }); // 75% scroll on homepage if (window.location.pathname === '/' || window.location.pathname === '') { var fired = false; window.addEventListener( 'scroll', function () { if (fired) return; var scrollDepth = (window.scrollY + window.innerHeight) / document.documentElement.scrollHeight; if (scrollDepth >= 0.75) { fired = true; trackEvent('scroll_75_homepage'); } }, { passive: true } ); } console.log('[VELOV] Performance + tracking patch loaded'); }); })();