Swiper js, как сделать чтобы при фокусе по табу на ссылке внутри слайда не исчезала пагинация?

Решение проблемы с исчезновением пагинации Swiper при фокусе на ссылках

Проблема

При навигации по странице с помощью клавиши Tab, когда фокус попадает на ссылку внутри слайда Swiper, пагинация (буллеты/номера страниц) может исчезать. Это происходит потому, что Swiper по умолчанию скрывает некоторые элементы управления при отсутствии явного взаимодействия со слайдером.

Подробное решение

1. Настройка параметров Swiper

Добавьте следующие параметры в конфигурацию вашего Swiper:

const swiper = new Swiper('.swiper', {
  // Основные параметры
  slidesPerView: 1,
  spaceBetween: 30,
  
  // Критически важные настройки для решения проблемы
  watchOverflow: true,
  observer: true,
  observeParents: true,
  observeSlideChildren: true,
  
  // Пагинация
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
    renderBullet: function (index, className) {
      return '<span class="' + className + '">' + (index + 1) + '</span>';
    },
  },
  
  // Дополнительные настройки для улучшения доступности
  a11y: {
    enabled: true,
    prevSlideMessage: 'Previous slide',
    nextSlideMessage: 'Next slide',
    paginationBulletMessage: 'Go to slide {{index}}',
  },
  
  // Автоматическое скрытие элементов управления (отключаем или настраиваем)
  autoHeight: false,
});

2. CSS решение для принудительного отображения пагинации

Добавьте в ваш CSS:

.swiper-pagination {
  opacity: 1 !important;
  visibility: visible !important;
  transition: opacity 0.3s ease;
}

/* Сохраняем пагинацию видимой при фокусе на элементах внутри слайда */
.swiper-slide:focus-within .swiper-pagination {
  opacity: 1 !important;
  visibility: visible !important;
}

/* Альтернативный подход - всегда показывать пагинацию */
.swiper-container .swiper-pagination {
  display: flex !important;
}

3. JavaScript решение с обработчиками событий

const swiper = new Swiper('.swiper', {
  // ... остальная конфигурация
});

// Обработчики для поддержания видимости пагинации
const pagination = document.querySelector('.swiper-pagination');
const links = document.querySelectorAll('.swiper-slide a');

// При фокусе на ссылке показываем пагинацию
links.forEach(link => {
  link.addEventListener('focus', () => {
    pagination.style.opacity = '1';
    pagination.style.visibility = 'visible';
  });
  
  link.addEventListener('blur', () => {
    // Опционально: скрываем пагинацию после потери фокуса
    // pagination.style.opacity = '0';
    // pagination.style.visibility = 'hidden';
  });
});

// Дополнительно: обновляем Swiper при изменениях
swiper.update();

4. Полное решение с кастомными классами

class AccessibleSwiper {
  constructor(selector) {
    this.swiper = new Swiper(selector, {
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
      // ... другие настройки
    });
    
    this.initAccessibility();
  }
  
  initAccessibility() {
    const slides = this.swiper.slides;
    
    slides.forEach((slide, index) => {
      const focusableElements = slide.querySelectorAll('a, button, input, [tabindex]');
      
      focusableElements.forEach(element => {
        element.addEventListener('focus', () => {
          this.swiper.pagination.el.classList.add('pagination-visible');
          this.swiper.pagination.el.style.opacity = '1';
        });
        
        element.addEventListener('blur', () => {
          this.swiper.pagination.el.classList.remove('pagination-visible');
        });
      });
    });
  }
}

// Использование
const accessibleSwiper = new AccessibleSwiper('.swiper-container');

5. Дополнительные CSS стили для доступности

/* Базовые стили для пагинации */
.swiper-pagination {
  position: absolute;
  bottom: 10px;
  width: 100%;
  display: flex;
  justify-content: center;
  z-index: 10;
}

/* Состояние при фокусе */
.swiper-pagination:focus,
.swiper-pagination-bullet:focus {
  outline: 2px solid #007bff;
  outline-offset: 2px;
}

/* Класс для принудительного отображения */
.pagination-visible {
  opacity: 1 !important;
  visibility: visible !important;
}

/* Улучшение видимости для accessibility */
.swiper-pagination-bullet {
  width: 12px;
  height: 12px;
  margin: 0 6px;
  background: #000;
  opacity: 0.5;
}

.swiper-pagination-bullet-active {
  opacity: 1;
  background: #007bff;
}

6. Альтернативное решение с MutationObserver

const swiper = new Swiper('.swiper', {
  // ... конфигурация
});

// Наблюдаем за изменениями в пагинации
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === 'attributes' && 
        mutation.attributeName === 'style' &&
        mutation.target.classList.contains('swiper-pagination')) {
      
      const style = window.getComputedStyle(mutation.target);
      if (style.opacity === '0' || style.visibility === 'hidden') {
        mutation.target.style.opacity = '1';
        mutation.target.style.visibility = 'visible';
      }
    }
  });
});

observer.observe(document.querySelector('.swiper-pagination'), {
  attributes: true,
  attributeFilter: ['style']
});

Рекомендации по реализации:

  1. Начните с CSS решения - это самое простое и эффективное
  2. Протестируйте с различными устройствами и браузерами
  3. Убедитесь, что решение не нарушает другие функции Swiper
  4. Добавьте плавные переходы для лучшего пользовательского опыта
  5. Протестируйте доступность с помощью инструментов like Lighthouse

Важные моменты:

  • Всегда обновляйте Swiper после динамических изменений: swiper.update()
  • Тестируйте с реальными пользователями, особенно с теми, кто использует клавиатуру для навигации
  • Учитывайте производительность при использовании MutationObserver

Это комплексное решение должно решить проблему с исчезновением пагинации при фокусе на ссылках внутри слайдов Swiper.