Resizing and scrolling issue (JS/HTML) - javascript

There are two containers: the first is a small viewport and the second is huge workspace. So, user scroll the viewport to move within the workspace. I want to implement a zoom in/out feature via CSS property tranform, but during the process I faced one difficulty and could not find a precise solution for it.
The issue is: when user zooms in/out, elements at the workspace are shifted. This happens actually because the workspace is resized, not they. But if I resize each element at the workspace, the distances between them (in terms of top/left CSS values) will be changed, what is not preferred.
I see the following solution: change scrolls values after resizing, but I do not know what ratios or numbers to use. Is there any formulae or another solution to overcome such a problem?
For resizing use Alt + MouseWheel
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
workspace.style.setProperty('transform', 'scale(' + new_scale + ')');
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
<div class="viewport">
<div class="workspace">
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>
UPD: I attached some photos from the original project for clarification:
So, that's a look of the workspace with scale(1)
Then I resize it and get the following result:
But desirable result looks like this:
UPD2
I inserted <svg> element to show how lines are drawn and why resizing each button seems to me a not viable solution in my case
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event;
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
var btns = workspace.getElementsByClassName('element');
for(var i = 0; i <btns.length; i++) {
btns[i].style.setProperty('transform', 'scale(' + new_scale + ')');
}
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
transform-origin: 0 0;
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
.line-drawer
{
position:absolute;
height:1000px;
width:1000px;
}
<div class="viewport">
<div class="workspace">
<svg class="line-drawer">
<line x1="100px" x2="130px" y1="80px" y2="230px" style='stroke-width: 4px; stroke: black'></line>
</svg>
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top: 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>

Scaling the individual elements like this will keep them in there position
let workspace = document.getElementsByClassName('workspace')[0];
workspace.onwheel = resize;
let current_scale = 1;
function resize(E) {
E = E || window.event
if (E.altKey) {
E.preventDefault();
let new_scale = Math.max(0.1, current_scale - E.deltaY / 360);
var btns = workspace.getElementsByClassName('element');
for(var i = 0; i <btns.length; i++) {
btns[i].style.setProperty('transform', 'scale(' + new_scale + ')');
}
current_scale = new_scale;
}
}
.viewport {
width: 80vw;
height: 80vh;
box-sizing: border-box;
overflow: scroll;
transform: scale(1);
}
.workspace {
position: relative;
width: 1000px;
height: 1000px;
overflow: hidden;
}
.element {
position: absolute;
width: 10px;
height: 10px;
}
<div class="viewport">
<div class="workspace">
<button class="element" style="top: 100px; left: 150px"></button>
<button class="element" style="top 80px; left: 100px"></button>
<button class="element" style="top: 230px; left: 130px"></button>
<button class="element" style="top: 100px; left: 250px"></button>
</div>
</div>

Related

Background reveal javascript not working properly

By following this tutorial :https://codepen.io/xaviDDB/pen/ExaKeeN I made a section in my website with this background reveal. here is the link:http://example.com/abra/
The code works fine if I do not have any other section in this page. But if I do, then it gets very strange. The reveal circle move away from the Mouse. See the page, I have added a horse image & the code gets messy. How do I solve this?
This is my current code:
(function() {
let magic = document.querySelector('.magic');
let magicWHalf = magic.offsetWidth / 2;
document.body.addEventListener('mousemove', function(e) {
magic.style.left = e.pageX - magicWHalf + 'px';
magic.style.top = e.pageY - magicWHalf + 'px';
});
document.body.addEventListener('mouseout', function(e) {
//magic.style.left = 'calc(50% - 10rem)';
//magic.style.top = 'calc(50% - 10rem)';
});
})();
.containers {
position: relative;
height: 100vh;
width: 100%;
background-color: #ffffff;
text-align: center;
overflow: hidden;
z-index: 1;
}
.containers:hover {
cursor: crosshair;
}
.text {
position: absolute;
font-size: 72px;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
bottom: 20%;
left: 0;
right: 0;
z-index: 3;
}
.magic {
position: absolute;
top: calc(50% - 10rem);
left: calc(50% - 10rem);
width: 500px;
height: 500px;
background: center center no-repeat fixed;
background-size: cover;
border-radius: 50%;
z-index: 2;
}
<div class="containers">
<div class="text">Lorem Ipsum</div>
<div class="magic" style="background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/hover-reveal.jpg')"></div>
</div>
You have to update your mouse-move function in javascript. It has to calculate the relative mouse position to its parent (.container)
and one more improvement: set the eventListener on the element you want to hover. Not the entire body.
(function() {
const container = document.querySelector('.container');
const magic = document.querySelector('.magic');
const magicWHalf = magic.offsetWidth / 2;
container.addEventListener('mousemove',function(e){
const rect = container.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
magic.style.left = (e.pageX - (rect.left + scrollLeft)) - magicWHalf+'px';
magic.style.top = (e.pageY - (rect.top + scrollTop)) - magicWHalf+'px';
});
container.addEventListener('mouseout',function(e){
//magic.style.left = 'calc(50% - 10rem)';
//magic.style.top = 'calc(50% - 10rem)';
});
})();
.container {
position: relative;
height: 100vh;
width: 100%;
background-color: #ffffff;
text-align: center;
overflow: hidden;
z-index: 1;
}
.container:hover {
cursor: crosshair;
}
.text {
position: absolute;
font-size: 72px;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
bottom: 20%;
left: 0;
right: 0;
z-index: 3;
}
.magic {
--size: 20rem;
position: absolute;
top: calc(50% - var(--size));
left: calc(50% - var(--size));
width: var(--size);
height: var(--size);
background: center no-repeat fixed;
background-size: cover;
border-radius: 50%;
z-index: 2;
}
<h1>add</h1>
<h1>extra</h1>
<h1>space</h1>
<h1>at top</h1>
<div class="container">
<div class="text">Lorem Ipsum</div>
<div class="magic" style="background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/hover-reveal.jpg')"></div>
</div>
You need to add the height of the previous element of your div.container
html
<div class="other">Other div </div>
<div class="container">
<div class="text">Lorem Ipsum</div>
<div class="magic" style="background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/hover-reveal.jpg')"></div>
</div>
js
let magic = document.querySelector('.magic');
let magicWHalf = magic.offsetWidth / 2;
let heightPrevELm=document.querySelector('.other').offsetHeight;
document.body.addEventListener('mousemove',function(e){
magic.style.left = e.pageX - magicWHalf+'px';
magic.style.top = e.pageY - (magicWHalf+heightPrevELm)+'px';
});
You can see the result here :
https://codepen.io/bertyn99/pen/YzEwOpO
But i think if they are multiple element before we need to optimize the code

is there a way to make a background scroll down while some content stay in the middle at all time?

I'm trying to do something like (in js, html, sass) :
when I scroll the page down my layers (ground, sky, space, ...) go down
my content (that will be a rocket going in the sky) stay in the middle of the screen and will move to the sides like if it were to be flying (that will be for later)
some elements will move on the layers (like asteroids going from right to left or something) (for later)
So here are some ideas of code I tried but this seem odd and do not work as intended; as you can see, the layers are scrolling as intended, but they are not all showing for whatever reason, they seem to fill all the page size but they shouldn't and i'm going round and round about this on the internet and no one seem to have done something like this.
// Functions
detectPageVerticalPosition = () => {
pageVerticalPosition = pageYOffset;
};
getDivs = () => {
for (
let div = document.getElementsByTagName("div"), i = 0; i < div.length; i++
) {
div[i].getAttribute("class") == "layer-vertical" &&
layerVerticalArray.push(div[i]);
}
console.log("layerVerticalArray: ", layerVerticalArray);
};
moveLayers = () => {
for (let i = 0; i < layerVerticalArray.length; i++) {
layerVerticalArray[i].style.bottom = -1 * pageVerticalPosition + "px";
}
};
// End Functions
// Variables
var pageVerticalPosition = 0,
layerVerticalArray = new Array();
// End Variables
// Events
window.onload = e => {
getDivs();
// console.log(layerVerticalArray);
};
window.onscroll = e => {
detectPageVerticalPosition();
moveLayers();
};
// End Events
body {
margin: 0;
}
#page {
position: relative;
height: 20000px;
width: 100%;
}
#rocket-container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
#rocket-container #rocket {
position: absolute;
width: 100px;
height: 100px;
left: calc(50% - 50px);
top: calc(50% - 50px);
}
#background-container {
position: fixed;
height: 100%;
width: 100%;
background-color: red;
overflow: hidden;
}
#background-container .layer-vertical {
width: 100%;
height: 3500px;
}
#background-container #layer-vertical-1 {
position: absolute;
background-color: blue;
}
#background-container #layer-vertical-1 #cloud-1 {
outline-style: dashed;
right: 0px;
}
#background-container #layer-vertical-1 #cloud-2 {
outline-style: dotted;
bottom: 0px;
}
#background-container #layer-vertical-2 {
background-color: green;
}
#background-container #layer-vertical-3 {
background-color: purple;
}
.cloud {
position: absolute;
width: 180px;
height: 120px;
background-image: url(../images/cloud.png);
}
<div class="page">
<div class="background-container">
<div class="layer-vertical" id="layer-vertical-1">
Layer 1
<div class="cloud" id="cloud-1"></div>
<div class="cloud" id="cloud-2"></div>
</div>
<div class="layer-vertical" id="layer-vertical-2">
Layer 2
</div>
<div class="layer-vertical" id="layer-vertical-3">
Layer 3
</div>
</div>
<div id="rocket-container">
<div id="rocket">STAY MIDDLE</div>
</div>
</div>
[1]: https://via.placeholder.com/180/120
So, here's what i found in order to fix this (jsfiddle: http://jsfiddle.net/kjrte2sd/2/)
i used some jquery to make the background-container scroll down as intended instead of each elements scrolling down by himself.
now the page div is gone and the body handle the sizing of the whole thing.
i guess the answer was simpler than i expected it to be.
var winHeight = $(window).innerHeight();
$(document).ready(() => {
$(".layer-vertical").height(winHeight);
$("body").height(winHeight * $(".layer-vertical").length);
});
window.addEventListener("resize", e => {
$(".layer-vertical").height($(window).innerHeight());
});
$(window).on("scroll", () => {
$("#background-container").css("bottom", $(window).scrollTop() * -1);
});
body {
margin: 0;
padding: 0;
}
#rocket-container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
#rocket-container #rocket {
position: absolute;
width: 100px;
height: 100px;
left: calc(50% - 50px);
top: calc(50% - 50px);
}
#background-container {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}
#background-container .layer-vertical {
width: 100%;
}
#background-container .layer-vertical h1 {
width: 100px;
position: relative;
display: block;
margin: 0 auto;
text-align: center;
top: 50%;
}
#background-container #layer-vertical-1 {
background-color: green;
}
#background-container #layer-vertical-2 {
background-color: red;
}
#background-container #layer-vertical-3 {
background-color: white;
}
#background-container #layer-vertical-4 {
background-color: pink;
}
#background-container #layer-vertical-5 {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="background-container">
<div class="layer-vertical" id="layer-vertical-5">
<h1>5</h1>
</div>
<div class="layer-vertical" id="layer-vertical-4">
<h1>4</h1>
</div>
<div class="layer-vertical" id="layer-vertical-3">
<h1>3</h1>
</div>
<div class="layer-vertical" id="layer-vertical-2">
<h1>2</h1>
</div>
<div class="layer-vertical" id="layer-vertical-1">
<h1>1</h1>
</div>
</div>
<div id="rocket-container">
<div id="rocket">STAY MIDDLE</div>
</div>

Keep parallax moving for one second on mouseout and stop smoothly

I would like to make a website with mouse parallax effect like in this page http://brightmedia.pl background mouse parallax is so smooth..
I have two questions:
When you mouseover on a container from, let's say, the top left corner, the image jumps. How can I make a smooth animation?
When you mouseout of a container, how can I make the image move a little bit and stop with a smooth animation?
What would code to solve these problems be?
Here is basic code:
$('.container').mousemove( function(e){
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({marginLeft: -xPos/20});
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body{
height: 1000px;
}
h1{
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css.css">
</head>
<body>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
As I had solved the problem long time ago and I forgot about this post so I decided to update with the answer. Maybe it will be helpful for anyone else.
Problem solved by using GSAP. Below You can see the code that works exactly as I wanted
let wrap = document.getElementById('container');
let request = null;
let mouse = { x: 0, y: 0 };
let cx = window.innerWidth / 2;
let cy = window.innerHeight / 2;
document.querySelector('.container').addEventListener('mousemove', function(event) {
mouse.x = event.pageX;
mouse.y = event.pageY;
cancelAnimationFrame(request);
request = requestAnimationFrame(update);
});
function update() {
dx = mouse.x - cx;
dy = mouse.y - cy;
let tiltx = (dy / cy );
let tilty = - (dx / cx);
TweenMax.to("#container img", 1, {x:-tilty*20, y:-tiltx*20, rotation:0.01, ease:Power2.easeOut});
}
window.addEventListener('resize', function(event){
window.innerWidth / 2;
window.innerHeight / 2;
});
* {
margin:0;
padding:0;
box-sizing:border-box;
}
.container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.container img {
width: 110%;
height: 120vh;
position: absolute;
}
h1 {
z-index:100;
font-size: 6rem;
z-index: 10;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>GSAP Mouse Parallax</h1>
</div>
You can rely one mouseenter / mouseleave to add animation:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({
marginLeft: -xPos / 10
});
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').animate({
"marginLeft": -xPos / 10
}, "slow");
});
$('.container').mouseleave(function(e) {
$('#par1').animate({
"marginLeft": "0"
}, "slow");
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
As Temani said, playing with transition and eventually delay should do the job.
For 1st question: transition seems appropriate, associated with a mousein listener. Or even better, use the $(element).animate() function that allows to set the animation duration. That way, you don't set any value for transition duration.
For 2nd question: listener on mouseout > same process, but shorter animation (for the img shifting as well as the animation duration).
This should also give you some ideas:
https://codepen.io/Aldlevine/pen/Jowke
Based on Teemani below code example:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseleave(function(e) {
$('#par1').css({"transition": "margin-left 1s ease-in-out", "margin-left": "0"});
setTimeout( function() {
$('#par1').css("transition", "initial");
}, 500);
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
transition: margin-left 0.2s;
/* transition: margin-left 0.2s ease-in-out 0.2s;*/
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>

Parallax Issue in Javascript

I was creating a parallax effect in which the image and the text move in opposite direction to the movement of the mouse. That is happening inside an element called parallax-wrapper. But when I move out of the element I want the image and the text to return back to their original positions. I have tried to detect the mouse position outside the element but for some reason it not firing properly.
The codepen link is - https://codepen.io/rohitgd/pen/gRLNad?editors=1010
HTML
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
CSS
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
Javascript
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(document).mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
alert('out of the element');
e.stopPropagation();
}
});
What I want is when the mouse is outside the parallax-wrapper the Image and the text return back to their original positions.
You're not resetting the transformations when your mouse leaves. You need to add this where you have the alert...
$(".parallax-wrapper").mouseleave(function(e) {
$("*[data-mouse-parallax]").each(function() {
$(this).css({ transform: "translate3d( 0, 0, 0 )" });
});
});
Note that the mouseleave event is triggered when the mouse leaves .parallax-wrapper, not document as you previously had it.
Here's a modified codepen...
https://codepen.io/anon/pen/ZyBgYJ
I think a selector was wrong. Here's a correct version or see code below.
To show better when you are inside/outside I change the background color, that's better than an alert. When you leave the wrapper (the black background) it flips correctly now.
Where RED is set you can reset the transform to the origin.
// Trying to replicate the effect here - https://tympanus.net/Development/MorphingBackgroundShapes/
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$(".parallax-wrapper").css("background-color", "#00ff00"); // <-- EXIT
// reset transform here
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
// this is the selector I changed from "document" to ".parallax-wrapper"
$(".parallax-wrapper").mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
$(".parallax-wrapper").css("background-color", "#ff0000"); // <-- ENTER
e.stopPropagation();
}
});
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
Replace $(document).mouseleave with $(".parallax-wrapper").mouseleave.
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(".parallax-wrapper").mouseleave(function(e) {
alert('out of the element');
});
body {
background-color: #fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color: #0c0c0c;
position: relative;
overflow: hidden;
}
.parallax-wrapper .layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color: #FFF;
transition: all 200ms ease-out;
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>

Is it possible to skew HTML element by a number of pixels using CSS transform?

My problem is:
there's a block containing variable number of HTML elements. Something like this...
<ul class="list">
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
</ul>
This block must have a skew on the right side (the content must not be skewed). The horizontal size of this skew must be fixed. So adding CSS rules like...
.list {
position: relative;
background: #A0A0FF;
}
.list:after {
content: " ";
display: block;
position: absolute;
top: 0;
bottom: 0;
right: -10px;
width: 20px;
transform: skewX(-15deg);
background: #A0A0FF;
}
...won't do because in this case the skew will have variable horizontal size depending on the number of items in the list. The only solution that comes to my mind is to calculate the number of degrees in js. But this is kinda meh.
So my question is: is it possible to somehow skew an element by a number of pixels instead of degrees/radians using CSS?
You can achieve the same skew appearance by using a linear gradient on a pseudo-element.
*,
::after,
::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
ul {
width: 200px;
background: #663399;
margin: 25px auto;
list-style-type: none;
position: relative;
}
ul::after {
position: absolute;
content: "";
top: 0;
left: 100%;
background: linear-gradient(to bottom right, #663399 0%, #663399 50%, transparent 50%, transparent 100%);
width: 16px;
height: 100%;
}
<ul class="list">
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
</ul>
<ul class="list">
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
</ul>
Sorry if my message is irrelevant to this exact case, but once I searched for "CSS skew in pixels" and although neither this question is about what I tried to find (provide the exact width in px to skew), nor the accepted answer solves my problem, I still believe this can help someone someday.
As we know, transform: skew() receives only angles as a parameter.
In order to get the exact width when the angle is unknown, one should calculate the angle using arctangent. Luckily, JavaScript 1.0 Math provides atan2() method to return the arctangent (in radians) by given X and Y coordinates.
Thus, calculating the skew angle has the solution on JS.
The example below draws diagonal lines (via border-bottom/border-left) based on the dimensions of the underlying elements.
let prevY = null;
document.querySelectorAll('.a').forEach(el => {
const top = el.style.top;
const left = el.style.left;
const width = el.style.width;
const height = el.style.height;
const xEl = document.querySelector('#x' + el.id.substr(1));
xEl.style.top = top;
xEl.style.left = left;
xEl.style.width = width;
xEl.style.height = height;
applySkew(el);
});
window.addEventListener('resize', function(e) {
prevY = null;
document.querySelectorAll('.a').forEach(el => {
applySkew(el);
});
});
function applySkew(el) {
const xEl = document.querySelector('#x' + el.id.substr(1));
const top = el.style.top;
const w = el.offsetWidth;
const h = el.offsetHeight;
const directionUp = prevY && prevY != top;
prevY = top;
if(w < h) {
xEl.style.borderBottom = 'none';
xEl.style.borderLeft = 'black 1px solid';
xEl.style.transform = 'skewX(' + Math.atan2((directionUp ? -1 : 1) * w, h) + 'rad) translateX(' + (w / 2) + 'px)';
} else {
xEl.style.borderLeft = 'none';
xEl.style.borderBottom = 'black 1px solid';
xEl.style.transform = 'skewY(' + Math.atan2((directionUp ? -1 : 1) * h, w) + 'rad) translateY(-' + (h / 2) + 'px)';
}
}
html, body {
margin: 0;
height: 100%;
}
body > div {
margin: 5% 0 0 5%;
background: yellow;
position: relative;
height: 40%;
width: 90%;
}
body > div > div {
position: absolute;
box-sizing: border-box;
}
<div>
<div id="a0" class="a" style="
top: 0;
left: 0;
width: 7.5%;
height: 70%;
background-color: rgba(0,255,255,.5);
"></div>
<div id="a1" class="a" style="
top: 40%;
left: 7.5%;
width: 17.5%;
height: 30%;
background-color: rgba(0,255,255,.2);
"></div>
<div id="a2" class="a" style="
top: 40%;
left: 25%;
width: 37%;
height: 55%;
background-color: rgba(0,255,255,.4);
"></div>
<div id="a3" class="a" style="
top: 25%;
left: 62%;
width: 3%;
height: 70%;
background-color: rgba(0,255,255,.1);
"></div>
<div id="a4" class="a" style="
top: 25%;
left: 65%;
width: 35%;
height: 50%;
background-color: rgba(0,255,255,.6);
"></div>
<div id="x0"></div>
<div id="x1"></div>
<div id="x2"></div>
<div id="x3"></div>
<div id="x4"></div>
</div>
I don't know what you are after, But is this what you are searching for?
.list {
position: relative;
background-color: yellow;
}
.list:after {
content: " ";
display: block;
position: absolute;
background-color: blue;
top: 0;
bottom: 0;
right: 10px;
width: 20px;
transform: skewX(-15deg);
}
<ul class="list">
<li class="item">...</li>
<li class="item">...</li>
<li class="item">...</li>
</ul>

Categories

Resources