CSS Transform Math - Calculate height of div caused by skew - javascript

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.

Related

How to move to the next/previous slides on a CSS carousel?

I'm building a carousel with CSS
.carousel {
-webkit-scroll-snap-type: x mandatory;
-ms-scroll-snap-type: x mandatory;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
overflow-x: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
width: 500px;
display: flex;
flex-direction: row;
outline: 1px #000 solid;
}
.slide {
background-color: #ccc;
width: 100%;
height: 100px;
scroll-snap-align: start;
flex-shrink: 0
}
.prev {
translatex(-500px)
}
.next {
translatex(500px)
}
<div class="carousel">
<div class="slide">1</div>
<div class="slide">2</div>
<div class="slide">3</div>
</div>
<button type="button">prev</button>
<button type="button">next</button>
It works fine in modern browsers. Is there a way to also add prev and next arrows? I assume it will trigger some JS that will move to the next slide, but how to know which one is the current slide with this approach?
This reminded me that I had some old carousel code kicking around from...2017! Wow, long time.
I had to puzzle it out for a minute. Looks like I have some resize code to make the images fit inside the container. In this case, the images are 512px wide but the container is 300px wide, so they scale.
It has a show method that can be attached to buttons. It takes two parameters: an int to say how many images to move (negative goes backwards) and a boolean that indicates if it should wrap around when it hits the end.
It manipulates the margin offset to show the each "slide". The advantage of this is the CSS transition that makes them animate.
var Slides;
(function(Slides) {
let slides_container = document.querySelector(".slides-container");
let slides = document.querySelector(".slides");
let images = slides.querySelectorAll("img");
let img_idx = 0;
for (let ix = 0; ix < images.length; ix++) {
images[ix].addEventListener("load", function() {
scaleElementToAncestor(this, slides_container);
});
}
function show(next, wrap) {
if (!slides.children[img_idx + next]) {
if (!wrap)
return;
img_idx = img_idx + next;
if (img_idx < 0)
img_idx = slides.children.length - 1;
if (img_idx > slides.children.length - 1)
img_idx = 0;
} else {
img_idx = img_idx + next;
}
let offset = 0;
for (let ix = 0; ix < img_idx; ix++) {
offset += slides.children[ix].clientWidth;
}
slides.style.marginLeft = -offset + "px";
}
Slides.show = show;
function scaleElementToAncestor(el, ancestor) {
const max_width = ancestor.clientWidth;
const max_height = ancestor.clientHeight;
const initial_width = el.clientWidth;
const initial_height = el.clientHeight;
let width = (max_height * initial_width) / initial_height;
let height = (max_width * initial_height) / initial_width;
if (width > max_width)
width = (height * initial_width) / initial_height;
if (height > max_height)
height = (width * initial_height) / initial_width;
el.style.width = width + "px";
el.style.height = height + "px";
}
})(Slides || (Slides = {}));
.slides-container {
font-size: 0;
width: 300px;
height: 150px;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
}
.slides {
display: inline-block;
-webkit-transition: margin-left 0.5s;
transition: margin-left 0.5s;
}
.slides img {
vertical-align: top;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<div class="container">
<div class="row">
<div class="slides-container">
<!-- add class -->
<div class="slides" onclick="Slides.show(1, true)">
<!-- add class -->
<!-- add click-handler, or not -->
<img src="https://dummyimage.com/512x256/000/fff">
<img src="https://dummyimage.com/512x128/f00/fff">
<img src="https://dummyimage.com/512x256/0f0/000">
<img src="https://dummyimage.com/256x256/00f/fff">
<img src="https://dummyimage.com/512x256/999/000">
</div>
</div>
<div style="margin-top: 1em; text-align: center;">
<button onclick="Slides.show(-1, false)">Previous</button>
<!-- add click-handler -->
<button onclick="Slides.show(1, true)">Next</button>
<!-- add click-handler -->
</div>
</div>
</div>

How to change size of the circles if the screen size changed?

I saw a code on the internet and i was trying to change the size of the circle according to the screen size , i tried to place the whole JS code in if statement and a function i saw in a website, it worked but it needs to refresh the page after scaling , so is it possible to change the size of circles with changing size of screen ?
I got the code from :https://codepen.io/Yago/pen/WNbxjYw
/**
* index.js
* - All our useful JS goes here, awesome!
Maruf-Al Bashir Reza
*/
function myFunction(x) {
if (x.matches) { // If media query matches
$(document).ready(function($) {
function animateElements() {
$('.progressbar').each(function() {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find('.circle').attr('data-percent');
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data('animate');
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data('animate', true);
$(this).find('.circle').circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 4,
lincCape:'round',
emptyFill:'#d4d4d4',
fill: {
color: '#1F88E9'
},
size:80
})
}
});
}
// Show animated elements
animateElements();
$(window).scroll(animateElements);
});
} else {
$(document).ready(function($) {
function animateElements() {
$('.progressbar').each(function() {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find('.circle').attr('data-percent');
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data('animate');
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data('animate', true);
$(this).find('.circle').circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 4,
lincCape:'round',
emptyFill:'#d4d4d4',
fill: {
color: '#1F88E9'
},
size:150
})
}
});
}
// Show animated elements
animateElements();
$(window).scroll(animateElements);
});
}
}
var x = window.matchMedia("(max-width: 700px)")
myFunction(x) // Call listener function at run time
x.addListener(myFunction)
/**
* index.scss
* - Add any styles you want here!
*/
body {
background: #f5f5f5;
}
.progressbar {
display: inline-block;
width: 100px;
margin: 25px;
}
.circle {
width: 100%;
margin: 0 auto;
margin-top: 10px;
display: inline-block;
position: relative;
text-align: center;
}
.circle canvas {
vertical-align: middle;
}
.circle div {
position: absolute;
top: 30px;
left: 0;
width: 100%;
text-align: center;
line-height: 40px;
font-size: 20px;
}
.circle strong i {
font-style: normal;
font-size: 0.6em;
font-weight: normal;
}
.circle span {
display: block;
color: #aaa;
margin-top: 12px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta -->
<meta charset="UTF-8" />
<title>My New Pen!</title>
<!-- Styles -->
<link rel="stylesheet" href="styles/index.processed.css">
</head>
<body>
<h1 style="margin:auto;text-align:center;color:skyblue;">Circle Progressbar When Scroll</h1>
<div style="width:100%;height:800px;">↓ Scroll down ↓</div>
<h3>Title (Placeholder)</h3>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="100">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="30.5">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="77">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="49">
<div></div>
<p>Testing</p>
</div>
</div>
<div style="width:100%;height:500px;"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://rawgit.com/kottenator/jquery-circle-progress/1.2.1/dist/circle-progress.js"></script>
<script src="scripts/index.js"></script>
</body>
</html>
I will not concentrate on quality, #mplungjan did a better job with quality but your issue is that you have to add resize event listener and also invalidate the animate true when your animation is done so that the condition can run again to resize the circles, you will notice that this will re-animate whenever you resize the page.
/**
* index.js
* - All our useful JS goes here, awesome!
Maruf-Al Bashir Reza
*/
function myFunction(x) {
let size = 150;
if (x.matches) {
// If media query matches
size = 80;
}
function animateElements() {
$(".progressbar").each(function () {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find(".circle").attr("data-percent");
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data("animate");
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data("animate", true);
$(this)
.find(".circle")
.circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 4,
lincCape: "round",
emptyFill: "#d4d4d4",
fill: {
color: "#1F88E9",
},
size: size,
});
$(this).data("animate", false);
}
});
}
// Show animated elements
animateElements();
$(window).scroll(animateElements);
}
var x = window.matchMedia("(max-width: 700px)");
myFunction(x);
$(window).on("resize", function (e) {
var x = window.matchMedia("(max-width: 700px)");
myFunction(x); // Call listener function at run time
});
/**
* index.scss
* - Add any styles you want here!
*/
body {
background: #f5f5f5;
}
.progressbar {
display: inline-block;
width: 100px;
margin: 25px;
}
.circle {
width: 100%;
margin: 0 auto;
margin-top: 10px;
display: inline-block;
position: relative;
text-align: center;
}
.circle canvas {
vertical-align: middle;
}
.circle div {
position: absolute;
top: 30px;
left: 0;
width: 100%;
text-align: center;
line-height: 40px;
font-size: 20px;
}
.circle strong i {
font-style: normal;
font-size: 0.6em;
font-weight: normal;
}
.circle span {
display: block;
color: #aaa;
margin-top: 12px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta -->
<meta charset="UTF-8" />
<title>My New Pen!</title>
<!-- Styles -->
<link rel="stylesheet" href="styles/index.processed.css">
</head>
<body>
<h1 style="margin:auto;text-align:center;color:skyblue;">Circle Progressbar When Scroll</h1>
<div style="width:100%;height:800px;">↓ Scroll down ↓</div>
<h3>Title (Placeholder)</h3>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="100">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="30.5">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="77">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="49">
<div></div>
<p>Testing</p>
</div>
</div>
<div style="width:100%;height:500px;"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://rawgit.com/kottenator/jquery-circle-progress/1.2.1/dist/circle-progress.js"></script>
<script src="scripts/index.js"></script>
</body>
</html>
Vary the size:
Working code:
function animateElements() {
$('.progressbar').each(function() {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find('.circle').attr('data-percent');
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data('animate');
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data('animate', true);
$(this).find('.circle').circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 4,
lincCape: 'round',
emptyFill: '#d4d4d4',
fill: {
color: '#1F88E9'
},
size: $(this).width() / 2
})
$(this).data("animate", false); // added this!
}
})
}
$(function() {
// Show animated elements
$(window).on("resize scroll", animateElements);
});
<h1 style="margin:auto;text-align:center;color:skyblue;">Circle Progressbar When Scroll</h1>
<div style="width:100%;height:800px;">↓ Scroll down ↓</div>
<h3>Title (Placeholder)</h3>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="100">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="30.5">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="77">
<div></div>
<p>Testing</p>
</div>
</div>
<div class="progressbar" data-animate="false">
<div class="circle" data-percent="49">
<div></div>
<p>Testing</p>
</div>
</div>
<div style="width:100%;height:500px;"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://rawgit.com/kottenator/jquery-circle-progress/1.2.1/dist/circle-progress.js"></script>
<script src="scripts/index.js"></script>
You can add an eventListener on "resize":
document.addEventListener("resize", handleResize);
And then change the size in handleResize. I'm not sure why you don't use CSS media queries instead of javascript though.
add this to your css
#media only screen and (max-width: 600px) {
.circle {
width: 50%;
}
}

animate opacity in and out on scroll

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>

Parallax based on mousemove has different offset

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'});
})
});

Why does sometimes some of cards doesn't rotate at all?

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/

Categories

Resources