From the GIF image you can see what kind of effect we are going for. So let’s take a look at how to achieve this with Angular. I have generated an Angular project and for the purpose of this article/tutorial we will implement this effect in the app component
.
So let’s create the HTML page first1
2
3
4
5
6
7<div class='wrapper' (mousemove)='onMouseMove($event)'>
<div class="card" #card>
<div class="card-content">
<p class="info">Photo by Doug Maloney on Unsplash</p>
</div>
</div>
</div>
Here we have a wrapper which we are going to extend to full screen later with css, we have an eventListener (mousemove)
and our onMouseMove($event)
method that will grab the event $event
. Than we have a div with a class card
and a template reference variable #card
. Next we have the card content with a class card-content
and a paragraph with a class info
.
For our next step we can focus on the css1
2
3
4
5
6
7.wrapper {
background: #2d809c;
-webkit-perspective: 500px;
perspective: 500px;
display: flex;
height: 100vh;
}
The Wrapper, here we add a background color, set the display to flex, we set the height of the wrapper to 100vh
of viewport height (basicly making it full-size) and perspective of 500px
defining how far the card is away from the user (we need this for later on when we mess with the transform property).
Now let’s make the card1
2
3
4
5
6
7
8
9
10
11
12
13
14.card {
background-image: url("../assets/images/doug-maloney-767820-unsplash.jpg");
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
padding: 30px;
border-radius: 10px;
width: 250px;
height: 250px;
margin: auto;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
box-shadow: 0 0 5px rgba(20, 20, 20, .6);
}
I have downloaded an image from Unsplash and added it to /assets/images/
and i have set that as background of our card, next there is some padding and some border radius and width and height to make it a bit rounded, added in slight shadow and some transform-style
(specifying how nested elements are rendered in 3D space). This property is supposed to be used together with transform
property so in our typscript file later, you can see how to add this aditinal poperty that will have dynamic values based on the pointer position.
Card after1
2
3
4
5
6
7
8
9
10.card:after {
content: " ";
position: absolute;
width: 100%;
height: 10px;
border-radius: 70%;
left: 0;
bottom: -50px;
box-shadow: 0px 25px 15px #1a18184d;
}
Of corse to make it look believable that the card is floating we add a bit of shade under our card nothing special here.
Card content1
2
3
4
5
6.card-content {
margin: auto;
text-align: center;
bottom: 20px;
position: absolute;
}
Same here, nothing special just positioning the content on the bottom of the card.
Info1
2
3
4
5
6
7
8.info {
display: block;
-webkit-transform: translateZ(60px);
transform: translateZ(60px);
font-style: italic;
font-weight: bold;
color:white;
}
Now here for the transform
property i set the translateZ(60px)
to give the text that perspective that it’s sort of floating in front of the card in about 60px apart.
That’s all about our CSS, now it’s time to move on with app.component.ts
First thing to do is to import ViewChild
, ElementRef
and Renderer2
1
import { Component,ViewChild,ElementRef,Renderer2} from '@angular/core';
Next pass in Renderer2 to the constructor1
constructor(private renderer:Renderer2){}
Grab a reference to the HTML card
element1
'card') card: ElementRef; (
And build onMouseMove
method1
2
3
4
5onMouseMove(event) {
let x = -(window.screen.width / 2 - event.screenX) / 10;
let y = (window.screen.height / 2 - event.screenY) / 7;
this.renderer.setStyle(this.card.nativeElement,'transform',`rotateY(${x}deg) rotateX(${y}deg)`);
}
So here we have x
and y
values generated from the window width and height, divided by 2, minus the position of the mouse pointer which we grab from passing in the $event
, you can play with these values depending on how you want the card to flow in your app. I wanted it to be smooth and not go over 180 degrees when we move the pointer from one side to the other that’s why i have divided it by 10 on the X and 7 on the Y axis.
Next we grab the renderer
, call setStyle
and pass in the card element this.card.nativeElement
than the style transform
and the value rotateY(${x}deg) rotateX(${y}deg)
.
So that’s it guys, hope this was fun and you can find a use in your projects for this, you can find the full code on my github .
Thanks and I’ll cya in the next one.