How to set an exact background position based on element's position? - javascript

What I am trying to achieve: using the same image, set an elements background-position with jQuery, so they overlaps closest parents background-image. I somehow figured, that $element.property().left needs to be multiplied by something close to 2 (still don't really understand why it's so), but I cannot see any math pattern in it.
If anybody could tell me what exactly comes into an equation, it'd be great help. I imagine there is padding and margin of an element and all the elements up the DOM tree involved, but after lot of combinations I still cannot get there.
It might seem that the best way to get desired effect is just to set background: transparent;, but it is not the case; I need it for further usage of filter CSS property on the element's background image.
There are inline styles in HTML added for testing; also, I created jsfiddle.
$.fn.filteredImg= function() {
var $this = $(this)
$this.each(function(index, card) {
var $card = $(card);
var img = $card.data("img");
var $parent = $card.parentsUntil("[data-img='" + img + "']").last().parent();
var $effect = $card.children(".filtered-effect");
var pos = $card.position();
$parent.css({
backgroundImage: "url(" + img + ")",
backgroundRepeat: "no-repeat"
});
$effect.css({
backgroundImage: "url(" + img + ")",
backgroundPosition: -2 * Math.ceil(pos.left) + "px " + -Math.round(pos.top) + "px"
});
})
}
$(".card-filtered-img").filteredImg();
.card-filtered-img {
width: 80%;
min-height: 500px;
margin-left: 77px;
margin-top: 17px;
position: relative;
}
.card-filtered-img > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-filtered-img .filtered-effect {
z-index: 99;
}
.card-filtered-img .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="container" style="margin-top:30px">
<div class="row" style="padding:30px">
<div class="col">
<div class="card-filtered-img" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
<div class="card-filtered-img" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
</div>

Here is the solution base on offset instead of position (and I simplified the code):
$.fn.filteredImg= function() {
var $this = $(this);
$this.each(function(index, card) {
var $card = $(card);
var $effect = $card.children(".filtered-effect");
var $parent = $(card).parents(".parent").first();
var img = $parent.data("img");
var cardPos = $card.offset();
$parent.css({
backgroundImage: "url(" + img + ")",
backgroundRepeat: "no-repeat"
});
$effect.css({
backgroundImage: "url(" + img + ")",
backgroundPosition: -cardPos.left + "px " + -cardPos.top + "px"
});
})
}
$(".card-filtered-img").filteredImg();
.card-filtered-img {
width: 80%;
min-height: 500px;
margin-left: 77px;
margin-top: 17px;
position: relative;
}
.card-filtered-img > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-filtered-img .filtered-effect {
z-index: 99;
}
.card-filtered-img .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="card-filtered-img">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card-filtered-img">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
</div>

Since/If you use the full viewport, you can use viewport units to position and size the inner card's and drop the script all together.
This also scales when you resize and will give you a performance boost since you don't need a script to watch for resize and redraw.
Note, for this demo I ran this without bootstrap, as I didn't want to add compensations for its media query's etc.
Updated fiddle
html, body {
margin: 0;
overflow-x: hidden;
}
.outer {
height: 1080px;
width: 100vw;
}
.card-acrylic {
top: 20px;
width: 80vw;
margin-left: 10vw;
min-height: 500px;
position: relative;
background-position: left -10vw top -20px;
}
.card-acrylic + .card-acrylic {
top: 40px;
background-position: left -10vw top -540px;
}
.card-acrylic > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-acrylic .acrylic-effect {
z-index: 99;
}
.card-acrylic .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<div class="outer" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="card-acrylic" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="acrylic-effect"></div>
<div class="card-content"></div>
</div>
<div class="card-acrylic" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="acrylic-effect"></div>
<div class="card-content"></div>
</div>
</div>

Related

Move background on mouse position

I am currently building a script where the background image moves depending on the location of the mouse. I basically got this effect to work but the problem is that as soon if another div is overlaying it is not working anymore.
In the example (scroll down in snippet) you can see the difference between the two. Maybe somebody knows a solution for this where the background is still triggered on the mouse position but isn't affected because a div is overlaying?
I can add pointer-events:none to the overlaying div which works but looking for a better solution.
$(document).ready(function() {
var movementStrength = 50;
var height = movementStrength / $(window).height();
var width = movementStrength / $(window).width();
$(".hover-image").mousemove(function(e) {
var pageX = e.pageX - ($(window).width() / 2);
var pageY = e.pageY - ($(window).height() / 2);
var newvalueX = width * pageX * -1 - 25;
var newvalueY = height * pageY * -1 - 50;
$('.hover-image').css("background-position", newvalueX + "px " + newvalueY + "px");
});
});
* {
margin: 0;
padding: 0;
}
.spacer {
position: relative;
width: 100%;
height: 50vh;
background: black;
}
.bg {
position: relative;
width: 100%;
min-height: 100vh;
}
.hover-image {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background: url('https://source.unsplash.com/random') -25px -50px;
background-size: calc(100% + 50px);
z-index: 0;
}
.container {
position: relative;
}
.col-md-12 {
padding: 300px 0;
}
.col-md-12 span {
padding: 10px;
background: black;
color: white;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="spacer"></section>
<section class="bg">
<div class="hover-image"></div>
</section>
<section class="spacer"></section>
<section class="bg">
<div class="hover-image"></div>
<div class="container">
<div class="">
<div class="col-md-12 text-center">
<span>
BACKGROUND NOT WORKING ANYMORE
</span>
</div>
</div>
</div>
</section>
<section class="spacer"></section>

How to make a section sticky for several seconds and then sticky for all time

In the website - right panel has three ads, what I want - there should be 3 ads top two ads should be fixed for a few seconds and then third ad should be sticky for a long time.
I am using this code, in which third ad i.e. second section of the ad is sticky when scroll reaches to its position,
<div class="right-panel">
<div id="adsection1">
<!--ad1-->
<br/>
<!--ad2-->
</div>
<div id="adsection2" style="width: 300px; height: 600px;">
<div id="abc_ad1">
<!--ad3-->
</div>
</div>
<script>
if (window.innerWidth > 1024) {
var adElem = document.getElementById('adsection2');
window.onscroll = function () {
var rect = adElem.getBoundingClientRect();
adElem.style.width = rect.width + 'px';
adElem.style.height = rect.height + 'px';
document.getElementById('abc_ad1').style.width = rect.width + 'px';
document.getElementById('abc_ad1').style.height = rect.height + 'px';
if (rect.top <= 0) {
document.getElementById('abc_ad1').style.position = "fixed";
document.getElementById('abc_ad1').style.top = "0";
document.getElementById('abc_ad1').style.zIndex = "2147483647";
} else {
document.getElementById('abc_ad1').style.position = "";
document.getElementById('abc_ad1').style.top = "";
document.getElementById('abc_ad1').style.zIndex = "";
}
};
}
</script>
</div>
Consider the right section on this link (I want to design just like it), https://www.tutorialspoint.com/python_blockchain/python_blockchain_client_class.htm
You don't really need JavaScript in order to achieve described effect.
The trick is to properly format your HTML layout - it also means to divide it in appropriate parts, so that you have a right parent for a sticky element.
Side note: I use divs for the sake of simplicity of an example, but in the real life app you should opt for semantic HTML.
body, html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#content {
height:200%;
width: 100%;
}
.col {
height: 100%;
width:50%;
float: left;
}
#main {
background: linear-gradient(#58668b, #ffffff);
}
#ads {
position: sticky;
top: 0px;
background-color:#bdeaee;
}
#header {
height:30px;
background-color: #29a8ab;
}
#footer {
height:100px;
background-color: #651e3e;
color: #ffffff;
}
.top-section {
height: 25%;
}
.top-section div {
height: 45%;
background-color:#ffcc5c;
}
.top-section div:not(:last-child) {
margin-bottom:10%;
}
.bottom-section {
height: 30%;
background-color: #ff6f69;
margin-top: 12%;
}
.sticky-content {
width: 100%;
height: 60%;
position: sticky;
top: 0px;
}
<div id="header">Header</div>
<div id="content">
<div id="main" class="col"><p>Main Content</p></div>
<div id="ads" class="col">
<div class="sticky-content">
<div class="top-section">
<div></div>
<div></div>
</div>
<div class="bottom-section"></div>
</div>
</div>
</div>
<div id="footer">Footer</div>

How to make a background change its position based on the position on the cursor

I am wanting to make a website that uses a background that moves based on the position that the curser is on the website. I have found this website that gives a visual representation of what I want to do. http://www.alexandrerochet.com/I just need to know how to make the letters move. I will replace them with images later.
You can achieve that using css properties.
Based on Lea Verou's talk
const root = document.documentElement;
document.addEventListener("mousemove", evt => {
let x = evt.clientX / innerWidth;
let y = evt.clientY / innerHeight;
root.style.setProperty("--mouse-x", x);
root.style.setProperty("--mouse-y", y);
});
html {
height: 100%
}
:root {
--mouse-x: .5;
--mouse-y: .5;
}
body {
height: 100%;
background-image: radial-gradient( at calc(var(--mouse-x) * 100%) calc(var(--mouse-y) * 100%), transparent, black);
}
You may want to try using parallax.js to achieve the desired effect.
Demo site.
Quick jsfiddle.
var scene = document.getElementById('scene');
var parallaxInstance = new Parallax(scene);
parallaxInstance.friction(0.2, 0.2);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #F9F871;
width: 100vw;
height: 100vh;
}
.scene {
top: 30%;
}
.layer {
width: 100%;
height: 200px;
}
.item {
width: 50px;
height: 50px;
border-radius: 200px;
background-color: red;
position: relative;
}
.item-1 {
background-color: #FF9671;
left: 30%;
}
.item-2 {
background-color: #D65DB1;
left: 60%;
}
.item-3 {
background-color: #FF6F91;
left: 40%;
}
.item-4 {
background-color: #FFC75F;
left: 70%;
}
<div class="container">
<div id="scene" class="scene">
<div data-depth="0.2" class="layer layer-1">
<div class="item item-1"></div>
<div class="item item-2"></div>
</div>
<div data-depth="0.6" class="layer layer-2">
<div class="item item-3"></div>
<div class="item item-4"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/parallax/3.1.0/parallax.min.js"></script>

jquery change active class fixed div

I'm new to using JQuery and Javascript. I can't figure out what is wrong here.
I want to h1 element to be displayed as block and to add the class as active as is parent div is showing in the window.
I'm hoping the consequent effect will be somewhat like the 'Y logo' on this site http://www.collectif-yay.com/en
HTML
<div class= "section" id="Title">
<h1 style="position: fixed; top: 10px; display: none">Title</h1>
</div>
<div id="Publications">
<h1 style="position: fixed; top: 10px; display: none">Publications</h1>
</div>
<div class= "section" id="Articles">
<h1 style="position: fixed; top: 10px; display: none">Articles</h1>
</div>
<div class= "section" id="Contributors">
<h1 style="position: fixed; top: 10px; display: none">Contributors</h1>
</div>
<div class= "section" id="Process">
<h1 style="position: fixed; top: 10px; display: none">Process</h1>
</div>
CSS
div{
height: 400px;
display: block;
width: 100%;
padding: 10px;
border: 0;
overflow: hidden;
}
h1 {
top: 10px;
padding-left: 20px;
width: 100%;
color: #0000aa;
}
.section {
padding-top: 100px;
padding-bottom: 0px;
}
.active {
color: #0000aa;
JQuery
$(document).ready(function () {
setup_section_titles();
display_section_titles();
});
$(window).scroll(function () {
display_section_titles();
});
function setup_section_titles() {
$("h1").css("position", "fixed").css("top", "10px");
}
// ----------------------------------------
function display_section_titles() {
var sectionArray = $.makeArray($(".section"));
var window_scroll_top = $(window).scrollTop();
var window_center = $(window).height()/2;
window_center = 100;
// sort sections by their relative distance to the center of the window
sectionArray.sort( function(a, b) {
return getDiff(a, window_scroll_top, window_center) > getDiff(b, window_scroll_top, window_center) ? 1 : -1;
});
$(".section h1:visible").hide();
$(sectionArray[0]).children("h1").show();
$(".active").removeClass("active");
$(sectionArray[0]).addClass("active");
}
// ----------------------------------------
function getDiff(item, window_scroll_top, window_center) {
var item_viewportoffset_top = $(item).offset().top - window_scroll_top;
var dist_of_top = Math.abs(item_viewportoffset_top - window_center);
var dist_of_bottom = Math.abs(item_viewportoffset_top + $(item).height() - window_center);
// return minimum of distances of top and bottom of an element
// to center of the window
return Math.min( dist_of_top, dist_of_bottom );
}

Fixing the right button of a vanilla Javascript carousel

Against all reason, I'm trying to create a vanilla JavaScript carousel.
I am having two problems:
1. The images move left at widths of -680px as they should but when I tried to create the same function for the right button, the left value goes to 1370px making the picture off the screen.
2. I would like for it to slide left rather jump left (same for right), I managed to get it to do this but it doesn't work on the first slide, only from the second slide.
Here is the HTML code just for the carousel:
<div id = "container">
<div id = "carousel">
<div class = "slide"><img class = "slideImage" class = "active" src = "sithCover.png"></div>
<div class = "slide"><img class = "slideImage" src = "darthVader.png"></div>
<div class = "slide"><img class = "slideImage" src = "darthSidious.png"></div>
<div class = "slide"><img class = "slideImage" src = "kyloRen.png"></div>
</div>
</div>
<div id = "left" class = "button"></div>
<div id = "right" class = "button"></div>
Here is the CSS code:
#container {
position: absolute;
top: 200px;
left: 100px;
width: 680px;
height: 360px;
white-space: nowrap;
overflow:hidden;
}
#carousel {
position: absolute;
width: 2740px;
height: 360px;
white-space: nowrap;
overflow: hidden;
transition: left 300ms linear;
}
.slide {
display: inline-block;
height: 360px;
width: 680px;
padding: 0;
margin: 0;
transition: left 300ms linear;
}
.slideImage {
position:relative;
height: 360px;
width: 680px;
float: left;
}
.button {
position: absolute;
top: 340px;
height: 60px;
width: 60px;
border-bottom: 12px solid red;
}
#left {
left: 115px;
border-left: 12px solid red;
transform: rotate(45deg);
}
#right {
left: 693px;
border-right: 12px solid red;
transform: rotate(-45deg);
}
Here is the JavaScript:
var carousel = document.querySelector('#carousel');
var firstVal = 0;
document.querySelector('#left').addEventListener("click", moveLeft);
function moveLeft (){
firstVal +=685;
carousel.style.left = "-"+firstVal+"px";
};
document.querySelector('#right').addEventListener("click", moveRight);
function moveRight() {
firstVal +=685;
carousel.style.left = "+"+firstVal+"px";
};
Here is a JSFiddle so that you can see what I mean:
"https://jsfiddle.net/way81/8to1kkyj/"
I appreciate your time in reading my question and any help would be much appreciated.
Ofcourse it goes from -685px on left click and then to +1370pxthe next right click; You are always adding 685 to your firstVal variable.
firstVal = 0
//firstVal is worth 0
moveLeft()
//firstVal is now worth 685
moveRight()
//firstVal is now worth 1370.
The problem is that when you apply the firstVal to your CSS thing in the javascript, you create a string to get your negative value (where you apply the "-" sign infront of firstVal)
Instead, write them like this
function moveLeft (){
firstVal -=685; //note we now subtract, the "-" should appear when the number becomes negative
carousel.style.left = firstVal + "px";
};
function moveRight() {
firstVal +=685;
carousel.style.left = firstVal + "px";
};
var left = document.getElementById("left");
left.addEventListener("click", moveLeft, false);
var right = document.getElementById("right");
right.addEventListener("click", moveRight, false);
var carousel = document.getElementById("carousel");
var images = document.getElementsByTagName("img");
var position = 0;
var interval = 685;
var minPos = ("-" + interval) * images.length;
var maxPos = interval * images.length;
//slide image to the left side <--
function moveRight() {
if (position > (minPos + interval)) {
position -= interval;
carousel.style.left = position + "px";
}
if (position === (minPos + interval)) {
right.style.display = "none";
}
left.style.display = "block";
}
//slide image to the right side -->
function moveLeft() {
if (position < (maxPos - interval) && position < 0) {
position += interval;
carousel.style.left = position + "px";
}
if (position === 0) {
left.style.display = "none";
}
right.style.display = "block";
}
#container {
position: absolute;
top: 200px;
left: 100px;
width: 680px;
height: 360px;
white-space: nowrap;
overflow: hidden;
}
#carousel {
position: absolute;
width: 2740px;
height: 360px;
white-space: nowrap;
overflow: hidden;
transition: left 300ms linear;
}
.slide {
display: inline-block;
height: 360px;
width: 680px;
padding: 0;
margin: 0;
transition: left 300ms linear;
}
.slideImage {
position: relative;
height: 360px;
width: 680px;
float: left;
}
.button {
position: absolute;
top: 340px;
height: 60px;
width: 60px;
border-bottom: 12px solid red;
}
#left {
left: 115px;
border-left: 12px solid red;
transform: rotate(45deg);
display: none;
}
#right {
left: 693px;
border-right: 12px solid red;
transform: rotate(-45deg);
}
<div id="container">
<div id="carousel">
<div class="slide">
<img class="slideImage" class="active" src="sithCover.png" alt="slide1">
</div>
<div class="slide">
<img class="slideImage" src="darthVader.png" alt="slide2">
</div>
<div class="slide">
<img class="slideImage" src="darthSidious.png" alt="slide3">
</div>
<div class="slide">
<img class="slideImage" src="kyloRen.png" alt="slide4">
</div>
</div>
</div>
<div id="left" class="button"></div>
<div id="right" class="button"></div>

Categories