14 de septiembre, 202510 min readWeb Accessibility

Web Accessibility and Images: Beyond Alt Text

Complete web accessibility guide for images. Contrast, visual impairments, screen readers and WCAG 2.1 compliance in 2025.

Web accessibility isn't an optional feature: it's a fundamental right. Approximately 15% of the world's population lives with some type of visual impairment, and poorly optimized images can be an insurmountable barrier for millions of users. In 2025, accessibility is not only ethically necessary but legally required in many countries.

🌍 Accessibility principles for web images:

  • Descriptive alt text: Relevant context, not decorative
  • Adequate contrast: Minimum 4.5:1 for text in images
  • Scalable sizes: Responsive without readability loss
  • Progressive loading: Accessible content during load
  • Support tools: Optimize maintaining quality | Universal formats

Understanding visual accessibility needs

Types of visual impairment and their needs:

1. Complete blindness

  • Need: Complete textual descriptions of visual content
  • Tools: Screen readers (NVDA, JAWS, VoiceOver)
  • Implementation: Detailed alt text and ARIA elements

2. Low vision

  • Need: High contrast, scalability, large text
  • Tools: Screen magnifiers, high contrast themes
  • Implementation: 7:1 contrast (AAA), scalability up to 200%

3. Color blindness (8% men, 0.5% women)

  • Need: Information not dependent solely on color
  • Types: Protanopia (red), deuteranopia (green), tritanopia (blue)
  • Implementation: Patterns, shapes, text as color alternatives

4. Light sensitivity

  • Need: Brightness control, dark mode
  • Tools: Screen filters, system settings
  • Implementation: Respect for prefers-color-scheme

Impactful data

71% of users with disabilities abandon a website immediately if it's not accessible. This represents not only a loss of audience, but also potential legal consequences under regulations like the ADA in the United States or EN 301 549 in the European Union.

Beyond alt text: Comprehensive accessibility

1. Strategic and contextual alt text

Alternative text should be descriptive of purpose, not just appearance:

<!-- ❌ Decorative alt text -->
<img src="sales-chart.jpg" alt="Chart">

<!-- ❌ Redundant alt text -->
<img src="sales-chart.jpg" alt="Image of a sales chart">

<!-- ✅ Functional alt text -->
<img src="sales-chart.jpg" 
     alt="Sales increased 35% in Q4 2024, from 2.1M to 2.8M euros">

<!-- ✅ Alt text for decorative content -->
<img src="floral-decoration.jpg" alt="" role="presentation">

2. Longdesc for complex content

For charts, infographics and complex visual content:

<img src="sustainability-infographic.jpg" 
     alt="Infographic about environmental impact of image formats"
     longdesc="#detailed-description">

<div id="detailed-description" class="sr-only">
  <h3>Detailed infographic description:</h3>
  <p>The infographic compares three image formats:</p>
  <ul>
    <li>JPEG: 45% more CO2 emissions due to additional transfer</li>
    <li>WebP: 30% size reduction, 25% fewer emissions</li>
    <li>AVIF: 50% size reduction, 40% fewer emissions</li>
  </ul>
  <p>Conclusion: Modern formats significantly reduce 
     the environmental impact of the web.</p>
</div>

3. ARIA elements for interactive images

<!-- Image with functionality -->
<button type="button" 
        aria-label="Compress uploaded image"
        aria-describedby="compression-help">
  <img src="compress-icon.svg" alt="" role="presentation">
  Compress
</button>
<div id="compression-help" class="sr-only">
  Reduces file size while maintaining visual quality
</div>

<!-- Image gallery -->
<div role="img" 
     aria-labelledby="gallery-title"
     aria-describedby="gallery-description">
  <h3 id="gallery-title">2024 Portfolio</h3>
  <p id="gallery-description">
    Collection of 12 professional photographs organized by date
  </p>
  <!-- Individual images... -->
</div>

Color contrast: More than numbers

WCAG 2.1 conformance levels:

Level Minimum contrast Recommended use
AA 4.5:1 (normal text) Minimum legal standard
AA 3:1 (large text) Headers and buttons
AAA 7:1 (normal text) Maximum accessibility
AAA 4.5:1 (large text) Critical content

Contrast verification tools:

// Function to automatically calculate contrast
function calculateContrast(color1, color2) {
  const getLuminance = (r, g, b) => {
    const [rs, gs, bs] = [r, g, b].map(component => {
      component = component / 255;
      return component <= 0.03928 
        ? component / 12.92 
        : Math.pow((component + 0.055) / 1.055, 2.4);
    });
    return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
  };
  
  const color1Luminance = getLuminance(...color1);
  const color2Luminance = getLuminance(...color2);
  
  const brightest = Math.max(color1Luminance, color2Luminance);
  const darkest = Math.min(color1Luminance, color2Luminance);
  
  return (brightest + 0.05) / (darkest + 0.05);
}

// Validate contrast in real time
function validateImageTextContrast(canvas) {
  const ctx = canvas.getContext('2d');
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  
  // Analyze contrast in text areas
  const contrastWarnings = [];
  
  // Implement contrast detection algorithm...
  // Report problematic areas
  
  return contrastWarnings;
}

Practical high contrast implementation:

/* Support for system high contrast mode */
@media (prefers-contrast: high) {
  .image-overlay-text {
    background: rgba(0, 0, 0, 0.9);
    color: #ffffff;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 1);
    border: 2px solid #ffffff;
  }
  
  .interactive-image-button {
    border: 3px solid currentColor;
    background: rgba(255, 255, 255, 0.95);
    color: #000000;
  }
}

/* Reduced motion mode */
@media (prefers-reduced-motion: reduce) {
  .image-carousel, .parallax-image {
    animation: none;
    transform: none;
  }
  
  .hover-image-effect {
    transition: none;
  }
}

/* Reduced transparency for better readability */
@media (prefers-reduced-transparency: reduce) {
  .image-overlay, .glassmorphism-effect {
    backdrop-filter: none;
    background: rgba(0, 0, 0, 0.95);
  }
}

Responsive accessibility: Scalability without barriers

Images that scale correctly with zoom:

/* Ensure scalability up to 200% without horizontal scroll */
.responsive-image-container {
  max-width: 100%;
  height: auto;
  overflow: hidden;
}

.responsive-image {
  width: 100%;
  height: auto;
  max-width: none; /* Allow full scalability */
}

/* Text in images must remain legible */
.image-with-text {
  position: relative;
}

.image-text-overlay {
  position: absolute;
  font-size: clamp(1rem, 2.5vw, 1.5rem); /* Fluid scalability */
  line-height: 1.4;
  padding: 0.5em;
  background: rgba(0, 0, 0, 0.8);
  color: white;
}

/* Accessible breakpoints */
@media (max-width: 768px) {
  .image-text-overlay {
    font-size: clamp(0.875rem, 3vw, 1.25rem);
    /* Minimum legible size on mobile */
  }
}

Focus management for interactive images:

// Focus management for image galleries
class AccessibleImageGallery {
  constructor(container) {
    this.container = container;
    this.currentIndex = 0;
    this.images = container.querySelectorAll('[role="img"]');
    this.setupKeyboardNavigation();
  }
  
  setupKeyboardNavigation() {
    this.container.addEventListener('keydown', (e) => {
      switch(e.key) {
        case 'ArrowRight':
        case 'ArrowDown':
          e.preventDefault();
          this.navigate(1);
          break;
        case 'ArrowLeft':
        case 'ArrowUp':
          e.preventDefault();
          this.navigate(-1);
          break;
        case 'Home':
          e.preventDefault();
          this.goToImage(0);
          break;
        case 'End':
          e.preventDefault();
          this.goToImage(this.images.length - 1);
          break;
      }
    });
  }
  
  navigate(direction) {
    const newIndex = this.currentIndex + direction;
    if (newIndex >= 0 && newIndex < this.images.length) {
      this.goToImage(newIndex);
    }
  }
  
  goToImage(index) {
    // Remove previous focus
    this.images[this.currentIndex]?.setAttribute('tabindex', '-1');
    
    // Set new focus
    this.currentIndex = index;
    const currentImage = this.images[this.currentIndex];
    currentImage.setAttribute('tabindex', '0');
    currentImage.focus();
    
    // Announce change to screen readers
    this.announceImageChange(index + 1, this.images.length);
  }
  
  announceImageChange(current, total) {
    const announcement = document.createElement('div');
    announcement.setAttribute('aria-live', 'polite');
    announcement.setAttribute('aria-atomic', 'true');
    announcement.className = 'sr-only';
    announcement.textContent = `Image ${current} of ${total}`;
    
    document.body.appendChild(announcement);
    setTimeout(() => announcement.remove(), 1000);
  }
}

// Initialize accessible gallery
document.addEventListener('DOMContentLoaded', () => {
  const galleries = document.querySelectorAll('[data-gallery="accessible"]');
  galleries.forEach(gallery => new AccessibleImageGallery(gallery));
});

⚠️ Common accessibility errors

  • Empty alt on informative images: Makes critical content invisible
  • Text in images without alternative: Inaccessible to screen readers
  • Insufficient contrast: Especially problematic in overlays
  • Exclusive color dependence: Invisible to colorblind people
  • Images without context: Alt text that doesn't explain purpose

Accessible progressive loading

Semantic placeholder during loading:

<div class="progressive-image-container" 
     aria-live="polite"
     aria-label="Loading image: Q4 2024 performance chart">
  
  <!-- Initial placeholder with information -->
  <div class="image-placeholder" 
       role="img"
       aria-label="Image loading: Chart showing 35% increase in sales">
    <svg viewBox="0 0 400 300" aria-hidden="true">
      <rect width="400" height="300" fill="#f0f0f0"/>
      <text x="200" y="150" text-anchor="middle" fill="#666">
        Loading chart...
      </text>
    </svg>
  </div>
  
  <!-- Real image (lazy load) -->
  <img src="q4-performance-chart.jpg"
       alt="Bar chart showing quarterly sales: Q1: 2.1M€, Q2: 2.3M€, Q3: 2.5M€, Q4: 2.8M€. Consistent upward trend with highest growth in Q4."
       class="progressive-image"
       loading="lazy"
       onload="this.parentElement.classList.add('loaded')">
</div>
.progressive-image-container {
  position: relative;
  overflow: hidden;
}

.image-placeholder {
  display: block;
  transition: opacity 0.3s ease;
}

.progressive-image {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.progressive-image-container.loaded .image-placeholder {
  opacity: 0;
}

.progressive-image-container.loaded .progressive-image {
  opacity: 1;
}

/* Accessible loading indicator */
@keyframes loading-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 0.8; }
}

.image-placeholder {
  animation: loading-pulse 1.5s ease-in-out infinite;
}

/* Stop animation if user prefers less motion */
@media (prefers-reduced-motion: reduce) {
  .image-placeholder {
    animation: none;
    opacity: 0.6;
  }
}

Automated accessibility testing

Automatic validation tools:

// Automatic image accessibility audit function
function auditImageAccessibility() {
  const issues = [];
  
  // Check alt text
  document.querySelectorAll('img').forEach((img, index) => {
    const alt = img.getAttribute('alt');
    const src = img.getAttribute('src');
    
    if (!alt && alt !== '') {
      issues.push({
        type: 'missing-alt',
        element: img,
        message: `Image ${index + 1} without alt attribute`,
        severity: 'error'
      });
    }
    
    if (alt && alt.length > 125) {
      issues.push({
        type: 'long-alt',
        element: img,
        message: `Alt text too long (${alt.length} characters)`,
        severity: 'warning'
      });
    }
    
    // Check if decorative image has empty alt
    if (img.getAttribute('role') === 'presentation' && alt !== '') {
      issues.push({
        type: 'decorative-with-alt',
        element: img,
        message: 'Decorative image should not have alt text',
        severity: 'warning'
      });
    }
  });
  
  // Check contrast in text over images
  document.querySelectorAll('.image-text-overlay').forEach(overlay => {
    const style = getComputedStyle(overlay);
    const textColor = style.color;
    const bgColor = style.backgroundColor;
    
    // Calculate contrast (implement contrast function)
    const contrast = calculateContrast(textColor, bgColor);
    
    if (contrast < 4.5) {
      issues.push({
        type: 'low-contrast',
        element: overlay,
        message: `Insufficient contrast: ${contrast.toFixed(2)}:1`,
        severity: 'error'
      });
    }
  });
  
  return issues;
}

// Run audit and show results
function runAccessibilityAudit() {
  const issues = auditImageAccessibility();
  
  if (issues.length === 0) {
    console.log('✅ No accessibility issues found');
    return;
  }
  
  console.group('🔍 Accessibility issues found:');
  issues.forEach(issue => {
    const icon = issue.severity === 'error' ? '❌' : '⚠️';
    console.log(`${icon} ${issue.message}`, issue.element);
  });
  console.groupEnd();
  
  // Optionally, show in UI for development
  if (process.env.NODE_ENV === 'development') {
    displayA11yIssues(issues);
  }
}

// Run in development
if (process.env.NODE_ENV === 'development') {
  window.addEventListener('load', runAccessibilityAudit);
}

Legal and regulatory compliance

Regulations by region:

United States - ADA (Americans with Disabilities Act)

  • Application: Websites of companies offering public services
  • Standard: WCAG 2.1 Level AA
  • Consequences: Lawsuits can result in fines of $75,000-$150,000

European Union - EN 301 549

  • Application: Public sector websites since 2018, private since 2025
  • Standard: WCAG 2.1 Level AA
  • Consequences: Fines up to 4% of annual revenue

United Kingdom - Public Sector Bodies Accessibility Regulations 2018

  • Application: Mandatory for public administrations
  • Standard: WCAG 2.1 Level AA
  • Evaluation: Mandatory accessibility statements

Image compliance checklist:

## ✅ WCAG 2.1 AA Accessibility Checklist

### Perceivable
- [ ] All informative images have descriptive alt text
- [ ] Decorative images have alt="" or role="presentation"
- [ ] Minimum 4.5:1 contrast for text in images
- [ ] Minimum 3:1 contrast for graphic elements
- [ ] Information doesn't depend solely on color

### Operable
- [ ] Interactive images are keyboard accessible
- [ ] No content causing seizures (< 3 flashes/second)
- [ ] Moving images can be paused
- [ ] Visible focus on interactive elements

### Understandable
- [ ] Alt text is clear and contextual
- [ ] Complex content has detailed description
- [ ] Error messages are descriptive

### Robust
- [ ] Valid HTML code
- [ ] Compatible with assistive technologies
- [ ] ARIA labels correctly implemented

Optimize accessibility with FotoLince

FotoLince helps you create accessible web images: optimize contrast, maintain quality for magnification, and generate universally compatible formats. Process locally preserving accessibility metadata.

Create accessible images

Tools and resources for implementation

Browser extensions for testing:

  • WAVE Web Accessibility Evaluator: Visual evaluation of issues
  • axe DevTools: Automatic audits on elements
  • Lighthouse: Accessibility metrics integrated in Chrome
  • Colour Contrast Analyser: Precise contrast verification

Screen readers for testing:

  • NVDA (Windows): Free, widely used
  • JAWS (Windows): Industry standard, commercial license
  • VoiceOver (macOS/iOS): Integrated in Apple devices
  • TalkBack (Android): Native mobile screen reader

Useful APIs and libraries:

// Library for automatic alt text generation (use with caution)
import { generateAltText } from '@microsoft/cognitive-services-vision';

async function generateAccessibleAltText(imageUrl, context) {
  const aiDescription = await generateAltText(imageUrl);
  
  // Combine AI description with human context
  const contextualAlt = `${context}: ${aiDescription}`;
  
  // Validate length and relevance
  if (contextualAlt.length > 125) {
    return contextualAlt.substring(0, 120) + '...';
  }
  
  return contextualAlt;
}

// User capability detection
function detectUserPreferences() {
  return {
    reducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches,
    highContrast: window.matchMedia('(prefers-contrast: high)').matches,
    reducedTransparency: window.matchMedia('(prefers-reduced-transparency: reduce)').matches,
    colorScheme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  };
}

// Adapt interface according to preferences
function adaptInterfaceForUser() {
  const prefs = detectUserPreferences();
  
  if (prefs.reducedMotion) {
    document.documentElement.classList.add('reduced-motion');
  }
  
  if (prefs.highContrast) {
    document.documentElement.classList.add('high-contrast');
  }
  
  // Apply specific adaptations...
}

Conclusion: Accessibility as competitive advantage

Web accessibility isn't just regulatory compliance: it's a market opportunity. Accessible websites:

  1. Expand their audience by including 1.3 billion people with disabilities
  2. Improve SEO with better semantic structure and descriptions
  3. Reduce legal risk by complying with international regulations
  4. Increase usability for all users, not just those with disabilities
  5. Demonstrate values of inclusion and corporate social responsibility

Accessibility is universal design: what benefits users with disabilities benefits everyone. A truly accessible website is a better website for its entire audience.

Ready to create truly inclusive websites?

Use FotoLince to optimize your images while maintaining accessibility: optimal contrast, universal formats and quality that scales. All processed locally to maintain privacy of your sensitive content.

Create accessible images

Need to optimize images?

Try our free tool to compress and optimize images with full privacy. All processing happens locally in your browser.

Open the tool