Skip to content

Commit

Permalink
Дополняет доку про perspective (#5437)
Browse files Browse the repository at this point in the history
* Добавляет раздел На практике, исправляет демку и формулировку в доке про perspective

* ~~Баба Яга~~ пунктуация против :)

* repspective -> perspective

* Отбивает математические операторы пробелами

Co-authored-by: Alena Batitskaia <[email protected]>

* Добавляет демку в совет

* добавляет пустую строку

* удаляет пробел

* Добавляет overflow: hidden

* Дарит значок

---------

Co-authored-by: Svetlana Korobtseva <[email protected]>
Co-authored-by: Alena Batitskaia <[email protected]>
Co-authored-by: Alena Batitskaia <[email protected]>
  • Loading branch information
4 people authored Jul 19, 2024
1 parent 41bc198 commit fffabe9
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 39 deletions.
176 changes: 176 additions & 0 deletions css/perspective/demos/dynamic-practice/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Интерактивная песочница — perspective — Дока</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap">
<style>
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html {
color-scheme: dark;
accent-color: #2E9AFF;
}

body {
min-height: 100vh;
padding: 50px;
display: flex;
align-items: center;
justify-content: center;
background-color: #18191C;
color: #FFFFFF;
font-family: "Roboto", sans-serif;
font-size: 18px;
overflow: hidden;
}

code {
font-family: "Roboto Mono", monospace;
font-size: calc(1em - 1px);
}

.container {
width: 500px;
margin: 0 auto;
}

.controls {
margin-bottom: 25px;
text-align: center;
text-transform: lowercase;
}

.value {
font-size: 40px;
font-weight: 500;
}

.slider {
display: block;
width: 100%;
margin: 5px 0;
}

.plane {
width: 500px;
height: 250px;
perspective: 500px;
transform-style: preserve-3d;
background-color: #2e9aff80;
display: grid;
grid-template-rows: 40px 1fr 40px;
justify-items: center;
align-items: center;
}

.element {
text-align: left;
width: 500px;
height: 150px;
background-color: #F498AD;
transform: rotateY(45deg);
position: relative;
}

.line {
width: 1px;
height: calc(100% - 2px);
position: absolute;
top: 0;
left: -10px;
background-color: #fff;
}

.line::before,
.line::after {
content: "";
position: absolute;
top: 0;
height: 1px;
left: -4px;
width: 10px;
background-color: #fff;
}

.line::after {
top: 100%;
}

.height-calc {
transform: rotateZ(-90deg);
position: absolute;
left: -35px;
top: 44%;
}

@media (max-width: 768px) {
body {
padding: 30px;
}

.container, .plane, .element {
width: 300px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="controls">
<label>
<code class="value"><span id="demo"></span></code>
<input type="range" min="200" max="1000" value="500" class="slider" id="myRange">
</label>
<p>Значение свойства <code>perspective</code></p>
</div>
<div class="plane">
Плоскость экрана
<div class="element">
<pre>
<code>
.pink-element {
width: 500px;
height: 150px;
transform: rotateY(45deg);
}
</code>
</pre>
<div class="line">
<code class="height-calc"></code>
</div>
</div>
</div>
</div>

<script>
const myRange = document.getElementById('myRange')
const output = document.getElementById('demo')
const plane = document.querySelector('.plane')
const element = document.querySelector('.element')
const heightCalc = document.querySelector('.height-calc')
const height = element.clientHeight
output.textContent = myRange.value + 'px'
heightCalc.textContent = "232px"

myRange.onchange = myRange.oninput = function () {
let value = myRange.value

plane.style.perspective = `${+value}px`
output.textContent = `${+value}px`

let multiplier = value / (value - (Math.sin(Math.PI / 4) * 250))

heightCalc.textContent = Math.round(height * multiplier) + "px"
}
</script>
</body>
</html>
56 changes: 18 additions & 38 deletions css/perspective/demos/dynamic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,45 +59,33 @@
margin: 5px 0;
}

.scene {
position: absolute;
.plane {
width: 500px;
height: 250px;
perspective: 500px;
}

.scene-wrapper {
width: 500px;
height: 250px;
transform-style: preserve-3d;
background-color: #2e9aff80;
display: grid;
grid-template-rows: 40px 1fr 40px;
justify-items: center;
align-items: center;
}

.element {
display: flex;
justify-content: center;
text-align: center;
width: 500px;
height: 250px;
height: 150px;
padding: 15px;
}

.element--front {
align-items: end;
background-color: #2e9aff80;
transform: rotateY(0) translateZ(100px);
}

.element--back {
align-items: start;
background-color: #F498AD;
transform: rotateY(180deg) translateZ(100px);
transform: rotateY(45deg);
}

@media (max-width: 768px) {
body {
padding: 30px;
}

.container, .scene, .scene-wrapper, .element {
.container, .plane, .element {
width: 300px;
}
}
Expand All @@ -108,36 +96,28 @@
<div class="controls">
<label>
<code class="value"><span id="demo"></span></code>
<input type="range" min="100" max="1000" value="500" class="slider" id="myRange">
<input type="range" min="200" max="1000" value="500" class="slider" id="myRange">
</label>
<p>Значение свойства <code>perspective</code></p>
</div>
<div class="scene">
<div class="scene-wrapper">
<div class="element element--back">Задняя стенка экрана</div>
</div>
<div class="plane">
Плоскость экрана
<div class="element">Элемент с <code>transform: rotateY(45deg)</code></div>
</div>
<div class="element element--front">Пользователь</div>
</div>

<script>
const myRange = document.getElementById('myRange')
const output = document.getElementById('demo')
const scene = document.querySelector('.scene')
const elementBack = document.querySelector('.element--back')
const plane = document.querySelector('.plane')
const element = document.querySelector('.element')
output.textContent = myRange.value + 'px'

myRange.onchange = myRange.oninput = function() {
let value = myRange.value
elementBack.style.transform='rotateY(180deg) translateZ(100px)'

if (value === '1000') {
value = 'none'
elementBack.style.transform='rotateY(180deg) translateZ(0)'
}

scene.style.perspective = value === 'none' ? 'none' : `${ +value}px`
output.textContent = value === 'none' ? 'none' : `${ +value}px`
plane.style.perspective = `${ +value}px`
output.textContent = `${ +value}px`
}
</script>
</body>
Expand Down
4 changes: 3 additions & 1 deletion css/perspective/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: "`perspective`"
description: "Перспектива есть всегда, даже в двумерном вебе."
authors:
- sqlzzy
contributors:
- denis-gh
related:
- css/transform
- css/transition
Expand All @@ -13,7 +15,7 @@ tags:

## Кратко

Свойство `perspective` определяет расстояние от пользователя до _задней стенки_ экрана по оси _z_. Таким образом можно придать глубину элементу, к которому применяется свойство [`transform`](/css/transform/). Эффект заметен только при 3D-трансформациях.
Свойство `perspective` определяет расстояние от пользователя до плоскости экрана по оси _z_. При уменьшении значения свойства `perspective` элементы (или части элементов), расположенные выше плоскости экрана по оси _z_ (ближе к зрителю) увеличиваются в размерах, а те, что дальше — уменьшаются. Таким образом можно придать глубину элементу, к которому применяется свойство [`transform`](/css/transform/). Эффект заметен только при 3D-трансформациях.

Свойство `perspective` влияет на _вложенные элементы_ контейнера, для которого указано, а не на сам контейнер.

Expand Down
5 changes: 5 additions & 0 deletions css/perspective/practice/denis-gh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
🛠 Для точного масштабирования в перспективе мы можем определить, во сколько раз увеличится элемент, по формуле _d/(d-z)_, где _d_ — значение свойства `perspective`, _z_ — смещение элемента отностительно плоскости экрана по оси _z_. Смещение по оси _z_ определяем следующим образом: если задали элементу `transform: translateZ(100px)`, то параметр _z_ равен 100px, а если задали элементу `transform: rotateY(20deg)`, то для крайней левой точки элемента смещение по оси _z_ определяется как _sin(20)_, умноженный на половину изначальной ширины элемента.

Рассмотрим на конкретном примере: изначальная ширина элемента — 500px, высота — 150px, элемент повёрнут на 45°, родителю зададим `perspective: 700px`. Применяем формулу: 700 / (700 - sin(45) * 250) = 1,3379 — во столько раз увеличится высота элемента в крайней левой точке. Подставляя разные значения в формулу можем «на бумаге» рассчитать эффект перспективы.

<iframe title="Интерактивная песочница" src="../demos/dynamic-practice/" height="500"></iframe>
8 changes: 8 additions & 0 deletions people/denis-gh/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: 'Денис Вакуленко'
url: https://github.com/Denis-GH
badges:
- first-contribution-small
---

Начинающий фронтендер

0 comments on commit fffabe9

Please sign in to comment.