How can I have the same parallax offset in all the sections? Right now the offset increases as you add more sections. Note that in section .two and .three the parallax is different from section .one. I want section .two and .three to have the same parallax as in section .one. I am unsure what's causing the divs to go wider in section .two and .three.
Why is this happening and how can I fix it?
JSFiddle
Thank you in advance.
JS
var currentX = '';
var currentY = '';
var movementConstant = .05;
$(document).mousemove(function(e) {
var xToCenter = e.pageX - window.innerWidth/2;
var yToCenter = e.pageY - window.innerHeight/2;
$('.parallax div').each( function(i) {
var $el = $(this);
var newX = (i + 1) * (xToCenter * movementConstant);
var newY = (i + 1) * (yToCenter * movementConstant);
$el.css({left: newX + 'px', top: newY + 'px'});
});
});
HTML
<section class="one">
<div class="parallax">
<div class="asset asset-layer4">4</div>
<div class="asset asset-layer3">3</div>
<div class="asset asset-layer2">2</div>
<div class="asset asset-layer1">1</div>
</div>
</section>
<section class="two">
<div class="parallax">
<div class="asset asset-layer4">4</div>
<div class="asset asset-layer3">3</div>
<div class="asset asset-layer2">2</div>
<div class="asset asset-layer1">1</div>
</div>
</section>
<section class="three">
<div class="parallax">
<div class="asset asset-layer4">4</div>
<div class="asset asset-layer3">3</div>
<div class="asset asset-layer2">2</div>
<div class="asset asset-layer1">1</div>
</div>
</section>
CSS
.one,
.two,
.three {
position: relative;
width: 100%;
height: 200px;
}
.one { background-color: pink; }
.two { background-color: lightgray; }
.three { background-color: orange; }
.parallax {
position: absolute;
left: 50%;
top: 50%;
bottom: 50%;
right: 50%;
overflow: visible;
}
.asset {
position: absolute;
}
.asset-layer1 {
background-color: yellow;
}
.asset-layer2 {
background-color: green;
}
.asset-layer3 {
background-color: blue;
}
.asset-layer4 {
background-color: red;
}
body {
overflow:hidden;
}
the issue is that you are doing an each over ALL over the children div of .parallax. This means you are looping about 11 times. Each time you multiply by a larger i value, so it starts to look off.
Instead, what I have done is within each Parallax container, you will loop through it's children, giving you a value from 0-3. Now they are in sync!
https://jsfiddle.net/p4hrbdge/2/
$('.parallax').each( function(i) {
$(this).find('div').each(function(i) {
var $el = $(this);
var newX = (i + 1) * (xToCenter * movementConstant);
var newY = (i + 1) * (yToCenter * movementConstant);
$el.css({left: newX + 'px', top: newY + 'px'});
})
});
Related
So I have a set of elements called .project-slide, one after the other. Some of these will have the .colour-change class, IF they do have this class they will change the background colour of the .background element when they come into view. This is what I've got so far: https://codepen.io/neal_fletcher/pen/eGmmvJ
But I'm looking to achieve something like this: http://studio.institute/clients/nike/
Scroll through the page to see the background change. So in my case what I'd want is that when a .colour-change was coming into view it would slowly animate the opacity in of the .background element, then slowly animate the opacity out as I scroll past it (animating on scroll that is).
Any suggestions on how I could achieve that would be greatly appreciated!
HTML:
<div class="project-slide fullscreen">
SLIDE ONE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#EA8D02">
SLIDE THREE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#cccccc">
SLIDE THREE
</div>
</div>
jQuery:
$(window).on('scroll', function () {
$('.project-slide').each(function() {
if ($(window).scrollTop() >= $(this).offset().top - ($(window).height() / 2)) {
if($(this).hasClass('colour-change')) {
var bgCol = $(this).attr('data-bg');
$('.background').css('background-color', bgCol);
} else {
}
} else {
}
});
});
Set some data-gb-color with RGB values like 255,0,0…
Calculate the currently tracked element in-viewport-height.
than get the 0..1 value of the inViewport element height and use it as the Alpha channel for the RGB color:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;
(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i, el) {
function visPx() {
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(),
t = r.top,
b = r.bottom;
return cb.call(el, Math.max(0, t > 0 ? Math.min(elH, H - t) : (b < H ? b : H)), H);
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// OK. Let's do it
var $wrap = $(".background");
$("[data-bg-color]").inViewport(function(px, winH) {
var opacity = (px - winH) / winH + 1;
if (opacity <= 0) return; // Ignore if value is 0
$wrap.css({background: "rgba(" + this.dataset.bgColor + ", " + opacity + ")"});
});
/*QuickReset*/*{margin:0;box-sizing:border-box;}html,body{height:100%;font:14px/1.4 sans-serif;}
.project-slide {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.project-slide h2 {
font-weight: 100;
font-size: 10vw;
}
<div class="project-slides-wrap background">
<div class="project-slide">
<h2>when in trouble...</h2>
</div>
<div class="project-slide" data-bg-color="0,200,255">
<h2>real trouble...</h2>
</div>
<div class="project-slide">
<h2>ask...</h2>
</div>
<div class="project-slide" data-bg-color="244,128,36">
<h2>stack<b>overflow</b></h2>
</div>
</div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>
Looks like that effect is using two fixed divs so if you need something simple like that you can do it like this:
But if you need something more complicated use #Roko's answer.
var fixed = $(".fixed");
var fixed2 = $(".fixed2");
$( window ).scroll(function() {
var top = $( window ).scrollTop();
var opacity = (top)/300;
if( opacity > 1 )
opacity = 1;
fixed.css("opacity",opacity);
if( fixed.css('opacity') == 1 ) {
top = 0;
opacity = (top += $( window ).scrollTop()-400)/300;
if( opacity > 1 )
opacity = 1;
fixed2.css("opacity",opacity);
}
});
.fixed{
display: block;
width: 100%;
height: 200px;
background: blue;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.fixed2{
display: block;
width: 100%;
height: 200px;
background: red;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.container{
display: inline-block;
width: 100%;
height: 2000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
Scroll me!!
</div>
<div class="fixed">
</div>
<div class="fixed2">
</div>
example: http://codepen.io/anon/pen/mEoONW
Cards at least heave minimum 180 degree rotation, set in CSS with JS, but in multiple run some of it doesn't rotate at all. Can anyone please explain why?
<div class="flip-container">
<div class="flipper">
<div class="front"></div>
<div class="back">?</div>
</div>
</div>
...
<button onclick="rotate();">Rotate</button>
<style>
.flip-container {
perspective: 1000px;float:left;
}
.flip-container, .front, .back {
width: 160px;height: 220px;
}
.flipper {
transform-style:preserve-3d;position: relative;
}
.front, .back {
backface-visibility: hidden;position: absolute; top: 0; left: 0;
}
.front {
z-index: 2; transform: rotateY(0deg);background-color: blue;
}
.back {
transform: rotateY(180deg); background-color: grey;font-size: 13em; text-align: center; vertical-align: middle;
}
</style>
<script>
function rnd(){
var randNum = Math.floor((Math.random() * 20) + 1);
if(randNum %2 == 0){//generated number is even
randNum = randNum +1 ;
}
return randNum;
}
function rotate(){
$('.flipper').each(function(i, obj) {
var rn = rnd();
var nn = 180 * rn;
var sp = 0.2 * rn;
console.log(rn);
$(this).css("transition", sp+"s").css("transform", "rotateY("+nn+"deg)");
});
}
</script>
Easy.
To start rotating in this pen, card has to receive new css.
If the number, that was generated by rnd() function is the same as previous one, css of the element is not changed, so browser doesnt start the animation, it thinks that's it already been played (and it was).
To 'restart animation' if it has SAME params you have two ways - or remove element from DOM and get it back there (ugly, ah?) OR you can clear style and then set it back in time out. That trick will help 'restart' animation.
$element.attr('style', null); //remove old style before setting new
setTimeout(function(){
$element.css("transition", "0.6s");
$element.css("transform", "rotateY("180deg)");
}, 100);
I've forked you pen and made all cards spin here.
You could create an extra checker to prevent the same card from recieing the exact number as before:
function rotate() {
$('.flipper').each(function(i, obj) {
var rn = rnd();
if ( $(this).data('rn') == rn ) { rn = rn + 2; }
var nn = 180 * rn;
var sp = 0.2 * rn;
$(this).data('rn', rn);
$(this).css("transition", sp + "s");
$(this).css("transform", "rotateY(" + nn + "deg)");
console.log(i + ': ' + rn + ' -d: ' + $(this).data('rn'));
});
}
Working Demo:
function rnd() {
var randNum = Math.floor((Math.random() * 20) + 1);
if (randNum % 2 == 0) { randNum = randNum + 1; }
return randNum;
}
function rotate() {
$('.flipper').each(function(i, obj) {
var rn = rnd();
if ( $(this).data('rn') == rn ) { rn = rn + 2; }
var nn = 180 * rn;
var sp = 0.2 * rn;
$(this).data('rn', rn);
$(this).css("transition", sp + "s");
$(this).css("transform", "rotateY(" + nn + "deg)");
//console.log(i + ': ' + rn + ' -d: ' + $(this).data('rn'));
});
}
rotate();
$('body').on('click', '#rotate', function(){rotate();});
.cards::after { clear:both; content: ''; display: table;}
/* entire container, keeps perspective */
.flip-container {
perspective: 1000px;
float: left;
margin: 2px;
}
.flip-container,.front,.back {
width: 160px;
height: 220px;
}
/* flip speed goes here */
.flipper {
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
}
/* hide back of pane during swap */
.front, .back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
/* front pane, placed above back */
.front {
z-index: 2;
/* for firefox 31 */
transform: rotateY(0deg);
background-color: blue;
}
/* back, initially hidden pane */
.back {
transform: rotateY(180deg);
background-color: grey;
font-size: 13em;
text-align: center;
vertical-align: middle;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cards">
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
<div class="flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
?
</div>
</div>
</div>
</div>
<button id="rotate">Rotate</button>
jsFiddle: https://jsfiddle.net/azizn/9v6340fd/
HTML:
<div class="inline-wrapper">
<div class="inline-blocks" id="f">123</div>
<div class="inline-blocks" id="s">123</div>
<div class="inline-blocks" id="t">123</div>
<div class="inline-blocks" id="fo">123</div>
</div>
CSS:
html, body {
width: 100%;
height: 100%;
/* overflow: hidden;*/
}
.inline-wrapper{
width: 400%;
height: 100%;
font-size: 0;
position: relative;
}
.inline-blocks{
display: inline-block;
width: 25%;
height: 100%;
vertical-align: top;
position: relative;
}
>.inline-blocks:nth-child(1){
background-color: #000;
}
.inline-blocks:nth-child(2){
background-color: blue;
}
.inline-blocks:nth-child(3){
background-color: red;
}
.inline-blocks:nth-child(4){
background-color: green;
}
How can I slide them without ID?
In fact this is the work of the slider. But I can not understand the logic.
Want to understand how flipping without ID.
We must check the blocks and give them сurrent class.
Auto Slide
HTML:
<div class="inline-wrapper">
<div class="inline-blocks" id="f">123</div>
<div class="inline-blocks" id="s">123</div>
<div class="inline-blocks" id="t">123</div>
<div class="inline-blocks" id="fo">123</div>
</div>
jQuery:
(function () {
var numDivs = $('.inline-wrapper').children().length; //Count children ELements
var counter = 1;
function slide(time, counter) {
var $currentDiv = $('.inline-wrapper .inline-blocks:nth-child(' + counter + ')'); //get next element
var position = $currentDiv.position(); //get position of next element
if (numDivs > 1) {
$('html,body').animate({
scrollLeft: position.left
}, time / 2); //Animate to next element
}
};
$('.inline-blocks').on('click', function () {
counter = counter + 1;
slide(2000, counter);
});
})();
DEMO
I'm having difficulty figuring out how I could calculate the extra height of a div container caused by skewing it. I am masking an image inside the container and resizing it using a plugin.
The containers will not always have the same height and width so using fixed dimensions will not work.
Please see my demo.
http://jsfiddle.net/RyU9W/6/
HTML
<div id="profiles" class="container">
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/750" alt="">
</div>
<div class="detail">
</div>
</div>
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/750" alt="">
</div>
<div class="detail">
</div>
</div>
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/750" alt="">
</div>
<div class="detail">
</div>
</div>
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/750" alt="">
</div>
<div class="detail">
</div>
</div>
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/750" alt="">
</div>
<div class="detail">
</div>
</div>
<div class="profile">
<div class="image">
<img src="http://placekitten.com/g/750/1200" alt="">
</div>
<div class="detail">
</div>
</div>
</div>
CSS
#profiles {
margin-top: 300px;
transform:skewY(-30deg);
-ms-transform:skewY(-30deg); /* IE 9 */
-webkit-transform:skewY(-30deg); /* Safari and Chrome */
}
.profile {
cursor: pointer;
float: left;
width: 32.25%;
margin: 0.5%;
position: relative;
}
.profile .image {
position: relative;
overflow: hidden;
height: 400px;
background: #000;
backface-visibility:hidden;
-webkit-backface-visibility:hidden; /* Chrome and Safari */
-moz-backface-visibility:hidden; /* Firefox */
-ms-backface-visibility:hidden; /* Internet Explorer */
}
.profile .image * {
position: relative;
transform:skew(0deg,30deg);
-ms-transform:skew(0deg,30deg); /* IE 9 */
-webkit-transform:skew(0deg,30deg); /* Safari and Chrome */
}
In skew we have a case of Right-angled triangle and the skew new width is equal to "Opposite" and we've the angle and the opposite so by this equation we can get the adjacent Opposite = Adjacent * tan(angle); Where opposite in case of skewX is the div height and in case of skewY will be the div width
Check this https://codepen.io/minaalfy/pen/exgvjb
function calculateSkew(){
var el = document.getElementById('bluebox');
var skewX = document.getElementById('skewX');
skewX.value = skewX.value || 0;
var skewY = document.getElementById('skewY');
skewY.value = skewY.value || 0;
var yRadians = skewY.value * Math.PI / 180;
var newHeight = el.offsetWidth * Math.tan(yRadians);
var calculatedHeight = el.offsetHeight + newHeight;
var xRadians = skewX.value * Math.PI / 180;
var newWidth = calculatedHeight * Math.tan(xRadians);
var calculatedWidth = el.offsetWidth + newWidth;
el.style.transform = ("skewX(" + skewX.value + "deg ) skewY(" + skewY.value + "deg )");
var output = document.getElementById('output');
output.innerHTML = "skewY by "+skewY.value+ " and new height calculated is "+calculatedHeight+ "<br> skewX by "+skewX.value+ " and the new calculated width is "+ calculatedWidth;
}
body {text-align:center}
#bluebox {width:100px;height:100px;background:blue;margin: 20px auto;}
<h4>Enter any numeric value for skewX or skewY to calculate the new width&height for the box</h4>
<div id="bluebox"></div>
<input type="number" placeholder="skewX" id="skewX" onkeyup="calculateSkew()" />
<input type="number" placeholder="skewY" id="skewY" onkeyup="calculateSkew()" />
<h1 id="output"></h1>
I got it using this solution.
var degrees = 30;
var radians= degrees*Math.PI/180;
var newHeight = parentWidth*Math.tan(radians);
var newOffset = newHeight / 2;
var parentHeight = parentHeight + newHeight;
Here is my updated fiddle with option to select degrees
http://jsfiddle.net/bhPcn/5/
Two functions that could help you.
function matrixToArray(matrix) {
return matrix.substr(7, matrix.length - 8).split(', ');
}
function getAdjustedHeight(skewedObj){
var jqElement = $(skewedObj);
var origWidth= jqElement.width();
var origHeight= jqElement.height();
var matrix = matrixToArray(jqElement.css('transform'))
var alpha = matrix[2];
var adjusted = Math.sin(alpha)*origWidth/Math.sin(Math.PI/2-alpha);
return origHeight+Math.abs(adjusted);
}
function getAdjustedWidth(skewedObj){
var jqElement = $(skewedObj);
var origWidth= jqElement.width();
var origHeight= jqElement.height();
var matrix = matrixToArray(jqElement.css('transform'))
var alpha = matrix[1];
var adjusted = Math.sin(alpha)*origHeight/Math.sin(Math.PI/2-alpha);
return origWidth+Math.abs(adjusted);
}
Usage (http://jsfiddle.net/x5her/18/):
// if you use scewY
console.log(getAdjustedWidth($(".image")[0]))
// if you use scewX
console.log(getAdjustedHeight($(".image")[0]))
Example of dynamic skew angle depending on the height.
In angular:
// We use a mathematical expression to define the degree required in skew method
// The angle depend on the height and width of the container
// We turn the answer from atan which is in radian into degrees
//
// DEGREES = RADIAN * 180 / PI
const degrees = Math.atan(
parent.nativeElement.clientWidth / parent.nativeElement.clientHeight
) * 180 / Math.PI;
parent.nativeElement.children[0].style.transform = `skew(${degrees}deg)`;
parent.nativeElement.children[1].style.transform = `skew(${degrees}deg)`;
In Jquery for the snippet :
$(document).ready(() => {
const parent = $('.duo:first');
const degrees = Math.atan(parent.width() / parent.height()) * 180 / Math.PI;
$('.first').css('transform', `skew(${degrees}deg)`);
$('.second').css('transform', `skew(${degrees}deg)`);
});
.container {
width: 10em;
height: 10em;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.one-square {
height: 100%;
width: 0;
flex-grow: 1;
display: flex;
}
.duo {
height: 100%;
width: 0;
flex-grow: 1;
display: flex;
flex-direction: row;
position: relative;
overflow: hidden;
}
.first {
width: 100%;
height: 100%;
background-color: red;
transform: skew(0deg);
transform-origin: 0 0;
position: absolute;
}
.second {
width: 100%;
height: 100%;
background-color: yellow;
transform: skew(0deg);
transform-origin: 100% 100%;
position: absolute;
}
.a {
background-color: grey;
}
.b {
background-color: green;
}
.c {
background-color: lightgrey;
}
.d {
background-color: #444444;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="one-square a"></div>
<div class="one-square b"></div>
<div class="duo">
<div class="first">
</div>
<div class="second">
</div>
</div>
<div class="one-square c"></div>
<div class="one-square d"></div>
</div>
Now that it's 2021, just use el.getBoundingClientRect().height. It takes css transform into its calculations.
Ok, I builded a slider in javascript and Jquery (with help of you guys) But now I want to have multiple sliders on 1 page. While using just one javascript. BUT...the slider can be different in width (or number of items): also the name of the slider is different because of the css width.
So How do I use 1 javascript to controle different sliders
Here is my code:
HTML
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<style type="text/css">
#temp{
height: 300px;
}
#container{
width: 500px;
height: 150px;
background:#CDFAA8;
overflow:hidden;
position:absolute;
left: 13px;
}
#slider{
width: 800px;
height: 150px;
background:#063;
position:absolute;
left: 0px;
}
#block1{
width: 100px;
height: 150px;
background:#067;
float: left;
}
#block2{
width: 100px;
height: 150px;
background:#079;
float: left;
}
#move_right{
height: 150px;
width: 20px;
background: #3f3f3f;
position: absolute;
right:0px;
z-index: 200;
opacity: 0.2;
}
#move_left{
height: 150px;
width: 20px;
background: #3f3f3f;
position: absolute;
left:0px;
z-index: 200;
opacity: 0.2;
}
</style>
</head>
<body>
<div id="temp">
<div id="container">
<div id="move_left"><button id="right">«</button></div><div id="move_right"><br><br><button id="left">»</button></div>
<div id="slider">
<div id="block1">1</div>
<div id="block2">2</div>
<div id="block1">3</div>
<div id="block2">4</div>
<div id="block1">5</div>
<div id="block2">6</div>
<div id="block1">7</div>
<div id="block2">8</div>
</div>
</div>
</div>
<div id="slider">
<div id="block1">1</div>
<div id="block2">2</div>
<div id="block1">3</div>
<div id="block2">4</div>
<div id="block1">5</div>
<div id="block2">6</div>
<div id="block1">7</div>
<div id="block2">8</div>
</div>
</div>
</div>
JavaScript
(function($) {
var slider = $('#slider'),
step = 500,
left = parseInt(slider.css('left'), 10),
max = $('#container').width() - slider.width(),
min = 0;
$("#left").click(function() {
if (left > max) {
var newLeft = left - step;
left = (newLeft>max) ? newLeft : max;
$("#slider").animate({
"left": left + 'px'
}, "slow");
}
});
$("#right").click(function() {
if (left < 0) {
var newLeft = left + step;
left = (newLeft<min) ? newLeft : min;
slider.animate({
"left": left + 'px'
}, "slow");
}
});
})(jQuery);
This should be fine:
(function($) {
$('#temp #container').each(function(){
var slider = $(this).find('#slider'),
parent = $(this),
step = 500,
left = parseInt(slider.css('left'), 10),
max = parent.width() - slider.width(),
min = 0;
parent.find("#left").click(function() {
if (left > max) {
var newLeft = left - step;
left = (newLeft>max) ? newLeft : max;
slider.animate({
"left": left + 'px'
}, "slow");
}
});
parent.find("#right").click(function() {
if (left < 0) {
var newLeft = left + step;
left = (newLeft<min) ? newLeft : min;
slider.animate({
"left": left + 'px'
}, "slow");
}
});
});
})(jQuery);
FIDDLE
In theory you could do some code which can take a selector to a wrapper element (which has the required slider elements inside) as some parameter. And then you can from this element create selectors which are more dynamic. I'm not sure where you get "step = 500" from, but that's maybe something you could grab dynamically from some relevant element.