image-optimization
Skill6 starsChanged 12 days agoMITView on GitHub
Image SEO and Core Web Vitals: WebP and AVIF, srcset and sizes, lazy loading, the LCP image (fetchpriority, preload), compression and WordPress or PrestaShop implementation. Use when auditing images for LCP, CLS, weight or accessibility.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- Abdox-menara/guard-skillstheir own version, first seen Aug 24, 2026
- YepAPI/skillstheir own version, first seen Apr 12, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- YepAPI/skills★ 8same name
- Abdox-menara/guard-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository40 other files it gives its agents.
- accesibilidad-wcagSkill
- cache-headersSkill
- canonicalSkill
- ccpaSkill
- core-web-vitalsSkill
- ga4-ai-trafficSkill
- ga4-analysisSkill
- geo-ai-discoverabilitySkill
- google-tag-managerSkill
- hreflangSkill
- javascript-seoSkill
- ley-25326Skill
- ley-datos-chileSkill
- lfpdpppSkill
- lgpdSkill
- mineria-de-impresionesSkill
- nfadpSkill
- on-page-fundamentalsSkill
- prestashop-seoSkill
- privacidadSkill
- redirectsSkill
- rgpdSkill
- robots-txtSkill
- schema-markupSkill
- screaming-frogSkill
- semrushSkill
- seo-educacionSkill
- seo-gsc-diagnosticsSkill
- seo-interlinkingSkill
- seo-negativoSkill
- seo-quoteSkill
- se-rankingSkill
- sitemapSkill
- ssl-httpsSkill
- third-party-scriptsSkill
- uk-gdprSkill
- ux-heuristicaSkill
- wordpress-diviSkill
- wordpress-elementorSkill
- wordpress-hidden-errorsSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 8 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 29
Always keep JPEG/PNG as fallback via <picture>.
- Distinctive: line 138
All images that are not visible without scrolling on initial load
- Very specific: line 229
Rule: Use <img> for content images.
- Distinctive: line 232
If a hero background-image must remain as CSS, add a manual preload:
- Distinctive: line 322
When auditing or proposing a gallery, recommend user-controlled zoom: opens on click or tap, shows the image large, zooms with buttons, …
- Distinctive: line 359
Only catches images referenced in raw HTML (no JavaScript-injected images)
- Distinctive: line 360
Does not follow srcset or picture sources — audits the default src only
- Distinctive: line 367
When a site has missing or generic alt text, use Claude's vision capability to analyze the actual image and generate contextually correct …
- Distinctive: line 375
Check surrounding page context (H1, page topic, business type)
- Distinctive: line 390
Add localization or brand when the image shows a location, team, or branded element
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Image Optimization — SEO & Core Web Vitals
Images are 50-70% of page weight on most sites. They are also the most common LCP element. Wrong format, wrong loading strategy, or missing dimensions are among the top 5 CWV failure causes.
Format selection
| Format | Best for | Browser support | Typical savings vs JPEG |
| JPEG | Photos, complex images | Universal | baseline |
| PNG | Graphics with transparency | Universal | baseline |
| WebP | Photos + graphics | 95%+ (2024) | 25-35% smaller |
| AVIF | Photos + graphics | 80%+ (2024) | 40-50% smaller |
| SVG | Icons, logos, illustrations | Universal | N/A (vector) |
Recommendation: Serve WebP as the default for all new images. Use AVIF where
browser support is acceptable and compression gains justify the encoding time.
Always keep JPEG/PNG as fallback via <picture>.
<!-- AVIF with WebP fallback and JPEG as final fallback -->
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero image description" width="1200" height="600"
loading="eager" fetchpriority="high">
</picture>File size targets
| Image type | Context | Target size |
| LCP hero | Above the fold, full-width | < 100 KB |
| Product image | E-commerce main image | < 150 KB |
| Blog featured image | Article header | < 80 KB |
| Thumbnail | Card, listing | < 30 KB |
| Icon / small graphic | < 50px | Use SVG or inline |
| Background texture | Decorative | < 50 KB |
Sizes above are for WebP. JPEG equivalents are approximately 30-40% larger.
Responsive images — srcset and sizes
Without responsive images, a mobile user downloads a 2400px-wide desktop image for a 390px-wide screen. This wastes bandwidth and delays LCP.
<img
src="product-800.jpg"
srcset="product-400.webp 400w,
product-800.webp 800w,
product-1200.webp 1200w,
product-1600.webp 1600w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
alt="Product name"
width="800"
height="600"
loading="lazy">sizes attribute explained: Tells the browser how wide the image will be
displayed before the CSS is parsed. This allows the browser to select the right
source from srcset during preload, before layout is known.
(max-width: 600px) 100vw→ on screens < 600px, image is 100% of viewport width(max-width: 1200px) 50vw→ on screens < 1200px, image is 50% of viewport width800px→ on larger screens, image is always 800px wide
Missing sizes attribute: The browser defaults to 100vw and downloads the
largest available image on all screen sizes. Equivalent to not using srcset.
LCP images — do not lazy-load
The LCP image is the most important image on the page. Loading strategies that delay its discovery or download directly increase LCP.
Rules for LCP images
- Never
loading="lazy"— lazy loading defers the fetch until the element is near the viewport. For the LCP element, the element IS in the viewport. - Always
fetchpriority="high"— signals to the browser that this image should be fetched at high priority, ahead of other resources. - Add
<link rel="preload">in<head>— allows the browser to start downloading the image before the HTML is parsed far enough to discover the<img>tag. - Only one
fetchpriority="high"per page — setting it on multiple images effectively cancels the priority signal.
<!-- In <head> -->
<link rel="preload" as="image"
href="/images/hero.webp"
imagesrcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w"
imagesizes="(max-width: 600px) 100vw, 800px"
fetchpriority="high">
<!-- In <body> — the actual LCP image -->
<img src="/images/hero.webp"
srcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w"
sizes="(max-width: 600px) 100vw, 800px"
alt="Hero description"
width="800" height="400"
loading="eager"
fetchpriority="high">Lazy loading — when it helps vs hurts
loading="lazy" is correct and recommended for all images below the fold.
It is incorrect and harmful on images above the fold (especially the LCP image).
When to use loading="lazy"
- All images that are not visible without scrolling on initial load
- Product images in a grid below the hero
- Blog post thumbnails in a list
- Images in footer sections
When NOT to use loading="lazy"
- LCP image (hero, product main image)
- Any image visible in the initial viewport on typical screen sizes
- Images with
fetchpriority="high"
Lazy loading paradox with page builders
Elementor and WP Rocket apply lazy loading automatically to all images, including the LCP hero. This is the most common LCP failure in WordPress sites.
Elementor: The lazy load CSS hides backgrounds of sections 4+ and swaps
src with a placeholder. Fix: e-no-lazyload class on hero section.
WP Rocket: Replaces <img src> with data-lazy-src even if loading="eager"
or fetchpriority="high" is set in the HTML. Fix: exclude the hero image filename
in WP Rocket > Media > LazyLoad > Excluded images.
alt text — SEO and accessibility
<!-- Correct: descriptive, with keyword where natural -->
<img src="limpieza-cristales-madrid.webp"
alt="Equipo de limpieza de cristales en fachada de edificio en Madrid"
width="800" height="533">
<!-- Wrong: keyword-stuffed -->
<img src="limpieza.webp" alt="limpieza limpieza cristales limpieza madrid limpieza profesional">
<!-- Wrong: empty alt on content image -->
<img src="team.jpg" alt="">
<!-- Correct: decorative image (pure visual) has empty alt -->
<img src="divider-wave.svg" alt="" role="presentation">Rules:
- Content images (photos, product images, infographics): descriptive alt required
- Decorative images (separators, backgrounds converted to
<img>):alt="" - Logos:
alt="Company name logo" - CTA buttons with image: describe the action, not the image
SEO impact: Alt text is used by Google to understand image content and as a ranking signal for image search. It is also a mandatory WCAG accessibility requirement.
Image dimensions — preventing CLS
Missing width and height attributes on images cause layout shifts (CLS) when
the image loads and the browser reflows the page to accommodate the image dimensions.
<!-- Causes CLS: browser does not know height before image loads -->
<img src="product.jpg" alt="Product">
<!-- No CLS: browser reserves exact space -->
<img src="product.jpg" alt="Product" width="600" height="400">CSS alternative:
img {
aspect-ratio: 3 / 2; /* matches 600x400 ratio */
width: 100%;
height: auto;
}Both approaches are valid. The aspect-ratio CSS approach is more flexible for
responsive images where the intrinsic size varies.
CSS background-image vs <img> tag
| CSS background-image | <img> tag | |
| Discoverable by preload scanner | No | Yes |
| Lazy loadable | Via Intersection Observer JS | Native loading="lazy" |
| Accessible (alt text) | No | Yes |
fetchpriority support | No | Yes |
| CLS prevention (dimensions) | Via aspect-ratio or min-height | width + height attributes |
Rule: Use <img> for content images. Use CSS background-image for
decorative backgrounds that have no informational value.
If a hero background-image must remain as CSS, add a manual preload:
<link rel="preload" as="image" href="/images/hero-bg.webp" fetchpriority="high">Compression and optimization workflow
WordPress
ShortPixel (recommended):
- Bulk optimization with WebP/AVIF generation
- Lossy compression with quality 82-88 (imperceptible quality loss)
- CDN delivery option
Smush:
- Free tier covers most small sites
- WebP conversion requires Pro plan
Imagify:
- Aggressive compression presets
- WebP conversion included
WP Rocket + Imagify: WP Rocket has native integration with Imagify for on-the-fly WebP conversion via CDN rewriting.
PrestaShop
PrestaShop regenerates thumbnails from original uploads. Large originals are stored and thumbnails generated per context (product list, product page, email).
Fix for large originals: reduce upload quality before uploading, or use a module that compresses originals on upload.
PrestaShop thumbnail configuration: Back Office > Design > Image Settings. Regenerate thumbnails after changing sizes.
Manual optimization tools
- Squoosh (squoosh.app): browser-based, side-by-side comparison, WebP/AVIF
- ImageOptim (Mac): lossless and lossy compression
- Sharp (Node.js): programmatic batch conversion
- cwebp: CLI tool for WebP conversion
CMS-specific issues
WordPress + Elementor — wrong element gets fetchpriority
Elementor Pro's "Image" widget has an "Attributes" field. It is common to see
fetchpriority="high" applied manually to a decorative divider or separator
icon instead of the hero image. Check that fetchpriority="high" is on the
visually largest above-the-fold element.
WordPress — attachments page
WordPress automatically creates a public page for each uploaded image at
/domain.com/attachment/filename-of-image/. These pages have thin content
(just the image) and should be redirected or set to noindex.
Fix in Yoast: SEO > Search Appearance > Media > Redirect attachment URLs to the attachment itself: Yes.
PrestaShop — product image alt text
PrestaShop uses the product name as the alt text for product images by default. This is often acceptable, but adding specific descriptive alt text per image improves both SEO and accessibility.
The alt text for product images can be set per image in Catalog > Products > Images tab.
WooCommerce — product gallery lazy loading
WooCommerce product gallery images after the first are lazy-loaded by WooCommerce
and WP themes. This is correct behavior — they are not visible until the user
interacts with the gallery. The main product image should be loading="eager".
Product galleries — hover zoom is a UX finding
Hover zoom (the magnified view follows the cursor) takes control away from the shopper: the zoom can't be held on the part they want to read (label, ingredients, certification marks), it disappears when the cursor moves toward the price or the buy button, and it does not work on mobile, touch or keyboard (WCAG 1.4.13, content on hover or focus). If the product page doesn't let people see the product, they go back to the results page or don't buy.
When auditing or proposing a gallery, recommend user-controlled zoom: opens on click or tap, shows the image large, zooms with buttons, wheel or pinch, pans by dragging, stays open until closed, and loads the large file only when opened (no extra weight on page load). Report an existing hover zoom as a UX problem that hurts conversion and interaction signals. Do not sell it as a direct ranking factor beyond Core Web Vitals.
Diagnostic commands — live site image audit
Detect oversized images (>200 KB) on any URL
curl -s https://example.com/ \
| grep -oE 'https?://[^"]+\.(jpg|jpeg|png|webp|gif)' \
| xargs -I {} curl -s -o /dev/null -w "%{size_download} %{url_effective}\n" {} \
| awk '$1 > 204800 {printf "%.2f KB - %s\n", $1/1024, $2}' \
| sort -nrWhat it does: Fetches the HTML of a URL, extracts all image URLs, measures each image's actual download size, and lists those exceeding 200 KB sorted by size descending.
Variants:
# Lower threshold — flag images > 100 KB (recommended for LCP candidates)
awk '$1 > 102400 {printf "%.2f KB - %s\n", $1/1024, $2}'
# All images regardless of size (full inventory)
awk '{printf "%.2f KB - %s\n", $1/1024, $2}' | sort -nr
# Save to file for reporting
| tee ~/claude-seo/client/image-audit-$(date +%Y%m%d).txtLimitations:
- Only catches images referenced in raw HTML (no JavaScript-injected images)
- Does not follow srcset or picture sources — audits the default src only
- For JS-rendered pages, combine with a PageSpeed Insights audit or Screaming Frog
Alt text generation — vision workflow
When a site has missing or generic alt text, use Claude's vision capability to analyze the actual image and generate contextually correct alt text.
Workflow
- Collect image URLs (from the diagnostic command above or from crawl data)
- For each image, fetch and analyze visually:
- Identify the main subject (person, product, action, location)
- Check surrounding page context (H1, page topic, business type)
- Apply keyword + localization/brand where natural
- Output format per image:
URL: https://example.com/images/foto1.jpg
Alt propuesto: [descripción natural con keyword y localización si aplica]
Nombre de archivo sugerido: keyword-descripcion-ciudad.webp
Observaciones: [si hay problema de relevancia, duplicado, o imagen decorativa]Alt text rules (applied during generation)
- Content images: descriptive alt required — never empty, never keyword-stuffed
- Include primary keyword naturally where it fits the visual content
- Add localization or brand when the image shows a location, team, or branded element
- Decorative images (separators, abstract backgrounds):
alt=""— no text - Logos:
alt="Nombre de empresa logo" - Max ~125 characters (screen reader limit)
Filename rules (applied when renaming is possible)
- kebab-case, no accents, no spaces:
limpieza-cristales-madrid.webp - Descriptive, not generic:
foto1.jpg→equipo-fisioterapia-barcelona.webp - Format:
.webp, max 100 KB
Example output
URL: https://clinica.es/wp-content/uploads/equipo.jpg
Análisis visual: foto grupal de 4 profesionales con batas blancas en consulta
Contexto página: clínica de fisioterapia en Valencia
Alt propuesto: Equipo de fisioterapeutas de la clínica en Valencia
Nombre sugerido: equipo-fisioterapeutas-valencia.webpAudit checklist
CRITICAL (LCP impact)
[ ] LCP image: NOT lazy-loaded (no loading="lazy", no data-src placeholder)
[ ] LCP image: has fetchpriority="high"
[ ] LCP image: < 100 KB
[ ] LCP image: served as WebP or AVIF (not JPEG/PNG if avoidable)
HIGH (CLS and performance)
[ ] All content images have explicit width + height (or aspect-ratio CSS)
[ ] Images below the fold use loading="lazy"
[ ] No images > 500 KB on any page (PSI "Properly size images")
[ ] Responsive srcset present on images > 400px wide
[ ] Hero image NOT served as CSS background-image (or preload link present)
MEDIUM (SEO and accessibility)
[ ] All content images have meaningful alt text
[ ] Decorative images have alt="" (empty alt, not missing)
[ ] No keyword-stuffed alt text
[ ] WordPress attachment pages redirected or noindexed
[ ] Product images in e-commerce have descriptive alt text
LOW (optimization)
[ ] WebP/AVIF served to supported browsers
[ ] Image CDN or compression plugin active
[ ] No images loaded unnecessarily on mobile (art direction via <picture>)
[ ] Thumbnails correct size (not oversized images scaled down with CSS)Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

