Improve background animation color change - javascript

I want to make an background color animation change when the user gets to the specific section.
Here is the jQuery code I wrote:
var initialColors = [];
$('section.changecolorbg').each(function(i){
initialColors[i] = $(this).css("backgroundColor");
});
$(window).scroll(function() {
$('section.changecolorbg').each(function(i){
if(isScrolledIntoView($(this))){
var bgc = initialColors[i];
$(this).parent().children('.changecolorbg').each(function(){
$(this).css("backgroundColor", bgc);
});
}
})
});
function isScrolledIntoView(elem)
{
var hT = elem.offset().top,
hH = elem.outerHeight(),
wH = $(window).height(),
wS = $(this).scrollTop() + 200;
return (wS > (hT+hH-wH))
}
The sections will have a background-color initially, this is why I saved them in a variable.
The problem with this is that it's working pretty slow. I think is that because all the checking needs to be done in the .scroll function.
Is there a way I can improve the code?
P.S. The effect I'm trying to achieve is same as on http://sfcd.com/

You can try something like this using hsl colors in CSS (hue, saturation, lightness) and deriving the hue value from the window.scrollY position:
var body = document.getElementsByTagName('body')[0];
function changeHue() {
var hue = (window.scrollY / 20);
body.style.backgroundColor = 'hsl('+hue+', 100%, 50%)';
}
window.addEventListener('scroll', changeHue, false);
body {
background-color: hsl(0,100%,50%);
}
div {
height: 10000px;
}
<div></div>

Related

Incremental CSS Media Queries

Consider a stylesheet that resizes the page as the height diminishes using media queries and transform:
#media (max-height: 620px) {
body {
transform: scale(0.95);
}
}
#media (max-height: 590px) {
body {
transform: scale(0.90);
}
}
#media (max-height: 560px) {
body {
transform: scale(0.85);
}
}
// and so on ...
The page "zooms out" as the window height diminishes, allowing the full content to be displayed on smaller screens.
If I want to support screens smaller than 560px height, I need to add more media queries.
Notice that for each 30px lost in height, we call scale with 0.05 less in the input.
Question: Is it there a way to define incremental media queries using only css?
Follow Up: If a pure css solution is not available, what would be the simplest way of accomplishing such effect in vanilla JS?
Edit: Thank you all for posting different solutions to this problem. I appreciate your help. Your answers helped me learn how to improve my code.
This is not possible using CSS alone. You can do this using JS by adding a window.onresize function to watch for resizing and scaling the body of the document. This solution also scales dynamically so you do not need to worry about breakpoints or #media queries.
function updateScale() {
let viewScale = window.innerHeight / document.documentElement.scrollHeight;
document.body.style = 'transform:scale(' + viewScale + ')';
document.documentElement.scrollHeight = window.innerHeight;
}
window.onresize = function() {
updateScale();
}
updateScale();
body {
transform-origin: 0 0;
margin: 0;
padding: 0;
overflow: hidden;
}
#block {
background-color: black;
width: 300px;
height: 4000px;
}
<div id='block'></div>
#NathanFries is correct, this isn't something that is possible with native CSS.
CSS includes viewport units for percentage-based values for your width and height, but you can't pass that onto the scale() function.
You'd then need to tie this to some resize event listener.
Here is a quick example that might accomplish what you're looking to do:
// #see https://github.com/WICG/EventListenerOptions/blob/9dcca95/explainer.md#feature-detection
// #example `elem.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false);`
var checkSupportPassiveEvents = function() {
var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
},
});
window.addEventListener('testPassive', null, opts);
window.removeEventListener('testPassive', null, opts);
} catch (e) {}
return supportsPassive;
};
var supportsPassive = checkSupportPassiveEvents();
var mapRange = function(fn, inStart, inEnd, outStart, outEnd) {
if (outStart === void 0) {
outStart = inStart;
outEnd = inEnd;
inStart = 0;
inEnd = 1;
}
var inRange = inEnd - inStart,
outRange = outEnd - outStart;
return function(val) {
var original = fn((val - inStart) / inRange);
return outStart + outRange * original;
};
};
var linear = function(x) {
return x;
};
var minHeight = 320;
var maxHeight = 620;
var minScale = 0.45;
var maxScale = 1;
var screenHeightToScaleFactorInner = mapRange(linear, minHeight, maxHeight, minScale, maxScale);
var screenHeightToScaleFactor = function(height) {
if (height <= minHeight) {
return minScale;
} else if (height > maxHeight) {
return maxScale;
} else {
return screenHeightToScaleFactorInner(height);
}
};
window.addEventListener(
'resize',
function(e) {
var height = this.innerHeight;
this.document.body.style.transform = 'scale(' + screenHeightToScaleFactor(height) + ')';
},
supportsPassive ? { passive: true } : false
);
You may have to use vanilla JavaScript in this case.
So, each 30px is 0.05, or each 6px is 0.01 from 650px down.
It means an amount of 600px is 1 in scale and that each pixel is 0.01/6.
With all that information in mind, we can use resize event to calculate this:
window.addEventListener('resize', changeTransform); // when resize, call changeTransform
var bodyEl = document.querySelector('body');
function changeTransform() {
var scale = 1; // default scale
if (window.innerHeight < 650) { // if window height < 650px, do magic
scale = -0.83 + (0.05/30)*window.innerHeight;
}
bodyEl.style.transform = "scale(" + scale + ")"; // apply scale (1 or the calculated one)
}
Hope it can help you somehow.
For a CSS solution you can consider vh and vw unit but it won't be possible with scale since this one need a unitless value.
A different approach would be to use translateZ() and some perspective to simulate a scale animation.
Here is a basic example. The result isn't accurate as I simply want to demonstrate the trick. Run the snippet full page and adjust the window height and you will see the element scaling.
.box {
width:100px;
height:100px;
background:red;
transform:perspective(180px) translateZ(15vh);
transform-origin:top left;
}
<div class="box">
some text here
</div>
You simply need to find the correct calculation for the different values.

Jquery transition Opacity based on var value

I am trying to animate an opacity value from 0 to 1, based on the scroll position within the viewport height. The code below sets variables for windowHeight and scrollTop, which can be combined to calculate percentageScrolled (0–100) of the viewport height. Based on this I am able to switch CSS values at set points, but instead I want to gradually change the opacity from 0–100 of percentageScrolled.
How can I adjust the code below to transition/animate the opacity?
Thanks.
$(window).on('scroll', function(){
// Vars
var windowHeight = $(window).height();
var scrollTop = $(this).scrollTop();
var percentageScrolled = (scrollTop*100)/windowHeight;
if( percentageScrolled < 100 ) {
$('.colour-overlay').css('opacity', '1');
} else {
$('.colour-overlay').css('opacity', '0');
}
});
You can remove the if and set the opacity to the percentage divided by 100
$(window).on('scroll', function() {
// Vars
var windowHeight = $(window).height();
var scrollTop = $(this).scrollTop();
$('.colour-overlay').css('opacity', scrollTop / windowHeight);
});
.colour-overlay {
display: block;
width: 20px;
height: 1200px;
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="colour-overlay"></div>
$(‘.colour-overlay’).css(opacity, percentageScrolled / 100);
Instead of if else statement.
Also as a general advice try to avoid using var, use const or let instead and if your project doesnt depend on jquery try to avoid it too.
const overlays = document.querySelectorAll(‘.colour-overlay’);
window.addEventListener('scroll', () => {
const windowHeight = window.offsetHeight;
const scrollTop = window.scrollTop;
const percentageScrolled = (scrollTop * 100) / windowHeight;
for (const overlay of overlays) {
overlay.style.opacity = percentageScrolled / 100;
}
});
This would be the pure js solution.
Dont know if i understood you right, but a wrote an example have a look.
$(document).on('scroll', function(){
// Vars
// use body instead of window, body will return the right height where window will return the view size
var windowHeight = $("body").height();
var scrollTop = $(this).scrollTop();
var percentageScrolled = Math.abs((((scrollTop / windowHeight) * 100) / 100 ));
$('.colour-overlay').css('opacity', percentageScrolled);
});
.colour-overlay{
background:red;
height:1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="colour-overlay"></div>

Parallax stop background image pos change if scroll exceeds bg image size

I have multiple sections showing different backgrounds, each section has a basic parallax background image. As the backgrounds vary in height, I cannot seem to work out how to stop the background image position once the image bottom is reached.
Background position change begins if the section offset().top is equal to or greater than $(window).scrollTop().
It would seem that the btmOffset is incorrect but I can't see why.
Any help greatly appreciated.
Live example
http://demo.dwweb.co.uk
What I have so far
$window = $(window);
var winWid = $window.width();
$('.portfolioSection').each(function(){
var $bgobj = $(this);
var speed = 2.4;
var bg = $(this).css('background-image').replace('url("','').replace('")','');
var tmpImg = new Image();
tmpImg.src = bg;
var orgW = tmpImg.width;
var orgH = tmpImg.height;
var imgResizedRatio = winWid/orgW;
var resizedH = orgH * imgResizedRatio;
var btmOffset = (resizedH - $(this).height()) + $bgobj.offset().top;
$(window).scroll(function() {
if($(window).scrollTop() > $bgobj.offset().top && $(window).scrollTop() < btmOffset){
var yPos = -(($window.scrollTop()-$bgobj.offset().top) / speed);
var coords = '0 '+ yPos + 'px';
$bgobj.css({ backgroundPosition: coords });
} else if($(window).scrollTop() < $bgobj.offset().top) {
$bgobj.css({ backgroundPosition: '0 0' });
} else {
$bgobj.css({ backgroundPosition: '0 '+resizedH+'px' });
}
});
});
orgH and orgW will be 0 on execution, since you are creating a new Image asynchronously, while executing your code synchronously:
var tmpImg = new Image();
tmpImg.src = bg;
//...
This means, you would have to use the onload event (and maybe cover the onerror event too), like this:
tmpImg.onload = function(ev) {
var orgW = tmpImg.width;
var orgH = tmpImg.height;
//and the rest of your code...
}
This is very inefficient, since you are loading all these (big) images again.
I would add data-attributes to each .portfolioSection, like data-bgmaxscroll="1000" (which is the height of the image).
This would be a bit more hardcoded, but i think it's the easiest and the most performant way.

How can I create a click and drag to change the width of an object with jQuery?

I have an object that I want to change the width of when you click on it and drag right or left. Adding to the width or taking away from it as you move the mouse (or finger).
<style>
#changeMe {width:300px; height: 200px;}
</style>
<div id="changeMe">
Some Content
</div>
<script>
$('#changeMe').mousedown(function(){
//Some Code?????
});
</script>
What you want to do is track the x co-ords of the mouse. If greater than they were before, increase size, if lower, decrease the size.
Not tested but the below should be inspiration.
var oldXPos = 0;
var isDragging = false;
$(document).mousemove(function(event) {
if (isDragging)
{
var difference = event.pageX - oldXPos;
// Do something with this value, will be an int related to how much it's moved
// ie $('#changeMe').css.width += difference;
}
oldXPos = event.pageX;
});
$('#changeMe').mousedown(function() {
isDragging = true;
})
$('#changeMe').mouseup(function() {
isDragging = false;
})
You just need a resizable({}) effect .
$('#changeMe').resizable({});
You can look at this article
Resizable
$(function() {
$('.testSubject').resizable();
});
or
#changeMe {width:300px; height: 200px; border: 1px solid black;}
<body>
<div id="changeMe">
Some Content
</div>
</body>
$('#changeMe').resizable({});
Or
$(function(){
$('img[src*=small]').toggle(
function() {
$(this).attr('src',
$(this).attr('src').replace(/small/,'medium'));
},
function() {
$(this).attr('src',
$(this).attr('src').replace(/medium/,'large'));
},
function() {
$(this).attr('src',
$(this).attr('src').replace(/large/,'small'));
}
);
});
If I understand your question correctly, that you want to be able to dynamically increase/decrease the size of the object as it moves along the x-axis, I recommend that you use $('#changeMe').offset() inside the jQuery UI drag event.
You can create a formula that you want to use based on an initial offset, and the new offset to size your container by $('#changeMe').css({ width: X, height: Y });, and insert whatever your X and Y values are in pixels.
Edited for further elaboration with code:
var initX = 0;
var initW = 0;
$('#changeMe').draggable({
start: function() {
initX = $(this).offset().left;
initW = $(this).width();
},
drag: function() {
var deltaX = initX - $(this).offset().left;
$(this).css({ width: initW + deltaX });
}
});
If you used that as your base, it's a very nice and simple solution for your application.

jQuery resize of images [duplicate]

This question already has answers here:
Image resize of items jQuery
(2 answers)
Closed 10 years ago.
I have managed to fit automatically the images of the gallery per row depending if it´s horizontal (one image per row) or vertical (two images per row).
The problem now is that I want the images to be scalable (resize on window resize) but I have no idea how to achieve it. How it should me made? (I'm looking for a javascript/jquery solution to avoid height: auto problems...)
This is the web: http://ldlocal.web44.net/test2/gallery.html
Can be downloaded here: http://ldlocal.web44.net/test2/test.zip
this is my code:
var gallery = new Gallery($('#gallery_images_inner'));
function Gallery(selector){
this.add_module = function(type, image){
var container = $('<div />' , {
'class' : 'gallery_container'
}).append(image);
if(type == 'horizontal'){
var h_ar = image.attr('height') / image.attr('width');
container.css({
'width' : selector.width(),
'height' : selector.width()*h_ar
})
}
if(type == 'vertical'){
container.css({
'width' : v_width,
'height' : v_height
})
}
container.appendTo(selector);
container.children('img').fitToBox();
}
var _this = this;
var gutter = 0;
// start vars for counting on vertical images
var v_counter = 0;
var w_pxls = 0;
var h_pxls = 0;
// iterates through images looking for verticals
selector.children('img').each(function(){
if($(this).attr('width') < $(this).attr('height')){
v_counter++;
h_pxls += $(this).attr('height');
w_pxls += $(this).attr('width');
}
})
// calculates average ar for vertical images (anything outside from aspect ratio will be croped)
var h_avrg = Math.floor(h_pxls/v_counter);
var w_avrg = Math.floor(w_pxls/v_counter);
var v_ar = h_avrg/w_avrg;
var v_width = (selector.width())/2;
var v_height = v_width*v_ar;
selector.children('img').each(function(){
if(parseInt($(this).attr('width')) > parseInt($(this).attr('height'))){
_this.add_module('horizontal', $(this));
}else{
_this.add_module('vertical', $(this));
}
})
selector.isotope({
masonry: {
columnWidth: selector.width() / 2
}
});
}
Update ALL NEW CODE:
http://jsfiddle.net/vYGGN/
HTML:
<div id="content">
<img class="fluidimage" src="http://thedoghousediaries.com/comics/uncategorized/2011-04-06-1b32832.png"
/>
</div>
CSS:
body {
text-align:center;
}
img {
float: right;
margin: 0px 10px 10px 10px;
}
#content {
width:70%;
margin: 0px auto;
text-align: left;
}
JS:
$(document).ready(function () {
function imageresize() {
var contentwidth = $('#content').width();
if ((contentwidth) < '300') {
$('.fluidimage').attr('height', '300px');
} else {
$('.fluidimage').attr('height', '600px');
}
}
imageresize(); //Triggers when document first loads
$(window).bind("resize", function () { //Adjusts image when browser resized
imageresize();
});
});
Found this at this article:
http://buildinternet.com/2009/07/quick-tip-resizing-images-based-on-browser-window-size/
If you want to resize images automatically and scale them down proportionally, all you have to do is set a css max-width on the <img> tag. You can scale it down automatically with a percentage value according to the $(window) or any element in the document. Here's an example of how to scale it proportionally using the $(window) to a percentage of the window:
$(document).ready(function() {
$(window).resize(function() {
var xWidth = $(window).width();
$('.[img class]').each(function() {
$(this).css({maxWidth: xWidth * ([your percentage value of window] / 100)});
});
}).trigger('resize');
});
Change [img class] to the class of the images.
Change [your percentage value of window] to the percent of the window element you want your images width to be scaled at. So, if you want 90%, change this to 90. When the user resizes the browser window, it will automatically resize the images accordingly as well.

Categories