javascript overlay on a custom html element - javascript

I am trying to make a simple Overlay module that would enable me to put overlay on a custom DOM element. The problem is that css for the overlay div specifies position:absolute. But element on which the overlay should be applied can have position:static in which case the overlay is applied incorrectly. How to overcome this issue? I have come up with this but I am not sure if it is good.
//js
if ($(elem).css('position') == 'static') {
$(elem).css('position', 'relative');
}
$('<div></div>').prependTo(elem).addClass('overlay').css('z-index', 100);
// css
div.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: 0.75;
filter: alpha(opacity=75);
}

The suggestion of Thomas Andersen works. A slight disadvantage is a bit higher complexity and that position of the overlay is not pinned to the position of the element. Another approach could be to do it like this:
div.overlay {
position: absolute;
background: #000;
opacity: 0.75;
filter: alpha(opacity=75);
}
var width = $(elem).width();
var height = $(elem).height();
$('<div></div>')
.width(width)
.height(height)
.prependTo(elem)
.addClass('overlay')
.css('z-index', 100)
Here I am setting position:absolute without specifying top/left which should cause the overlay to be taken out of the flow while keeping its offset. Uncommon usage, I guess, but I believe I can rely on this.
The original solution I have proposed is a real hack and caused me some problems already.

Related

Make a div bigger and wider while scrolling

How do I enlarge a div while scrolling from a size of 20% width and height in the center to 100% width and height?
I'm currently trying at my first website and I'm almost there. All that is missing is animations and improvements in CSS. One of my ideas is that you have a div with a background inside and while scrolling the picture gets bigger up to the whole viewpoint. I would be very grateful if someone could help me.
You can use transform scale to do it.
CSS part will set the element to take 100% of width and height (i use viewport units), and set it position to fixed (so you will see what happen when you scroll).
Since we gonna change it's scale while scroll, set it initial scale to be 20% of it's original size.
JS part will listen to scroll event and scale the div that it won't be less then 20% but also won't be larger then 100%.
Play with the numbers on the condition to get what you need:
const demoDiv = document.querySelector("#demo");
window.addEventListener('scroll', function() {
if (pageYOffset*0.0001 > 1 || pageYOffset*0.0001 < 0.2) { return; }
else { demo.setAttribute('style', 'transform: scale('+pageYOffset*0.0001+');'); }
});
body {height: 40000px; margin: 0; padding: 0;}
p {position: fixed; top: 0; left: 0; font-size: 40px;}
#demo {
text-align: center;
font-size: 10vw;
position: fixed; top: 0; left: 0;
width: 100vw;
height: 100vh;
background-color: black;
color: white;
transform: scale(0.2); /* since you ask for 20% */
}
<p style="">Scroll to see it grow.</p>
<div id="demo">My minumum width and height are 20% and i will stop grow when i get to 100%</div>
Firstly, Congratulations on your first website. Good luck on your coding journey.
You can do it by using CSS & JavaScript. There is many way, but I'm writing one here. I hope it will be some good.
Let us call the div with an CSS ID animatedDiv.
<div id="animatedDiv"></div>
Now, lets style it with CSS
#animatedDiv
{
margin-top: 200px;
background: #dc143c;
min-height: 350px;
min-width: 20%;
position: absolute;
}
Here, I gave the div a background color, Absolute type of position, and margin-top of 200px. You can change it according to your needs. I used min-height and min-width property because these value will not be any fixed value, they will change on scroll.
Now, lets write some JavaScript
var aDiv = document.getElementById("animatedDiv");
function changeWidth()
{
var scrollVal = window.pageYOffset;
var scrollSlow = (scrollVal / 4);
//Changing CSS Width
aDiv.style.width = Math.min(Math.max(scrollSlow, 20), 100) + "%";
}
window.addEventListener('scroll', function()
{
requestAnimationFrame(changeWidth);
}, false);
Here, on a user define function, I catch the div with it's ID and assign into aDiv variable. Then I catch the page offset on Y axis (How much pixel the page was scrolled) and store it into a variable scrollVal, Next I divide the value by four (you can use 5, 10 20). It will slow the changing effect.
I've use Math methods (min and max) to assign a value between 20 to 100%.
To make the function work on scroll, window.addEventListener is used, and the window.requestAnimationFrame() method will tell the browser that we wish to perform it as an animation.
I hope it will be some help to you. I don't know did I explain well the process to you or not. English is not my mother language, so please don't mind if I made any grammatically mistake.
Wish you all the best.

Repeated 2-layer css parallax background in Firefox with css "transform" and "perspective" (background not cut off at content height)

You are my last hope.
I decided to implement an update to the Page of my brothers store. One of the new features I wanted was a (simple^^) parallax background with two layers to create a kind of 3d-feeling while scrolling.
First I got it to work with a little bit of JS, adjusting the position on scroll events with a multiplicator. Then I noticed that the performance of the background is sticky, laggy, stuttering and doesn't really look well in Firefox. As far I could see this was because of the "Asynchronous Panning"-Feature of the browser.
Link to the JS-Version of the page update
So after a little time with the search engine of my choice I saw no option to disable or work around that feature and decided to start working on a CSS-only implementation on that site.
And guess which browser is not able to display everything as wanted? Firefox!
First I stuffed all my content into divs, so that - so my hope - a mutual parent div would enable me to use "height: 100%;" to scale the div's together. That didn't work as the the background was overflowing over my content. The problem was: Because I wanted the background images to repeat on the y-axis AND to move with a slower speed as the content I had to define a specific height of the background divs which is larger than the content height.
I even tried to set the height of the background divs with jQuery by
$(#background).height($(.main_content_container).height());
but the background always just turned out to be too large or too short.
After my idea with the parent div didn't work I started to work with the body and my content container itself to generate perspective. Could this have worked when i would've set all height to 100%? When I set height: 100%; I always got my viewport's height...
What I got now:
Creating the perspective and applying transform with body causing the overflow-y:
body {
overflow-y: auto;
overflow-x: hidden;
perspective: 1px;
width: 100%;
margin-left: 0px;
margin-top: 0px;
position: fixed;
height: 100vh;
transform-style: preserve-3d;
align-items: center;
align-content: center;
align-self: center;
text-align: left;
width: 100vw;
}
#background {
position: fixed;
bottom: 0;
left: 0;
transform: translateZ(-2px) scale(3);
width: 100vw;
background-size: 100vw;
background-image: url(websiteimage.png);
left: 0;
right: 0;
top: 0;
height: 500vh;
min-width: 100vw;
}
#background2 {
position: fixed;
bottom: 0;
left: 0;
transform: translateZ(-3px) scale(4);
background-image: url(websiteimage2.png);
background-size: 100vw;
left: 0;
right: 0;
top: 0;
height: 500vh;
min-width: 100vw;
opacity: 80%;
}
div.main_content_container {
transform: translateZ(0);
height: 100%;
background-color: transparent;
color: Silver;
max-width: 100vw;
width: 70%;
min-height: 100%;
}
In-vivo page (only startpage and only in dark mode is "working" at the moment)
Why does Chrome cut off the bottom of the background divs just as wanted and Firefox just create visible overflow?
Is there any chance to get one of my solutions to work fluent and formatted in Firefox?
I'm puzzling around for days now and thankful for every kind of idea/suggestion.
PS: This is my first post on StackOverflow. I hope I provided enough info and didn't break any rules as this site often helped me out of the hell of amateur webdesign.
PPS: I know my code is kind of a mess after all that puzzling but I'm playing around for days now
For all having the same problem:
I decided to try out several tweaks on my JS-implementation again and reached an improvement by adding
position: fixed;
background-attachment: fixed;
background-position: top;
to the background layers.
I also added a script by keith clark but I'm not sure if it takes any effect:
/*
Firefox super responsive scroll (c) Keith Clark - MIT Licensed
*/
(function(doc) {
console.log("Document executed")
var root = doc.documentElement,
scrollbarWidth, scrollEvent;
// Not ideal, but better than UA sniffing.
if ("MozAppearance" in root.style) {
// determine the vertical scrollbar width
scrollbarWidth = root.clientWidth;
root.style.overflow = "scroll";
scrollbarWidth -= root.clientWidth;
root.style.overflow = "";
// create a synthetic scroll event
scrollEvent = doc.createEvent("UIEvent")
scrollEvent.initEvent("scroll", true, true);
// event dispatcher
function scrollHandler() {
doc.dispatchEvent(scrollEvent)
}
// detect mouse events in the document scrollbar track
doc.addEventListener("mousedown", function(e) {
if (e.clientX > root.clientWidth - scrollbarWidth) {
doc.addEventListener("mousemove", scrollHandler, false);
doc.addEventListener("mouseup", function() {
doc.removeEventListener("mouseup", arguments.callee, false);
doc.removeEventListener("mousemove", scrollHandler, false);
}, false)
}
}, false)
// override mouse wheel behaviour.
doc.addEventListener("DOMMouseScroll", function(e) {
// Don't disable hot key behaviours
if (!e.ctrlKey && !e.shiftKey) {
root.scrollTop += e.detail * 16;
scrollHandler.call(this, e);
e.preventDefault()
}
}, false)
}
})(document);
Still no improvement on iOS Safari and mobile Firefox afaics.
Edit:
Thats the jQuery-function causing the effect here:
$(function() {
$(window).on('scroll', function() {
$('#background').css('background-position-y', $(window).scrollTop() * -.15);
});
});
$(function() {
$(window).on('scroll', function() {
$('#background2').css('background-position-y', $(window).scrollTop() * -.09);
});
});

Updating position of fixed element on scroll event on unresponsive page

I have a large page running a lot of javascript which also contains a fixed position floating element. The floating element updates its position based on the user's current scroll position, via a function which fires on the scroll event.
The issue I am having is that due to the size and complexity of the page, there is a delay before the code in the scroll event is executed, and this causes the fixed element to noticeably jump when scrolling quickly or using the mouse wheel.
See jsfiddle: http://jsfiddle.net/jorsgj2b/1/ (The use of setTimeout simulates the delay in executing the function on the real page.)
<div class="header"></div>
<div class="main"></div>
<div class="float"></div>
.header {
width: 100%;
height: 200px;
background-color: #787878;
}
.main {
width: 100%;
height: 1400px;
background-color: lightblue;
}
.float {
position: fixed;
width: 100px;
height: 50px;
top: 233px;
right: 25px;
background-color: red;
z-index: 2;
}
$(function() {
$(window).scroll(function() {
setTimeout(updateFloat, 50);
});
});
var updateFloat = function() {
var mainTop = $('.main').offset().top;
var scrollPos = $(window).scrollTop();
var floatOffset = 25;
var newTop = (scrollPos > mainTop)
? floatOffset + 'px'
: mainTop + floatOffset - scrollPos + 'px';
$('.float').css('top', newTop);;
}
I am at a bit of a loss as to how to resolve this. I have tried updating the margin instead of top position, as well as switching between absolute and fixed positioning. Perhaps there is a way to use css transitions to help, however I haven't managed to get them to work here.
You might add position: sticky to your css to that the stickiness is done by browsers that support it (only Firefox and Safari according to caniuse.com).
You'll always be limited to the fidelity of the scroll events so you may always see a bit of a delay, but you could improve things a little by caching values instead of looking them up each time updateFloat() is called. For example
var mainElement = $('.main');
var windowElement = $(window);
var floatElement = $('.float');
var updateFloat = function() {
var mainTop = mainElement.offset().top;
var scrollPos = windowElement.scrollTop();
var floatOffset = 25;
var newTop = (scrollPos > mainTop)
? floatOffset + 'px'
: mainTop + floatOffset - scrollPos + 'px';
floatElement.css('top', newTop);
}
The problem might also be related to browser trying to re-layout the page because the .float element is in the same render layer as the other divs. You can fix that by adding a style that tells the browser to put the .float element in its own render layer (resulting in much faster rendering due to GPU compositing). The most common trick is to add transform: translateZ(0); to your style, but there's also a proposed style will-change that is supported by several browsers. So you should update your css like this
.float {
will-change: scroll-position;
transform: translateZ(0);
position: fixed;
width: 100px;
height: 50px;
top: 233px;
right: 25px;
background-color: red;
z-index: 2;
}
Note that adding render layers increases memory usage so don't go overboard with it. It also sometimes impacts other features, like anti-aliasing of text.

Position fixed but still scrollable?

Would it be possible to have a DIV position: fixed, but if the content of that DIV extend beyond the viewing area of the screen then you could still scroll with the window? I've put everything I have thus far in this...
FIDDLE
This code sits inside a media query that gets triggered when the screen hits a max width and/or a max height, but I don't think that code is relevant to my question. This is the bit of code that I believe I need to modify to work correctly:
.expand {
display: block !important;
position: fixed;
-webkit-backface-visibility: hidden;
top: 50px;
left: 0;
background: rgba(31, 73, 125, 0.8);
width: 100%;
z-index: 999;
}
The reason I want this fixed is so the little hamburger menu stays statically in the upper left hand corner of the screen at all times, as at times the site I'm building could be rather lengthy, so I would like viewers to have a little more ease of access.
Thank you!
Yes, you just need to give the div a fixed height and the overflow: auto setting
(Demo)
.expand {
bottom: 0;
overflow: auto;
}
If you don't want to give it a minimum height, a simple (but not supported by old browsers) option would be to use css calc() like so
.expand {
max-height: calc(100% - 50px); // 100% viewport height minus the height of the nav.
}
I would suggest setting a fallback height before in case the browser does not support calc
JavaScript
To achieve what you really want you need javascript. Here it is.
Check to see if the menu is open, if not...
Define a check to see if the contents are larger than the viewport, if so then set bottom: 0px; and overflow: auto and remove scrolling from the body.
If so...
Remove all styles from the menu and the body that were added when opening the menu.
(Demo)
(function($) {
var menu = $('.responsive-menu'), open;
$('.menu-btn').click(function () {
if(!open) {
if(menu.height() > $(window).height()) {
open = true;
menu.css({'bottom': '0px', 'overflow': 'auto'});
document.body.style.overflow = 'hidden';
}
} else {
open = false;
menu.css({'bottom': '', 'overflow': ''});
document.body.style.overflow = '';
}
menu.toggleClass('expand');
});
})(jQuery);

background image shaky on div resize

I want to use HTML to create an "opening" effect of one on top of another one.
After some research i figured out a way (see JSFiddle).
I now have the problem that the background image moves a little bit when the circle is resizing.
Can anyone help me figure out how to get the background image to stand still.
The image in the circle needs to keep same zoom level when opening.
The circle needs to be centered and the bottom half needs to be out of the window.
Circle css is this:
.circle {
width: 0px;
height: 0px;
z-index: 10;
position: absolute;
border-radius: 50%;
overflow: hidden;
margin: 0 auto;
left: 50%;
-moz-transform: translate(-50%, 50%);
-webkit-transform: translate(-50%, 50%);
bottom: 0;
-moz-transition: all 1.5s;
-webkit-transition: all 1.5s;
}
JSFiddle: http://jsfiddle.net/GmvUQ/2/
Update,
Let me explain a little more. i notice that my question is not clear enough.
I have a few screenshot for the effect i want to create:
1st frame:
2nd frame
The entire effect is already working but when the transition is in progress (The circle with the image is getting bigger or smaller) the image inside the circle moves a little bit.
This is probably because of the calculations that need to be done by Javascript / CSS positioning.
I would like some help how to let this image stand entirely still during resize transition.
Thanks!
DEMO: http://jsfiddle.net/GmvUQ/5/
Updated HTML
<div>
<div class="buttons">
<button onclick="changeboleto(0)">Click here</button>
<button onclick="changeboleto(500)">Click here</button>
<button onclick="changeboleto(1000)">Click here</button>
</div>
<div class="circle girl">
</div>
<div class="circle lamborghini">
</div>
</div>
Note that I've removed the nested </div> elements within each .circle. Instead I've added an extra class for each, which sets the background-image (and some positioning for them, if necessary).
Updated CSS
.circle {
width: 250px;
height: 250px;
z-index: 10;
position: absolute;
border-radius: 50%;
overflow: hidden;
margin: 0 auto;
background-repeat: no-repeat;
background-size: cover;
background-origin: content-box;
background-position: center center;
}
.lamborghini {
background-image: url(http://www.hdwallpapers.in/walls/2013_wheelsandmore_lamborghini_aventador-wide.jpg);
}
.girl {
background-image: url(http://www.hdwallpapers.in/walls/colorful_background_girl-normal5.4.jpg);
top: 50%;
}
.buttons {
position: relative;
z-index: 5;
}
I've moved most of the CSS in to the .circle class as it is common to both image sets. Pay special attention to the values for the background-* attributes.
Updated JQuery
function changeboleto(pix) {
circleHeight = pix;
circleWidth = pix;
$('.circle').animate({
'width' : circleWidth,
'height': circleHeight
}, 1500, 'linear');
//css('width', circleWidth).css('height', circleHeight);
changeCircleBackgroundToWindow();
}
function changeCircleBackgroundToWindow() {
windowWidth = $(window).width();
windowHeight = $(window).height();
$(".circle > div").animate({
'width' : windowWidth,
'height': windowHeight
}, 1500, 'linear');
$(".circle > div").animate({
'width' : windowWidth,
'height': windowHeight
}, 1500, 'linear');
//$(".circle-background").css("width", windowWidth).css("height", windowHeight);
//$(".circle-background2").css("width", windowWidth).css("height", windowHeight);
}
Rather than mix JQuery and CSS transitions I've lumped all the animation together in the JQuery.
I've used the animate() function and specified the easing method. The default easing is swing but I've used linear as this progresses the animation at a constant pace.
Edit
The solution above includes CSS that allows the image to scale with the animation. However you are requesting that the image stays at the same "zoom level" throughout.
To achieve this simply remove a line from the CSS, namely this one:
.circle {
...
background-size: cover;
...
}
I know this is 5 years too late, but I found this thread via a search engine and thought I'd provide my own thoughts.
This effect can also be achieved with clip-path, which is a bit more forgiving than jquery's animate (which can still result in image shakiness if you're animating certain/enough properties).
clip-path has the additional benefit of not needing javascript at all if you're doing, say, hovers rather than button clicks. It also results in a simpler HTML file.
I've made an updated version of the original question's jsfiddle, http://jsfiddle.net/GmvUQ/13/ which demonstrates doing this with clip-path. It's still using jquery to handle the button clicks, but the "magic" all happens via CSS transitions, rather than javascript animations.
JQuery:
function changeboleto(pix) {
...
$('.circle-background').css('clip-path', 'circle(' + pix/2 + 'px at 50% 100%)');
}
CSS (including original CSS from original fiddle):
.circle-background {
position: absolute;
z-index: 10;
clip-path: circle(0% at 50% 100%);
background:url(http://www.hdwallpapers.in/walls/colorful_background_girl-normal5.4.jpg);
background-size: cover;
-webkit-transition: all 1.5s;
-moz-transition: all 1.5s;
bottom: 0%;
left: 50%;
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
}
What this does is simply cause the CSS to transition on the clip-path property, animating the circle expansion. Because the image itself never moves, just the boundaries between which it displays, it never shakes.
Full screen demo
JSFiddle: http://jsfiddle.net/7bP7Z/4/ (Click around to see things grow)
Okay, so now that the question has more clarification I have revisited the drawing board and have come up with a better solution.
HTML
<div class="circle">
<div class="circle-overlay"></div>
<img src="http://www.hdwallpapers.in/walls/2013_wheelsandmore_lamborghini_aventador-wide.jpg" />
</div>
<div class="circle">
<div class="circle-overlay"></div>
<img src="http://www.hdwallpapers.in/walls/colorful_background_girl-normal5.4.jpg" />
</div>
Note the changes to the structure:
A containing element
An "overlay" element
An </img>
CSS
.circle {
position: relative;
overflow: hidden;
}
.circle-overlay {
position: absolute;
left: 50%;
margin-left: -150px;
bottom: -150px;
border-radius: 50%;
width: 300px;
height: 300px;
box-shadow: 0px 0px 0px 3000px white;
}
Nice and simple CSS!
The majority of the code is used to position our .circle-overlay class. This class provides a transparent circle (using border-radius) and utilises one of my favourite new CSS features - box-shadow - to apply a solid, white "outline" of an arbitrarily large value that covers the image below it. Have a play with the colour and size (adjust the 300px value) of the box-shadow to see how this works.
JQuery
$('.circle').click(function() {
var c = $(this).children('.circle-overlay');
var w = c.width() + 100;
c.animate({
'width' : w,
'height': w,
'bottom': (w*-0.5),
'margin-left': (w*-0.5)
}, 500, 'linear');
});
Once again, keeping things nice and simple!
The above JQuery performs a very simple task. It increases the size of the circle-overlay whilst maintaining its bottom, centre positioning on every click.
This should be a very smooth animation and the image should not "judder" or "shake" as the image is not being manipulated.

Categories

Resources