Категории

Эффект «Принудительная прокрутка hero-секции»

09.11.2025 11:46 | коды из категории: Создание сайтов

про Эффект «Принудительная прокрутка hero-секции»

Эффект «Принудительная прокрутка hero-секции»

Интерактивный UI-приём, при котором основной контент сайта остаётся недоступным для прокрутки до тех пор, пока пользователь не пролистает всю hero-секцию (обычно — длинную иллюстрацию или фоновое изображение). Любое вращение колеса прокрутки, даже за пределами hero-блока, перехватывается и используется только для вертикальной навигации внутри него. Как только изображение доскроллено до конца, разблокируется стандартный скролл страницы.

Такой подход часто применяется на лендингах, чтобы гарантированно показать ключевую визуальную информацию до перехода к остальному содержимому.

css

 /* НИКАКОГО overflow: hidden на body! */
    body {
      margin: 0;
      font-family: sans-serif;
    }

    #heroo {
      height: 200px;
      width: 100%;
      overflow: hidden;
      position: relative;
      background: #f0f0f0;
      border-bottom: 1px solid #ccc;
    }

    #heroo img {
      width: 100%;
      height: auto;
      display: block;
      position: absolute;
      top: 0;
      left: 0;
    }

    .content {
      padding: 20px;
      height: 2000px;
      background: white;
    }

javascript

<script>
  const hero = document.getElementById('heroo');
  const heroImg = hero ? hero.querySelector('img') : null;

  if (!heroImg) {
    console.warn('Hero image not found');
  } else {
    let currentOffset = 0;
    let maxOffset = 0;
    let isReady = false;
    let heroFullyScrolled = false;

    heroImg.onload = () => {
      const heroWidth = hero.clientWidth;
      const scale = heroWidth / heroImg.naturalWidth;
      const scaledHeight = heroImg.naturalHeight * scale;

      heroImg.style.height = scaledHeight + 'px';
      maxOffset = Math.max(0, scaledHeight - hero.clientHeight);
      isReady = true;

      if (maxOffset <= 0) {
        heroFullyScrolled = true;
        console.log('Hero: no scroll needed');
      }
    };

    heroImg.onerror = () => {
      console.error('Hero image failed to load');
      heroFullyScrolled = true;
    };

    document.addEventListener('wheel', (e) => {
      if (heroFullyScrolled) return;
      if (!isReady) {
        e.preventDefault();
        return;
      }

      e.preventDefault();
      const step = 50;
      currentOffset = Math.max(0, Math.min(maxOffset, currentOffset + (e.deltaY > 0 ? step : -step)));
      heroImg.style.transform = `translateY(${-currentOffset}px)`;

      if (currentOffset >= maxOffset) {
        heroFullyScrolled = true;
        console.log('Hero fully scrolled — scroll unlocked');
      }
    }, { passive: false });
  }
</script>

html

  <div id="heroo">
    <img src="https://blog.iotprof.ru/uploads/ESP32-devkit-v1-pinout-diagram.png" alt="Длинная картинка" />
  </div>
  <div class="content">
    <h2>Теперь контент скроллится нормально!</h2>
    <p>Крути колёсико где угодно — сначала прокручивается фон в шапке.</p>
    <p>Как только доскроллил картинку до конца — страница скроллится как обычно.</p>
    <p>Проверь: доскроль фон, потом продолжи вниз — всё работает!</p>
  </div>

а вот так можно скролить картинку только когда курсор на картинке, а остальной контент скролится только когда курсор находится вне зоны картинки

<script>
  const hero = document.getElementById('heroo');
  const heroImg = hero ? hero.querySelector('img') : null;

  if (!heroImg) {
    console.warn('Hero image not found');
  } else {
    let currentOffset = 0;
    let maxOffset = 0;
    let isReady = false;
    let heroFullyScrolled = false;
    let isOverImage = false;

    // Отслеживаем наведение
    heroImg.addEventListener('mouseenter', () => {
      isOverImage = true;
    });

    heroImg.addEventListener('mouseleave', () => {
      isOverImage = false;
    });

    heroImg.onload = () => {
      const heroWidth = hero.clientWidth;
      const scale = heroWidth / heroImg.naturalWidth;
      const scaledHeight = heroImg.naturalHeight * scale;

      heroImg.style.height = `${scaledHeight}px`;
      maxOffset = Math.max(0, scaledHeight - hero.clientHeight);
      isReady = true;

      if (maxOffset <= 0) {
        heroFullyScrolled = true;
        console.log('Hero: no scroll needed');
      }
    };

    heroImg.onerror = () => {
      console.error('Hero image failed to load');
      heroFullyScrolled = true;
    };

    // Обрабатываем колесо ТОЛЬКО на изображении
    heroImg.addEventListener('wheel', (e) => {
      if (heroFullyScrolled || !isReady || !isOverImage) return;

      e.preventDefault(); // Блокируем стандартный скролл только здесь

      const step = 50;
      currentOffset = Math.max(0, Math.min(maxOffset, currentOffset + (e.deltaY > 0 ? step : -step)));
      heroImg.style.transform = `translateY(${-currentOffset}px)`;

      if (currentOffset >= maxOffset) {
        heroFullyScrolled = true;
        console.log('Hero fully scrolled — scroll unlocked');
      }
    }, { passive: false });
  }
</script>

ну если это не лендинг, где надо обязательно тормозить основной контент пока не прокрутишь картинку, если надо просто разделить. Короч, чтобы не блокировался основной контент. как у меня, то можно скролить и картинку и контент отдельно, наведя курсок в нужное место.

<script>
  const hero = document.getElementById('heroo');
  const heroImg = hero ? hero.querySelector('img') : null;

  if (!heroImg) {
    console.warn('Hero image not found');
  } else {
    let currentOffset = 0;
    let maxOffset = 0;
    let isReady = false;

    function initImage() {
      if (!heroImg.complete || !heroImg.naturalWidth) {
        // Картинка ещё не загружена — ждём onload
        return;
      }

      const heroWidth = hero.clientWidth;
      const scale = heroWidth / heroImg.naturalWidth;
      const scaledHeight = heroImg.naturalHeight * scale;

      heroImg.style.height = `${scaledHeight}px`;
      maxOffset = Math.max(0, scaledHeight - hero.clientHeight);
      isReady = true;

      if (maxOffset <= 0) {
        console.log('Hero: no scrollable area');
      }
    }

    // Проверяем сразу
    initImage();

    // Если ещё не готова — подключаем обработчики
    if (!isReady) {
      heroImg.addEventListener('load', initImage);
      heroImg.addEventListener('error', () => {
        console.error('Hero image failed to load');
      });
    }

    heroImg.addEventListener('wheel', (e) => {
      if (!isReady || maxOffset <= 0) return;

      e.preventDefault();
      const step = 50;
      currentOffset = Math.max(0, Math.min(maxOffset, currentOffset + (e.deltaY > 0 ? step : -step)));
      heroImg.style.transform = `translateY(${-currentOffset}px)`;
    }, { passive: false });
  }
</script>

Теги: #html #script #web #css #hero #site

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Важно: Блог-эксперимент

Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.

Посетителей сегодня: 0


кто я | книга | контакты без контактов

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA