I have a webpage where there is a full height intro image. Underneath this image is the main body of the site with a regular site header at the top, I'm trying to create an effect where once the user scrolls down to the site header, they cannot scroll back up to view the intro image.
CSS Classes:
Main Intro Image: .cq-fullscreen-intro
Site Header: .nav-down
I had a poke around on StackOverflow but I can't find anything that addresses this circumstance, can anyone point me in the right direction to achieve this using jQuery?
you can use JQuery scrollTop function like this
$(function() {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
// set the height in pixels
if (scroll >= 200) {
// after the scroll is greater than height then you can remove it or hide it
$(".intro-image").hide();
}
});
});
So instead of scrolling, I personally think it would be better to have it be actionable. Forcing the user to manually do the transition (and all in between states) is a bad idea. If the user scrolls half way, and see's something actionable (menu, button, input field) is it usable? If it is, what happens if they submit... very awkward. If it isn't usable, how do they know when it is? How do they know it's because they haven't scrolled all the way. It's very poor user experience.
In the following example, I've created a pseudo-screenport for you to see what's actually going on. The .body container in your real site would be the body element.
Code Pen Example
$(document).ready(function(){
$('.splash-screen').on('click', function(){
$('.splash-screen').addClass("is-hidden");
});
})
html, body{
background: #eee;
margin: 0;
padding: 0;
}
.flex-root {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.web-container {
width: 640px;
height: 480px;
background: #fff;
}
.body {
font-size: 0; // this is only to prevent spacing between img placholders
position: relative;
}
.splash-screen{
position: absolute;
transition: transform 1s ease-in-out;
}
.splash-screen .fa {
position: absolute;
z-index: 1;
font-size: 24px;
color: #fff;
left: 50%;
bottom: 15px;
}
.splash-screen.is-hidden {
transform: translateY(-110%);
transition: transform 1s ease-in-out;
}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-root">
<div class="web-container">
<div class="body">
<div class="splash-screen">
<img src="https://via.placeholder.com/640x480?text=Splash+Screen"/>
<i class="fa fa-chevron-circle-up"></i>
</div>
<img src="https://via.placeholder.com/640x60/cbcbcb?text=Menu"/>
<img src="https://via.placeholder.com/640x420/dddddd?text=Site Body"/>
<div>
</div>
</div>
While its not direclty preventing you from scrolling up and its not jQuery, I would suggest to remove/hide the element once its out of view.
You could get the current scroll position, relative to the top of the page, and check if its greater than the elements height:
const target = document.getElementById('my-target')
const targetHeight = target.getBoundingClientRect().height
const scrollEventListener = () => {
if (
document.body.scrollTop > targetHeight ||
document.documentElement.scrollTop > targetHeight
) {
target.remove()
window.removeEventListener('scroll', scrollEventListener)
document.documentElement.scrollTop = 0
}
}
window.addEventListener('scroll', scrollEventListener)
Here is a codepen https://codepen.io/bluebrown/full/aboagov
Related
So I sort of got it working. I believe I am not understanding the javascript correctly.
I took this from another thread, however it isn't behaving quite the way I am trying to achieve. I see the variables are a math equation that bases the movement on the window height.
How can I manipulate the equation so that I can control "Some cool text."'s initial position (if you notice on load it takes the correct position, and then on scroll it gets moved by JS) to stay where I want it?
What controls the speed and intensity of the movement and how can I manipulate that?
I believe I am just not understanding the syntax that controls all these variables, can you point me in the right direction for some reading to understand these specific variables? Thank you. :D
https://jsfiddle.net/codingcrafter/kv9od1ju/22/
/* Custom Horizontal Scrolling Parallax */
.hero-two {
overflow: hidden;
position: relative;
min-height: 500px;
}
h1 {
-webkit-text-stroke-width: 0.1rem;
-webkit-text-stroke-color: black;
color: #fff;
font-family: 'Open Sans', Helvetica, Times New Roman !important;
font-weight: 900;
}
.para-ele {
position: absolute;
width: 100%;
font-size: 5rem;
}
#hero-first {
left: 75%;
top: 15%;
}
#hero-second {
left: -32%;
bottom: 10%;
}
.container {
position: relative;
box-sizing: border-box;
width: 100%;
height: 100%;
}
<div class="container">
<div class="hero-two">
<h1 id="hero-first" class="h1 para-ele">
Some cool text.
</h1>
<h1 id="hero-second" class="h1 para-ele">
Some boring text.
</h1>
</div>
</div>
$(document).ready(function() {
var $horizontal = $('#hero-first');
$(window).scroll(function() {
var s = $(this).scrollTop(),
d = $(document).height(),
c = $(this).height();
scrollPercent = (s / (d - c));
var position = (scrollPercent * ($(document).width() - $horizontal.width()));
$horizontal.css({
'left': position
});
});
});
So you want to move the text from left to right or right to left?
I have done something similar to your issue but I used jQuery to handle the scroll effect.
If you are going to use the code below you will need to wrap the text within a element with the class Introduction
As the page scrolls the element will append the styles dynamically to the element.
<h1 class="introduction">
WE ARE A <br><span class="d">DIGITAL</span><br>PARTNER
</h1>
$(window).scroll(function() {
var wScroll = $(this).scrollTop();
$(".introduction").css({
transform: "translateX(-" + wScroll / 23 + "%)"
})
});
Demo: https://guide-nancy-64871.netlify.com/
When page is scrolled the header text moves to the left.
Read more on css transform: https://css-tricks.com/almanac/properties/t/transform/
Hope this helps!
I am attempting to use waypoints for two specific functions.
To identify if a user is scrolling up or down and the container comes into view. This is not working.
The second thing I am trying to figure out how to do doesn't necessarily have to do with waypoints. I want the image you see in the snippet to progressively transform: translateX based on the scroll progression. I am not sure how to do this. I put translate in the snippet to show the movement.
If you go to this site and scroll down a little to the "Nike and Snapchat" section, you will see a phone image of Lebron. As you progressively scroll up or down, the image moves accordingly. This is what I am trying to replicate.
Does anyone know what I can do to achieve this?
var homeMainSec = $('#homeMainSec');
homeMainSec.waypoint(function(direction) {
if (direction === 'down') {
$('#homeBoxGridRight img').addClass('slideLeftDisplay');
console.log('Left Slide');
}
}, {
offset: '25%'
});
homeMainSec.waypoint(function(direction) {
if (direction === 'up') {
$('#homeBoxGridRight img').addClass('slideRightDisplay');
console.log('Right Slide');
}
}, {
offset: '25%'
});
#homeMainSec {
width: 100%;
height: 95vh;
position: relative;
margin-top: 70px;
}
.homeMainBlock {
height: 100%;
width: 50%;
display: inline-block;
vertical-align: top;
box-sizing: border-box;
}
/*- HomeBoxGridRight Section -*/
#homeBoxGridRight img {
display: block;
width: 40%;
height: auto;
margin-left: 50%;
}
.slideLeftDisplay {
transform: translateX(-100px);-webkit-transform: translateX(-100px);
transition: 1s;-webkit-transition: 1s;
opacity: 1;
}
.slideRightDisplay {
transform: translateX(100px);-webkit-transform: translateX(100px);
transition: 1s;-webkit-transition: 1s;
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
<section id="homeMainSec">
<div class="homeMainBlock" id="homeBoxGridLeft">
</div><div class="homeMainBlock" id="homeBoxGridRight">
<img src="https://slidesjs.com/examples/standard/img/example-slide-1.jpg" alt="Image">
</div>
</section>
<br><br><Br><br><br><br><br><br>
This gives you page scroll position for vertical scroll
window.pageYOffset
This gives you total scroll height for body
document.querySelector("body").scrollHeight
You need to subtract the height of scrollbar element that is given by
document.scrollingElement.offsetHeight
You can translate with respect to ratio of vertical scroll position and body height
window.pageYOffset/(document.querySelector("body").scrollHeight - document.scrollingElement.offsetHeight)
This will give you, ratio of current position to max scrollable position.
Manipulate it as you like to translate the elements wrt their initial position.
My problem is along the lines of these previous issues on StackOverflow but with a slight difference.
Previous issues:
Stopping fixed position scrolling at a certain point?
Sticky subnav when scrolling past, breaks on resize
I have a sub nav that starts at a certain position in the page. When the page is scrolled the sub nav needs to stop 127px from the top. Most of the solutions I have found need you to specify the 'y' position of the sub nav first. The problem with this is that my sub nav will be starting from different positions on different pages.
This is the JS code i'm currently using. This works fine for one page but not all. Plus on mobile the values would be different again.
var num = 660; //number of pixels before modifying styles
$(window).bind('scroll', function () {
if ($(window).scrollTop() > num) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
});
I'm looking for a solution that stops the sub nav 127px from the top no matter where on the page it started from.
You can use position: sticky and set the top of the sub-nav to 127px.
See example below:
body {
margin: 0;
}
.main-nav {
width: 100%;
height: 100px;
background-color: lime;
position: sticky;
top: 0;
}
.sub-nav {
position: sticky;
width: 100%;
height: 50px;
background-color: red;
top: 100px;
}
.contents {
width: 100%;
height: 100vh;
background-color: black;
color: white;
}
.contents p {
margin: 0;
}
<nav class="main-nav">Main-nav</nav>
<div class="contents">
<p>Contents</p>
</div>
<nav class="sub-nav">Sub-nav</nav>
<div class="contents">
<p>More contents</p>
</div>
Please see browser support for sticky here
You should change your code to the below, should work fine:
$(window).bind('scroll', function () {
if ($(window).scrollTop() > $(".menu").offset().top) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
});
Maybe you can try this:
Find navigation div (.menu)
Find the top value of the .menu (vanilla JS would be menuVar.getBoundingClientRect().top, not sure how jQuery does this).
Get top value of browserscreen.
Calculate the difference - 127px.
When the user scrolls and reaches the top value of the menu -127px -> addClass('fixed').
I'm currently working on a project where the desired user experience involves a very customized interaction with scroll events.
Problem to solve:
The page has X sections, each of them with a height equal to the viewport hight height: 100vh;. When a user scrolls down on the viewport, the current visible section stays where it is and a scroll indicator animates based on a threshold of distance scrolled (30px, for example). Once the user has scrolled the threshold, the next section comes up from the bottom of the screen and covers up the current section (which still doesn't move).
Initial Approach:
Set each section to an absolute position and adjust them with by changing CSS classes based on the scrollwheel event. Body overflow:hidden and transform property to manipulate the sections. I am running in to issues, though.
The scrollwheel event seems to be documented as very unstable solution to implement.
The .wheelDelta aspect of the event fires asynchronously and is difficult to capture a gesture with. (On chrome, it just spits out a multiple of 3 a bunch of times rather than a distance of the gesture in px). This makes it difficult to set a threshold and animate the elements that are responsive to that threshold.
I basically want to be able to track the number of pixels a scrollwheel-like event is covering and apply that number to the position of a certain scroll-hint element until the scroll threshold is met. Once it is met, a function fires to change the classes and update some information on the page. If the threshold is not met, the scroll hint element goes back to it's default position.
My attached approach doesn't feel very conducive to accomplishing this, so I'm looking for either 1) a different and more stable approach or 2) revisions / criticisms on what I'm doing wrong with this approach to make it stable.
(function scrollerTest($){
$('body').on ('mousewheel', function (e) {
var delta = e.originalEvent.wheelDelta,
currentScreenID = $('section.active').data('self').section_id,
currentScreen = $('section.part-' + currentScreenID),
nextScreenID = currentScreenID + 1,
nextScreen = $('section.part-' + nextScreenID);;
if (delta < 0) { // User is Scrolling Down
currentScreen.removeClass('active').addClass('top');
nextScreen.removeClass('bottom').addClass('active')
} else if (delta > 0) { // User is Scrolling Up
}
});
}(jQuery));
body {
overflow: hidden;
padding: 0;
margin: 0;
}
section {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
z-index: 999;
background-color: #CA5D44;
transition: 0.8s all ease-in-out;
}
section.part-1 {
position: relative;
z-index: 9;
}
section.part-2 {
background-color: #222629;
}
section.active {
transform: translateY(0);
}
section.top {
transform: translateY(-10%);
}
section.bottom {
transform: translateY(100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<body>
<section class="part-1 home active" data-self='{ "section_id" : 1, "section_title" : "Home", "menu_main_clr" : "#fff" , "menu_second_clr" : "#CA5D44", "logo_clr" : "white" }'>
</section>
<section class="part-2 about bottom" data-self='{ "section_id" : 1, "section_title" : "About", "menu_main_clr" : "#CA5D44" , "menu_second_clr" : "#fff", "logo_clr" : "white" }'>
</section>
<section class="part-3 contact bottom" data-self='{ "section_id" : 1, "section_title" : "Contact", "menu_main_clr" : "#fff" , "menu_second_clr" : "#CA5D44", "logo_clr" : "white" }'>
</section>
</body>
Edit Note:
The snippet seems to have some issue with firing the event and changing classes after the first instance - not sure why. On my local example it fires them all at once..
**Edite Note 2: **
Listed code is just a copy of the closest behaviour I could achieve. The whole threshold functionality seems pretty unattainable with this method, unfortunately, as the wheel event doesn't behave like a scroll event.
the whole scroll topic is rather complex especially when you think about touch scroll events, too.
There are some libraries out there - see this list for example: http://ninodezign.com/30-jquery-plugins-for-scrolling-effects-with-css-animation/
I used https://projects.lukehaas.me/scrollify/ before and it might allow you to do what you intend (using the before callback eventually) but I can't tell without trying myself. Also regard that scrollify is relatively big (8kb minified) in comparison to other libraries.
You can approach this using by ensuring each content-filled section is followed by a blank transparent gap (in the example below, also 100vh in height) and then using javascript to apply position:fixed to each content-filled section when it hits the top of the viewport.
Example:
var screens = document.getElementsByClassName('screen');
function checkPosition() {
for (var i = 0; i < (screens.length - 1); i++) {
var topPosition = screens[i].getBoundingClientRect().top;
if (topPosition < 1) {
screens[i].style.top = '0';
screens[i].style.position = 'fixed';
}
}
}
window.addEventListener('scroll',checkPosition,false);
.screen {
position: absolute;
display: block;
left: 0;
width: 100%;
height: 100vh;
}
.red {
position: fixed;
top: 0;
background-color: rgb(255,0,0);
}
.orange {
top: 200vh;
background-color: rgb(255,140,0);
}
.yellow {
top: 400vh;
background-color: rgb(255,255,0);
}
.green {
top: 600vh;
background-color: rgb(0,191,0);
}
.blue {
top: 800vh;
background-color: rgb(0,0,127);
}
p {
font-size: 20vh;
line-height: 20vh;
text-align: center;
color: rgba(255,255,255,0.4);
}
<div class="red screen">
<p>Screen One</p>
</div>
<div class="orange screen">
<p>Screen Two</p>
</div>
<div class="yellow screen">
<p>Screen Three</p>
</div>
<div class="green screen">
<p>Screen Four</p>
</div>
<div class="blue screen">
<p>Screen Five</p>
</div>
The problem:
I have a form with a button underneath it to submit (post) from data with jQuery ajax(). I want for the button to be replaced with a spinner (animated png) for the duration of server ajax call. But such a trivial task is impossible in css to do right.
What i have tried:
I have placed button and image inside a bootstrap row. Ox ajax call I have set button display to none and img display to block. But because this two are not of the same size makes the whole page flicker, breaks the positioning of other elements and so on.
Another idea was to try to place both elements on top of each other with absolute positioning. But, stupid as css is I cannot center it on the middle of the row.
Is there a way to position both elements on top of each other so I can control their visibility?
Please bear in mind that I cannot used absolute position in pixel, because this is a web page and I do not not how wide the browser will be, image can change in the future, text in the button can change in the future, all this things affect absolute size.
If there is another solution to my problem which would prevent the page from jumping up and down it would also be great.
EDIT
Link to one of fiddle experiments:
https://jsfiddle.net/ofb2qdt8/
.button {
position: relative;
margin: auto;
height: 50px;
width: 30px;
background: blue;
z-index: 1;
display: block;
}
.spinner {
position: relative;
margin: auto;
height: 30px;
width: 50px;
background:red;
z-index: 2;
}
This renders second element underneath on screen. Not on different z layer.
Experiment 2:
https://jsfiddle.net/ofb2qdt8/
.button {
position: absolute;
margin: auto;
height: 50px;
width: 30px;
background: blue;
z-index: 1;
display: block;
}
.spinner {
position: absolute;
margin: auto;
height: 30px;
width: 50px;
background:red;
z-index: 2;
}
This does not center both elements, and they are pushed to the top of the containing div. The element with less height should be centered.
Check this working demo: https://jsfiddle.net/ofb2qdt8/3/
Add in a few lines of jquery and update your css.
Position your loading div according to button div's position, width, height using jquery.
*Click the button to see loading div, and try to play the margin of the button to any pixel.
###JQUERY
$(document).ready(function () {
$('.c2').each(function () {
$(this).css({
'width': $(this).siblings('.c1').outerWidth(),
'height': $(this).siblings('.c1').outerHeight(),
'top': $(this).siblings('.c1').offset().top,
'left': $(this).siblings('.c1').offset().left
});
});
$('.c2').on('click', function () {
$(this).hide(0);
});
});
###CSS
.c1 {
margin: 100px auto;
width: 100px;
text-align: center;
padding: 5px 10px;
background: blue;
z-index: 1;
}
.c2 {
position: fixed;
text-align: center;
background: red;
z-index: 2;
cursor: pointer;
}
Rough, ready and untested:
HTML
<div>
<input type='submit' />
<img src="spinneyIMage.gif" />
</div>
CSS
div{ text-align: center; }
div img{ display: none; }
jQuery
$('submit').click(function(e){
e.preventDefault();
$(this).hide().next().show();
});
After the Ajax call completes reverse the above jQuery.
As I haven't been able to find a working solution I have reverted to my first idea which I discarded at first. Albeit with a little twist.
HTML
<div class="row>
<div id="container-button" class="col-xs-12>
<button id="button" onclick="button_OnClick(e)">submit form via ajax</button>
<img src="img/spinner.png" sytle="display: none" />
</div>
</div>
JS
function btnContact_OnClick() {
// show the soinner and hide the button
showSpinner();
$.ajax(
{
type: 'POST',
url: "someurl.com/target",
data: $("#form").serialize(),
dataType: "json",
complete: function() { hideSpinner();},
success: onAjaxSuccess,
error : onAjaxError
});
}
function hideSpinner() {
$("#spinner").hide();
$("#button").show();
// make container height non-fixed and content adjustable again
$("#container-button").height('auto');
}
function showSpinner() {
// THis is the trick !!!
// Make the container fixed height as it was before displaying spinner, so it does not change with content (spinner is not the same height as button
$("#container-button").height($("#container-button").height());
$("#button").hide();
$("#spinner").show();
}
This is not the perfect solution but the best I could make.
Drawbacks:
it is not clean, you have to use javasript to fix what is css layout
problem
it still causes a little flicker
the height of container while displaying spinner is dependant on button, this may cause clipping if spinner is too big