← HTML & CSS/3D трансформации и перспектива#35 из 383← ПредыдущийСледующий →+20 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

3D трансформации и перспектива

CSS поддерживает трёхмерное пространство. С помощью perspective, transform-style: preserve-3d и 3D-функций трансформации можно создавать перелистывание карточек, 3D-карусели и другие эффекты.

perspective — глубина сцены

perspective задаёт расстояние от зрителя до плоскости Z=0. Чем меньше значение, тем сильнее выражен 3D-эффект:

/* На родителе — создаёт перспективу для всех детей */
.scene {
  perspective: 800px;           /* Расстояние зрителя */
  perspective-origin: 50% 50%;  /* Точка схода (по умолчанию центр) */
}

/* Или на самом элементе через transform */
.card {
  transform: perspective(800px) rotateY(45deg);
}

transform-style: preserve-3d

Без этого свойства дочерние элементы «сплющиваются» в плоскость родителя:

.card {
  transform-style: preserve-3d;  /* Дети живут в 3D-пространстве родителя */
  /* flat — по умолчанию, дети проецируются на 2D */
}

3D функции трансформации

/* Вращение вокруг осей */
transform: rotateX(45deg);   /* Наклон вперёд/назад */
transform: rotateY(45deg);   /* Поворот влево/вправо (как дверь) */
transform: rotateZ(45deg);   /* Обычное вращение (= rotate()) */
transform: rotate3d(1, 1, 0, 45deg); /* Вращение вокруг произвольной оси */

/* Перемещение по оси Z */
transform: translateZ(100px);  /* Ближе к зрителю */
transform: translateZ(-100px); /* Дальше от зрителя */
transform: translate3d(x, y, z);

/* Масштабирование */
transform: scaleZ(2);          /* Масштаб по оси Z */
transform: scale3d(1, 1, 2);

Переворот карточки (Card Flip)

Классический паттерн: карточка с лицевой и обратной сторонами:

.card-scene {
  perspective: 1000px;
  width: 200px;
  height: 280px;
}

.card {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
  position: relative;
}

.card.flipped {
  transform: rotateY(180deg);
}

/* Лицевая и обратная стороны */
.card__front,
.card__back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;  /* Прячем сторону, повёрнутую от зрителя */
  border-radius: 12px;
}

.card__back {
  transform: rotateY(180deg);   /* Обратная сторона изначально повёрнута */
  background: #7b2ff7;
  color: white;
}

backface-visibility

backface-visibility: hidden;  /* Прячет элемент, когда он повёрнут к нам спиной */
backface-visibility: visible; /* Показывает (зеркально отражённый) */

3D-карусель

.carousel {
  transform-style: preserve-3d;
  /* Каждая панель повёрнута на свой угол и отодвинута по Z */
}

/* 4 панели, каждая 90° друг от друга */
.panel:nth-child(1) { transform: rotateY(0deg)   translateZ(300px); }
.panel:nth-child(2) { transform: rotateY(90deg)  translateZ(300px); }
.panel:nth-child(3) { transform: rotateY(180deg) translateZ(300px); }
.panel:nth-child(4) { transform: rotateY(270deg) translateZ(300px); }

will-change для плавности

.card {
  will-change: transform;  /* Браузер заранее создаёт GPU-слой */
}

Используй с умом: избыток will-change увеличивает потребление памяти GPU.

Примеры

Интерактивная 3D-карточка с переворотом и вычислением матриц трансформации

// 3D Card Flip через CSS transform-style: preserve-3d
const style = document.createElement('style')
style.textContent = `
  .scene {
    perspective: 800px;
    width: 180px;
    height: 240px;
    margin: 20px;
    cursor: pointer;
  }
  .card-3d {
    width: 100%; height: 100%;
    transform-style: preserve-3d;
    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
  }
  .card-3d.flipped { transform: rotateY(180deg); }
  .face {
    position: absolute; inset: 0;
    backface-visibility: hidden;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: sans-serif;
    font-weight: 700;
    font-size: 18px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.15);
  }
  .front { background: linear-gradient(135deg, #7b2ff7, #06b6d4); color: white; }
  .back  { background: linear-gradient(135deg, #f59e0b, #ef4444); color: white;
           transform: rotateY(180deg); }
`
document.head.appendChild(style)

const scene = document.createElement('div')
scene.className = 'scene'
document.body.appendChild(scene)

const card = document.createElement('div')
card.className = 'card-3d'
scene.appendChild(card)

const front = document.createElement('div')
front.className = 'face front'
front.textContent = 'Лицо'
card.appendChild(front)

const back = document.createElement('div')
back.className = 'face back'
back.textContent = 'Обратная'
card.appendChild(back)

// Переворот по клику
let isFlipped = false
scene.addEventListener('click', () => {
  isFlipped = !isFlipped
  card.classList.toggle('flipped', isFlipped)
  console.log('Перевёрнута:', isFlipped)
  console.log('transform:', getComputedStyle(card).transform)
})

// Симуляция 3D-матрицы вращения по Y
function rotateYMatrix(angleDeg) {
  const a = angleDeg * Math.PI / 180
  return {
    m11: Math.cos(a),  m13: Math.sin(a),
    m31: -Math.sin(a), m33: Math.cos(a),
    m22: 1, m44: 1,
  }
}

console.log('Матрица rotateY(0deg):', rotateYMatrix(0))
console.log('Матрица rotateY(90deg):', rotateYMatrix(90))
console.log('Матрица rotateY(180deg):', rotateYMatrix(180))
console.log('Кликни на карточку чтобы перевернуть её')

// backface-visibility: когда |cos(angle)| < 0 — лицо от нас
function isFaceVisible(angleDeg) {
  return Math.cos(angleDeg * Math.PI / 180) >= 0
}
console.log('Front visible at 0°:', isFaceVisible(0))    // true
console.log('Front visible at 90°:', isFaceVisible(90))   // false (граница)
console.log('Front visible at 180°:', isFaceVisible(180)) // false

3D трансформации и перспектива

CSS поддерживает трёхмерное пространство. С помощью perspective, transform-style: preserve-3d и 3D-функций трансформации можно создавать перелистывание карточек, 3D-карусели и другие эффекты.

perspective — глубина сцены

perspective задаёт расстояние от зрителя до плоскости Z=0. Чем меньше значение, тем сильнее выражен 3D-эффект:

/* На родителе — создаёт перспективу для всех детей */
.scene {
  perspective: 800px;           /* Расстояние зрителя */
  perspective-origin: 50% 50%;  /* Точка схода (по умолчанию центр) */
}

/* Или на самом элементе через transform */
.card {
  transform: perspective(800px) rotateY(45deg);
}

transform-style: preserve-3d

Без этого свойства дочерние элементы «сплющиваются» в плоскость родителя:

.card {
  transform-style: preserve-3d;  /* Дети живут в 3D-пространстве родителя */
  /* flat — по умолчанию, дети проецируются на 2D */
}

3D функции трансформации

/* Вращение вокруг осей */
transform: rotateX(45deg);   /* Наклон вперёд/назад */
transform: rotateY(45deg);   /* Поворот влево/вправо (как дверь) */
transform: rotateZ(45deg);   /* Обычное вращение (= rotate()) */
transform: rotate3d(1, 1, 0, 45deg); /* Вращение вокруг произвольной оси */

/* Перемещение по оси Z */
transform: translateZ(100px);  /* Ближе к зрителю */
transform: translateZ(-100px); /* Дальше от зрителя */
transform: translate3d(x, y, z);

/* Масштабирование */
transform: scaleZ(2);          /* Масштаб по оси Z */
transform: scale3d(1, 1, 2);

Переворот карточки (Card Flip)

Классический паттерн: карточка с лицевой и обратной сторонами:

.card-scene {
  perspective: 1000px;
  width: 200px;
  height: 280px;
}

.card {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
  position: relative;
}

.card.flipped {
  transform: rotateY(180deg);
}

/* Лицевая и обратная стороны */
.card__front,
.card__back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;  /* Прячем сторону, повёрнутую от зрителя */
  border-radius: 12px;
}

.card__back {
  transform: rotateY(180deg);   /* Обратная сторона изначально повёрнута */
  background: #7b2ff7;
  color: white;
}

backface-visibility

backface-visibility: hidden;  /* Прячет элемент, когда он повёрнут к нам спиной */
backface-visibility: visible; /* Показывает (зеркально отражённый) */

3D-карусель

.carousel {
  transform-style: preserve-3d;
  /* Каждая панель повёрнута на свой угол и отодвинута по Z */
}

/* 4 панели, каждая 90° друг от друга */
.panel:nth-child(1) { transform: rotateY(0deg)   translateZ(300px); }
.panel:nth-child(2) { transform: rotateY(90deg)  translateZ(300px); }
.panel:nth-child(3) { transform: rotateY(180deg) translateZ(300px); }
.panel:nth-child(4) { transform: rotateY(270deg) translateZ(300px); }

will-change для плавности

.card {
  will-change: transform;  /* Браузер заранее создаёт GPU-слой */
}

Используй с умом: избыток will-change увеличивает потребление памяти GPU.

Примеры

Интерактивная 3D-карточка с переворотом и вычислением матриц трансформации

// 3D Card Flip через CSS transform-style: preserve-3d
const style = document.createElement('style')
style.textContent = `
  .scene {
    perspective: 800px;
    width: 180px;
    height: 240px;
    margin: 20px;
    cursor: pointer;
  }
  .card-3d {
    width: 100%; height: 100%;
    transform-style: preserve-3d;
    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
  }
  .card-3d.flipped { transform: rotateY(180deg); }
  .face {
    position: absolute; inset: 0;
    backface-visibility: hidden;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: sans-serif;
    font-weight: 700;
    font-size: 18px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.15);
  }
  .front { background: linear-gradient(135deg, #7b2ff7, #06b6d4); color: white; }
  .back  { background: linear-gradient(135deg, #f59e0b, #ef4444); color: white;
           transform: rotateY(180deg); }
`
document.head.appendChild(style)

const scene = document.createElement('div')
scene.className = 'scene'
document.body.appendChild(scene)

const card = document.createElement('div')
card.className = 'card-3d'
scene.appendChild(card)

const front = document.createElement('div')
front.className = 'face front'
front.textContent = 'Лицо'
card.appendChild(front)

const back = document.createElement('div')
back.className = 'face back'
back.textContent = 'Обратная'
card.appendChild(back)

// Переворот по клику
let isFlipped = false
scene.addEventListener('click', () => {
  isFlipped = !isFlipped
  card.classList.toggle('flipped', isFlipped)
  console.log('Перевёрнута:', isFlipped)
  console.log('transform:', getComputedStyle(card).transform)
})

// Симуляция 3D-матрицы вращения по Y
function rotateYMatrix(angleDeg) {
  const a = angleDeg * Math.PI / 180
  return {
    m11: Math.cos(a),  m13: Math.sin(a),
    m31: -Math.sin(a), m33: Math.cos(a),
    m22: 1, m44: 1,
  }
}

console.log('Матрица rotateY(0deg):', rotateYMatrix(0))
console.log('Матрица rotateY(90deg):', rotateYMatrix(90))
console.log('Матрица rotateY(180deg):', rotateYMatrix(180))
console.log('Кликни на карточку чтобы перевернуть её')

// backface-visibility: когда |cos(angle)| < 0 — лицо от нас
function isFaceVisible(angleDeg) {
  return Math.cos(angleDeg * Math.PI / 180) >= 0
}
console.log('Front visible at 0°:', isFaceVisible(0))    // true
console.log('Front visible at 90°:', isFaceVisible(90))   // false (граница)
console.log('Front visible at 180°:', isFaceVisible(180)) // false

Задание

Создай интерактивную карточку с 3D-переворотом при клике. Карточка должна иметь лицевую (синяя) и обратную (фиолетовая) стороны. Используй `transform-style: preserve-3d`, `backface-visibility: hidden` и `transition: transform 0.6s`. При клике добавляй/убирай класс `.flipped` с `rotateY(180deg)`.

Подсказка

`perspective: 800px` на `.scene` создаёт глубину. `transform-style: preserve-3d` — дети живут в 3D. `backface-visibility: hidden` — прячет обратную сторону. `.back` изначально повёрнута на `rotateY(180deg)`. `.flipped` — `rotateY(180deg)` на карточке.

Загружаем среду выполнения...
Загружаем AI-помощника...