В этом уроке мы создадим интерактивный элемент со свойством перспективы CSS3, чтобы дать представление о трех измерениях. Этот урок также научит вас, как использовать jQuery с событиями мыши для получения позиций элементов в JavaScript и как манипулировать свойствами CSS.
Структура HTML для свойства перспективы
Нам нужно, чтобы родительские и дочерние отношения работали правильно. Давайте сначала создадим структуру HTML, а затем продолжим стилизацию CSS.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<div id=»mainWrapper»>
<div id=»cardsWrapper»>
<div class=»card»>
<div class=»image first»>
<div class=»screen»></div>
<div class=»text»>
<p>Mountain</p>
<p>5 Days</p>
</div>
</div>
</div>
<div class=»card»>
<div class=»image second»>
<div class=»screen»></div>
<div class=»text»>
<p>Island</p>
<p>2 Days</p>
</div>
</div>
</div>
</div>
</div>
|
Здесь мы заключаем два элемента card
в div с идентификатором cardsWrapper
. Кроме того, этот cardsWrapper
обернут в другой div, чтобы иметь возможность легко манипулировать его положением в области просмотра.
Каждый элемент с классом card
имеет элемент image
, который охватывает screen
и text
элементы. Структура пока немного расплывчата, но я объясню использование каждого элемента в соответствующих следующих разделах.
Давайте использовать следующий стиль CSS для позиционирования наших элементов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#mainWrapper{
display: flex;
justify-content: center;
align-items: center;
height: 350px;
}
#cardsWrapper{
display: flex;
justify-content: space-between;
width: 700px;
}
.card{
width: 300px;
height: 175px;
background-color: red;
}
.image{
width: 100%;
height: 100%;
background-color: red;
}
|
Использование свойства перспективы
Свойство perspective
— это то, что вы должны установить в родительском элементе div, который содержит элементы div, которые вы хотите преобразовать с учетом перспективы. Представьте, что родительский div — это ваш мир, и он имеет определенную перспективную ценность, которую вы испытываете.
Давайте добавим perspective
свойство к нашему родительскому div, который является card
. Мы cardsWrapper
элемент card
как родительский, а не cardsWrapper
, поскольку мы хотим, чтобы каждый элемент карты имел индивидуальный эффект перспективы.
Настройте CSS card
следующим образом.
1
2
3
4
5
6
|
.card{
width: 300px;
height: 175px;
background-color: red;
perspective: 500px;
}
|
Теперь попробуйте добавить свойство transform
к элементу изображения, чтобы увидеть эффект перспективы.
1
2
3
4
5
6
|
.image{
width: 100%;
height: 100%;
background-color: red;
transform: rotateX(30deg);
}
|
Поскольку image
является прямым потомком card
, оно зависит от перспективы. Однако, если вы попытаетесь добавить свойство transform
к любому дочернему элементу image
, это не будет работать.
Чтобы эти дочерние элементы были преобразованы относительно их родителя, который является элементом image
в этом примере, вы должны использовать transform-style: preserve-3d
на родительском элементе.
1
2
3
4
5
6
|
.image{
width: 100%;
height: 100%;
transform-style: preserve-3d;
transform: rotateX(30deg);
}
|
Теперь у нас есть достаточный фон в свойстве перспективы и мы готовы продолжить стилизацию других элементов.
Не забудьте удалить transform: rotateX(30deg)
из вашего элемента изображения.
Стилизация карт
У нас есть элемент image
, и поверх него есть элемент с именем screen
, а затем text
. Поскольку мы используем здесь перспективу, вы можете думать о каждом из этих элементов как об отдельных слоях.
Теперь мы добавим фоновое изображение к нашему image
div и затем screen
элементы screen
и text
.
Давайте использовать следующий стиль CSS, чтобы добавить фоновое изображение к каждому отдельному объекту карты.
1
2
3
4
5
6
7
|
.image.first{
background-image: url(«https://c1.staticflickr.com/1/343/31652757460_b2b5794a51_n.jpg»);
}
.image.second{
background-image: url(«https://c2.staticflickr.com/2/1506/25121644830_2d768ef51a_n.jpg»);
}
|
Теперь мы будем screen
элемент screen
.
Поскольку мы хотим, чтобы элемент screen
был точно такого же размера, как и его родительский элемент image
, мы используем 100% значения ширины и высоты и серый черный цвет фона с альфа-каналом.
Импортируемая часть — это transform: translateZ(30px) scale(0.940)
.
Здесь мы просто переводим элемент screen
на оси Z на 20 пикселей. Это заставляет его парить над элементом image
. Так как это к нам, это будет больше по размеру, из-за правил перспективы. Поэтому мы уменьшаем его до размера, соответствующего родительскому элементу. Если вы используете разные значения перевода, значение масштаба будет отличаться. Аналогично, определение различных размеров высоты и ширины для родительского элемента приведет к требованию другого значения масштабирования.
1
2
3
4
5
6
|
.screen{
background-color: rgba(0, 0, 0, 0.22);
width: 100%;
height: 100%;
transform: translateZ(30px) scale(0.940);
}
|
Чтобы понять, что здесь происходит, просто поверните элемент image
вокруг осей X и Y, добавив следующую строку в правило CSS:
transform: rotateX(30deg) rotateY(30deg)
Теперь последняя часть этого раздела — стилизация text
элемента, что довольно тривиально.
Мы в основном используем те же настройки преобразования для text
элемента, чтобы он находился на том же уровне, что и элемент screen
. Остальная часть CSS — это просто стилизация. Вы можете настроить его так, как вам нравится.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
.text{
position: absolute;
bottom: 25px;
left: 30px;
color: white;
transform: translateZ(30px) scale(0.940);
}
.text p{
cursor: default;
padding: 0;
margin: 0;
}
.text p:first-of-type{
font-size: 2em;
margin-bottom: 5px;
}
.text p:last-of-type{
font-size: 1em;
}
|
Это конечный результат с ручным вращением, чтобы увидеть эффект.
Прежде чем продолжить, удалите правила вращения из вашего CSS, так как мы будем автоматически контролировать поворот в соответствии с положением курсора.
Теперь мы напишем некоторый код jQuery , чтобы сделать эти карты интерактивными.
Давайте доберемся до этого!
Добавление взаимодействия с jQuery
Давайте начнем с базового кода jQuery.
1
2
3
|
(function($){
})(jQuery);
|
Мы будем писать все внутри этой функции. Это позволит jQuery ждать, пока DOM не будет готов.
Так как мы заинтересованы во взаимодействии с нашим элементом card
, нам нужно выбрать его.
1
2
3
|
(function($){
var card = $(«.card»);
})(jQuery);
|
Следующим шагом является регистрация позиции курсора на элементе карты. Для этого мы будем использовать встроенное событие mousemove
.
1
2
3
4
|
(function($){
var card = $(«.card»);
card.on(‘mousemove’, function (e) {});
})(jQuery);
|
Теперь нам нужно отследить положение курсора. Немного сложно получить правильные значения.
1
2
3
4
5
6
7
|
(function($){
var card = $(«.card»);
card.on(‘mousemove’, function (e) {
var x = e.clientX — $(this).offset().left + $(window).scrollLeft();
var y = e.clientY — $(this).offset().top + $(window).scrollTop();
});
})(jQuery);
|
Здесь e.clientX
и e.clientY
возвращают позицию курсора внутри области просмотра. Однако, поскольку каждый объект card
располагается относительно области просмотра, мы должны компенсировать это, извлекая значения левого и верхнего смещения.
Последнее и самое важное, что нужно учитывать, это компенсация прокрутки окна. Таким образом, поскольку ваша позиция курсора зарегистрирована относительно вашего окна просмотра, но значения смещения фиксированы, при прокрутке ваш объект становится ближе к верху или левому краю окна просмотра в зависимости от направления, в котором вы прокручивались.
В результате наше относительное расстояние до вершины или левого угла области просмотра будет меньше. Однако, поскольку значения смещения фиксированы, мы должны это компенсировать, и это делается с помощью $(window).scrollLeft()
и $(window).scrollTop()
. Таким образом, добавляя эти значения к соответствующим переменным, мы просто компенсируем сумму, которую мы прокручивали. В результате, когда вы наводите курсор мыши на любой из элементов вашей card
, ваша позиция X будет варьироваться от 0 до ширины карты, которая определяется как 300px. Аналогично, позиция Y будет варьироваться от 0 до высоты карты, которая составляет 175px.
Следующим шагом является сопоставление позиции курсора с новым диапазоном, который будет величиной поворота, которую мы хотим применить в градусах, чтобы, когда ваш курсор стоял в середине элемента карты, он выглядел просто плоско, но когда вы двигаетесь влево / вправо или вверх / вниз, вы получите эффект вращения, как если бы карта следовала за курсором.
Вот краткая иллюстрация результата функции отображения.
1
2
3
4
|
function map(x, in_min, in_max, out_min, out_max)
{
return (x — in_min) * (out_max — out_min) / (in_max — in_min) + out_min;
}
|
В этой функции параметры in_min
и in_max
являются минимальными и максимальными значениями входного значения соответственно, которые соответствуют ширине и высоте элемента card
. out_min
и out_max
являются минимальными и максимальными значениями, которые будут отображаться на входе.
Давайте использовать эту функцию карты с нашими позициями курсора X и Y.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
(function($){
var card = $(«.card»);
card.on(‘mousemove’, function (e) {
var x = e.clientX — $(this).offset().left + $(window).scrollLeft();
var y = e.clientY — $(this).offset().top + $(window).scrollTop();
var rY = map(x, 0, $(this).width(), -17, 17);
var rX = map(y, 0, $(this).height(), -17, 17);
});
function map(x, in_min, in_max, out_min, out_max)
{
return (x — in_min) * (out_max — out_min) / (in_max — in_min) + out_min;
}
})(jQuery);
|
Теперь наши сопоставленные значения rX
и rX
.
Следующим шагом является установка правила CSS для элемента image
с использованием сопоставленных значений в качестве значений поворота.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
(function($){
var card = $(«.card»);
card.on(‘mousemove’, function (e) {
var x = e.clientX — $(this).offset().left + $(window).scrollLeft();
var y = e.clientY — $(this).offset().top + $(window).scrollTop();
var rY = map(x, 0, $(this).width(), -17, 17);
var rX = map(y, 0, $(this).height(), -17, 17);
$(this).children(«.image»).css(«transform», «rotateY(» + rY + «deg)» + » » + «rotateX(» + -rX + «deg)»);
});
function map(x, in_min, in_max, out_min, out_max)
{
return (x — in_min) * (out_max — out_min) / (in_max — in_min) + out_min;
}
})(jQuery);
|
Здесь мы выбрали дочерние элементы элемента card
с именем image
, а затем установили правило CSS для поворота этого элемента вокруг осей X и Y на rX
и rX
градусов соответственно.
Вы поймете, что элементы карты следуют за курсором в их соответствующих ракурсах. Однако, когда курсор находится вне элементов карты, они сохраняют свою ориентацию. Более того, они резко реагируют на наличие курсора над элементом карты. Поэтому нам также нужно обрабатывать те случаи, когда мышь входит и покидает элемент карты.
Чтобы справиться с этими проблемами, нам нужно использовать события mouseenter
и mouseleave
.
Когда мышь входит в область элемента card
, мы добавляем правило CSS перехода к элементу image
. Это обеспечит плавный переход для «взгляда» элемента image
.
1
2
3
4
5
|
card.on(‘mouseenter’, function () {
$(this).children(«.image»).css({
transition: «all » + 0.05 + «s» + » linear»
});
});
|
Точно так же нам нужно обработать событие mouseleave
.
Здесь я также добавляю еще одно правило CSS перехода с другой синхронизацией, которое делает плавный переход в исходное положение, когда мышь покидает элемент card
.
Я также добавляю правило CSS transform для сброса вращений элемента card
.
1
2
3
4
5
6
7
|
card.on(‘mouseleave’, function () {
$(this).children(«.image»).css({
transition: «all » + 0.2 + «s» + » linear»
});
$(this).children(«.image»).css(«transform», «rotateY(» + 0 + «deg)» + » » + «rotateX(» + 0 + «deg)»);
});
|
Итак, наш окончательный код jQuery выглядит так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
(function($){
var card = $(«.card»);
card.on(‘mousemove’, function (e) {
var x = e.clientX — $(this).offset().left + $(window).scrollLeft();
var y = e.clientY — $(this).offset().top + $(window).scrollTop();
var rY = map(x, 0, $(this).width(), -17, 17);
var rX = map(y, 0, $(this).height(), -17, 17);
$(this).children(«.image»).css(«transform», «rotateY(» + rY + «deg)» + » » + «rotateX(» + -rX + «deg)»);
});
card.on(‘mouseenter’, function () {
$(this).children(«.image»).css({
transition: «all » + 0.05 + «s» + » linear»,
});
});
card.on(‘mouseleave’, function () {
$(this).children(«.image»).css({
transition: «all » + 0.2 + «s» + » linear»,
});
$(this).children(«.image»).css(«transform», «rotateY(» + 0 + «deg)» + » » + «rotateX(» + 0 + «deg)»);
});
function map(x, in_min, in_max, out_min, out_max)
{
return (x — in_min) * (out_max — out_min) / (in_max — in_min) + out_min;
}
})(jQuery);
|
Вот окончательный результат. Я также использовал другой шрифт без засечек для text
элемента, чтобы он выглядел лучше.
Вывод
В этом уроке мы узнали, как использовать перспективное свойство и требуемую структуру HTML для правильной работы. Кроме того, мы рассмотрели, как зарегистрировать положение курсора мыши при наведении на определенный элемент HTML.
Кроме того, мы использовали mousemove
, mouseenter
и mouseleave
для mouseleave
интерактивности, добавляя правила CSS к элементам HTML с помощью jQuery.
Я надеюсь, что вам понравился этот урок и вы узнали некоторые полезные методы.