Техника 3D заворачивания для HTML элементов

Рассмотрим маленькую, но классную технику для сгибания и сворачивания HTML-элементов. Она может использоваться для создания интересных и разнообразных эффектов.

Эта иллюзия создается путем объединения нескольких элементов, чтобы создать впечатление, что это единый элемент. Затем, элементы разворачиваютя по краям, чтобы выглядели так, как будто края изгибаются.

Создание иллюзии сгибания

Для начала добавим контейнер с перспективой, чтобы видеть повороты в 3D. Cоздадим дочерние «складки» с фиксированными размерами и overflow: hidden. Верхняя и нижняя складки должны быть спозиционированы абсолютно на соответствующих сторонах средней складки.

Не обязательно делать складки фиксированных размеров. Можно указать каждому сгибу разные размеры. Но наличие фиксированных размеров значительно упрощает математические расчеты.

Свойство overflow:hidden необходимо, именно оно заставляет эффект работать. Потому что именно поэтому создается впечатление, что вся конструкция — единое целое, даже если складки имеют разные повороты.

<div class="wrapper-3d">
	<div class="fold fold-top"></div>
	<div class="fold fold-center" id="center-fold"></div>
	<div class="fold fold-bottom"></div>	
</div>
.wrapper-3d {
  position: relative;
  /* Based on screen with so the perspective doesn't break on small sizes*/
  perspective: 20vw;
  transform-style: preserve-3d;
}

.fold {
  overflow: hidden;
  width: 100vw;
  height: 80vh;
}

.fold-after {
  background: #dadada;
  position: absolute;
  transform-origin: top center;
  right: 0;
  left: 0;
  top: 100%;
}

.fold-before {
  background: #dadada;
  position: absolute;
  transform-origin: bottom center;
  left: 0;
  right: 0;
  bottom: 100%;
}

Примечание: здесь использовались свойства bottom и top для позиционирования дополнительных сгибов. Если вы хотите добавить более двух, потребуется сложить преобразования. Например, вы можете использовать функцию SCSS, которая генерирует код для всех сгибов, которые должны быть.

Теперь давайте добавим немного содержимого в сгибы и посмотрим, как это выглядит. Вставим их в новый контейнер .fold-content. Каждая сторона должна иметь одну и ту же копию контента, чтобы эффект был бесшовным.

Здесь контент будет представлять собой набор квадратов и заголовков. Можете попробовать добавить любые элементы HTML.

<div class="wrapper-3d">
  <div class="fold fold-top">
    <div class="fold-content">
      <div class="square green"></div>
      <h1>This is my content</h1>
      <div class="square blue"></div>
      <h1>This is my content</h1>
      <div class="square red"></div>
    </div>
  </div>
  <div class="fold fold-center" id="center-fold">
    <div class="fold-content" id="center-content">
      <div class="square green"></div>
      <h1>This is my content</h1>
      <div class="square blue"></div>
      <h1>This is my content</h1>
      <div class="square red"></div>
    </div>
  </div>
  <div class="fold fold-bottom">
    <div class="fold-content">
      <div class="square green"></div>
      <h1>This is my content</h1>
      <div class="square blue"></div>
      <h1>This is my content</h1>
      <div class="square red"></div>
    </div>
  </div>
</div>
.square {
  width: 100%;
  padding-bottom: 75%;
}

.green {
  background-color: lightgreen;
}

.blue {
  background-color: lightblue;
}

.red {
  background-color: lightcoral;
}

Здесь и сейчас наличие контента будет неуместно, потому что у каждого сгиба контент уже есть наверху. Так работает HTML. Надо, чтобы это было единое целое и все было ровно и плавно. Поэтому добавляем дополнительный .fold-align между содержимым и сгибом.

У каждой складки будет свое уникальное выравнивание. Разместим их содержимое так, чтобы они начинались сверху среднего сгиба.

<div class="wrapper-3d">
  <div class="fold fold-top">
    <div class="fold-align">
      <div class="fold-content">
        <!-- Content -->
      </div>
    </div>
  </div>
  <div class="fold fold-center" id="center-fold">
    <div class="fold-align">
      <div class="fold-content" id="center-content">
        <!-- Content -->
      </div>
    </div>
  </div>
  <div class="fold fold-bottom">
    <div class="fold-align">
      <div class="fold-content">
        <!-- Content -->
      </div>
    </div>
  </div>
</div>
.fold-align {
  width: 100%;
  height: 100%;
}

.fold-bottom .fold-align {
  transform: translateY(-100%);
}

.fold-top .fold-align {
  transform: translateY(100%);
}

Теперь нужно только повернуть верхнюю и нижнюю складки и создание эффекта завершено!

.fold-bottom {
  transform-origin: top center;
  transform: rotateX(120deg);
}

.fold-top {
  transform-origin: bottom center;
  transform: rotateX(-120deg);
}

See this code Bending HTML elements #1 on x.xhtml.ru.

Добавим прокрутку

Поскольку у сгибов overflow: hidden, по умолчанию их нельзя прокрутить. Тем более их нужно прокручивать синхронно.

Ничего необычного, обыкновенный скролл колесом мыши.

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

let centerContent = document.getElementById('center-content');
let centerFold = document.getElementById('center-fold');

let overflowHeight =  centerContent.clientHeight - centerFold.clientHeight

document.body.style.height = overflowHeight + window.innerHeight + "px";

Обновим положение содержимого складок, чтобы они прокручивались вместе со страницей.

let foldsContent = Array.from(document.getElementsByClassName('fold-content'))
let tick = () => {
    let scroll = -(
        document.documentElement.scrollTop || document.body.scrollTop
    );
    foldsContent.forEach((content) => {
        content.style.transform = `translateY(${scroll}px)`;
    })
    requestAnimationFrame(tick);
}
tick();

Вот и все!

See this code Bending HTML elements #2 – Scroll on x.xhtml.ru.