Custom context menu always visible - javascript

I'm implementing a custom menu that appears when the user clicks the left mouse button and I'm having trouble trying to set the position (X, Y) of the menu so that the entire menu will be visible no matter which part of the page it opens.
The image below represents the problem:
The width of the menu increases depending on the text it has, so adjusting its position and height is also a challenge.
var elements = $('#content').find('h1, p, span');
var setMenuPosition = function(x, y) {
$("#menu").css('top', y);
$("#menu").css('left', x);
};
var setSelectedText = function() {
$('#menu').data('text', $(this).text());
};
var openMenu = function(e) {
e.stopPropagation();
elements.css('border', '1px solid transparent');
$(this).css('border', '1px dashed #333');
$('#menu').addClass('active');
$('#selected-text').text($('#menu').data('text'));
setMenuPosition(e.pageX, e.pageY);
};
var closeMenu = function() {
elements.css('border', '1px solid transparent');
$('#menu').removeClass('active');
};
$('#content').find('h1, p, span').on('mouseenter', setSelectedText);
$('#content').find('h1, p, span').on("click", openMenu);
$('#menu').on('mouseleave', closeMenu);
h1,
p,
span {
border: 1px solid transparent;
}
#content {
background-color: #e9e9ea;
padding: 25px;
}
#menu {
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
background-color: #84ce6a;
color: #fff;
padding: 15px;
position: absolute;
min-width: 200px;
border-radius: 8px;
}
#menu.active {
visibility: visible;
opacity: 1;
}
#my-span {
background-color: rgb(255, 79, 79);
color: rgb(255, 255, 255);
padding: 0px 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<h1>My Title</h1>
<p>My text</p>
<p>My another text</p>
<p>My text <span id="my-span">My span</span>, other part of the same text</p>
</div>
<div id="menu">
<h4>Selected text is: <span id="selected-text"></span></h4>
<button>
Ok
</button>
</div>
My fiddle: https://jsfiddle.net/robsonnogueira/295d78ak/

To prevent the Menu go outside the viewport you need this logic:
// 1. Set menu content
$menuContent.text(ev.currentTarget.textContent);
// 2. Get X, Y click coordinates
let X = ev.clientX;
let Y = ev.clientY;
// 3. Fix X, Y
X = Math.max(0, Math.min(X, $win.width() - $menu.outerWidth(true)) );
Y = Math.max(0, Math.min(Y, $win.height() - $menu.outerHeight(true)) );
// 4. Show menu
$menu.css({left:X, top:Y}).addClass('is-visible');
which takes in consideration the window (viewport) size and the Menu size (after its content is inserted) - and fixes, modifies the X, Y coordinates accordingly by using a combination of Math.max() and Math.min()
Here's an example:
jQuery($ => {
const $win = $(window);
const $menu = $('#menu');
const $menuContent = $('#menu-content');
const menuOpen = (ev) => {
ev.stopPropagation();
// 1. Set menu content
$menuContent.text(ev.currentTarget.textContent);
// 2. Get X, Y click coordinates
let X = ev.clientX;
let Y = ev.clientY;
// 3. Fix X, Y
X = Math.max(0, Math.min(X, $win.width() - $menu.outerWidth(true)) );
Y = Math.max(0, Math.min(Y, $win.height() - $menu.outerHeight(true)) );
// 4. Show menu
$menu.css({left:X, top:Y}).addClass('is-visible');
}
const menuClose = () => {
$menu.removeClass('is-visible');
}
// Events
$(".menu-open").on('click', menuOpen);
$(".menu-close").on('click', menuClose);
$(document).on('click', menuClose);
$menu.on('click', ev => ev.stopPropagation());
});
html, body {
height: 100%;
margin:0;
font: 14px/1.4 sans-serif;
}
#menu {
position: fixed;
max-width: 300px;
left: 0;
top: 0;
background: #84ce6a;
padding: 10px 20px;
visibility: hidden;
opacity: 0;
transition: visibility 0.24s, opacity 0.24s;
}
#menu.is-visible {
visibility: visible;
opacity: 1;
}
/*Demo only*/
.menu-open{
position: absolute;
}
.menu-open:nth-child(1) {top: 0; left: 0;}
.menu-open:nth-child(2) {top: 0; right: 0;}
.menu-open:nth-child(3) {bottom: 0; left: 0;}
.menu-open:nth-child(4) {bottom: 0; right: 0;}
<span class="menu-open">Click to open menu</span>
<span class="menu-open">Click me</span>
<span class="menu-open">Click here to open menu</span>
<span class="menu-open">Click to open menu</span>
<div id="menu">
<h3>This is my menu</h3>
<div id="menu-content"></div>
<button class="menu-close">CLOSE MENU</button>
</div>
<script src="//code.jquery.com/jquery-3.3.1.min.js"></script>
The above can be additionally improved by:
Make the menu perform on the "right side" similarily as on the left side - by first calculating if a point-flip is achievable (anchor the element on the opposite right-top, right-bottom or left-bottom corners), or otherwise-stick to far edge as it does now.
Fixing the Menu width / height if does not fit in viewport (Some additional CSS for menu content/body scrollbars might be necessary)

Related

How to set the window size on a div as oppose to the entire window? [jQuery]

Good day,
I've came across the following CodePen from Estelle Pasquin. I would like to add this Apple-like scroll effect to my website.
Getting this to work on my site is no problem. However I would like to place content above this animation and this is where the problem comes in.
Based on the above CodePen content is structured like this:
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Heading</h2>
<p>Content here</p>
</div>
However I need additional content above this animation section, like:
<div class="contentOne">
<h2>Heading 1</h2>
<p>Content here</p>
</div>
<div class="animationContent">
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
</div>
<div class="content">
<h2>Heading 2 </h2>
<p>More content here</p>
</div>
In other words:
User scrolls through website content
User gets to a content break section where they see this big image, scroll, see the nice animation
User continues scrolling through rest of site
However this existing code only works when placed at the top of the page. Like a hero image.
In the JS file is can see the following variable declarations:
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
My attempt
Looking at
var $window = $(window);
I can see the scroll is set on the window size. However I was thinking can't this be changed to a div. For example
var $window = $('#animationContent');
I would like this animation to work exactly as is just within a div placed on the page as opposed to being the first piece of content.
$(function() {
// cache all elements before we do anything
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
// define variables and prefill
var offset = $mac.offset();
var windowHeight = $window.height();
var windowTop = $window.scrollTop();
var scrollPercent = (offset.top - windowTop) / offset.top;
var scale = 'scale(' + scrollPercent + ')';
// listen to scroll
$window.on('scroll', function() {
windowTop = $window.scrollTop();
// hide intro if point is reached
if (windowTop >= 940) {
$intro.hide();
} else {
if (windowTop < 200 && windowTop > 100) {
// only perform in a 100px range
$h1.fadeOut(500);
}
$intro.show();
scrollPercent = (offset.top - windowTop) / offset.top;
scale = 'scale(' + scrollPercent + ')';
$intro.css({
'transform': scale
});
}
});
});
#import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,800);
body {
color: #333;
font-family: Open sans;
}
h1 {
position: fixed;
top: 50%;
transform: translateY(-50%);
width: 100%;
text-align: center;
font-size: 52px;
z-index: 999;
color: rgba(255, 255, 255, 0.3);
}
.mac {
height: 613px;
width: 764px;
margin: 1340px auto 100px;
background: white url("https://i.imgur.com/AyELvGR.jpg") no-repeat 0 0;
background-size: 764px 613px;
backface-visibility: hidden;
}
.mac.intro {
position: fixed;
width: 2548px;
height: 2052px;
background-size: 100% auto;
margin: 0;
top: 0;
left: 50%;
margin-top: -300px;
margin-left: -1274px;
transform-origin: 50%;
}
.content {
width: 500px;
margin: 0 auto 150px;
}
.content h2 {
font-size: 52px;
line-height: 1.0865;
font-weight: 300;
margin-bottom: 48px;
}
.content p {
font-size: 18px;
margin: 1em 0 0 0;
line-height: 1.8;
color: #555;
font-weight: 400;
}
.content p a {
color: #555;
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<h1>Just scroll!</h1>
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Apple iMac scrolling effect.</h2>
<p>
iMac 27" mockup by Koy Carraway.<br/> Picture from WallWideHD - Transfagarasan.<br/> Read more about Transfagarasan <a href="http://en.wikipedia.org/wiki/Transf%C4%83g%C4%83r%C4%83%C8%99an"
target="_blank">here</a>.
</p>
</div>

How to change the properties of a sticky up arrow button based on its position?

I have a sticky up arrow image for my webpage as follows:
HTML:
<img src = "images/sticky-btn-light.png" id = "myBtn" alt = "sticky-up-button">
And CSS:
#myBtn {
visibility: hidden;
position: fixed;
bottom: 50px;
right: 30px;
z-index: 99;
cursor: pointer;
padding: 15px;
border-radius: 10px;
width: 5%;
opacity: 0.5 ;
}
The button disappears when the user scrolls down and appears when the user scrolls up based on this JS code.
window.onscroll = function(e) {
console.log(this.oldScroll > this.scrollY);
if((this.scrollY == 0) || (this.oldScroll < this.scrollY) ){
document.getElementById('myBtn').style.visibility = 'hidden';
}
else if(this.oldScroll > this.scrollY){
document.getElementById('myBtn').style.visibility = 'visible';
}
this.oldScroll = this.scrollY;
}
Now, I want to change the color of the button based on its changing position on the screen. As I scroll the page, the sticky button will be in different sections as below.
If the sticky button is in Section A, it should be red. And if it is in Section B, it should be blue. Please note that it's the page that is moving, not the button. The button is in a fixed position.
For this, I need the id of the section in which the sticky button is overlapping at any given moment. Is there any way to get that information through JavaScript?
PS: I have adjusted the details to make things more clear. It's the page that is moving. So, if I use Element.getBoundingClientRect() for #myBtn, will I not get the same top/y values for that element wherever I scroll on the page?
You can use element.getBoundingClientRect() to get the x,y of the top left corner and the x,y of the bottom right corner of a element.
var arrow = document.getElementById('myBtn');
var arrowRect = arrow.getBoundingClientRect();
console.log(arrowRect.top, arrowRect.right, arrowRect.bottom, arrowRect.left);
var section = document.getElementById('section1');
var sectionRect = section.getBoundingClientRect();
console.log(sectionRect.top, sectionRect.right, sectionRect.bottom, sectionRect.left);
Then you can check collisions with the arrow and the section. In your case the x-axis doesn't matter:
// This checks if the arrow is touching the section
( arrowRect.bottom > sectionRect.top && arrowRect.top < sectionRect.bottom )
// This checks if the arrow isn't touching the section, then inverts it (faster)
!( arrowRect.bottom < sectionRect.top || arrowRect.top > sectionRect.bottom )
Here, I did an example for you to test and implement.
this will also help understand getBoundingClientRect even with fixed position
var arrow= document.getElementById('myBtn');
window.onscroll = function(e) {
var arrowBound = arrow.getBoundingClientRect();
var divs = document.querySelectorAll(".container > div");
divs.forEach(function(item){
var divBound = item.getBoundingClientRect();
var color= item.getAttribute("arrowColor");
if ( arrowBound.bottom > divBound.top && arrowBound.top < divBound.bottom )
{
arrow.style.borderTopColor = color
}
})
}
#myBtn {
position: fixed;
top: 10px;
left:270px;
z-index: 99;
cursor: pointer;
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid #f00;
}
.container{
width:300px;
height:800px;
z-index: 81;
}
.container > div {
width:300px;
height:100px;
border:1px solid black;
}
<div class="container">
<a id = "myBtn" href = "#navbar-scroll"></a>
<div arrowColor="red"> box red </div>
<div arrowColor="blue"> box blue </div>
<div arrowColor="green"> box green </div>
</div>
You can get coords of a html element with getBoundingClientRect() method, call this function and you'll get the Y coords of element (pixels), then you can use an if conditional
function getCoords(elem) {
let box = elem.getBoundingClientRect();
let body = document.body;
let docEl = document.documentElement;
let scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
let clientTop = docEl.clientTop || body.clientTop || 0;
return Math.round(box.top + scrollTop - clientTop);
}
if(getCoords(elem) > 100){
elem.className = 'your_class_name'
}
.your_class_name{
color: red;
}

how to increase speed of scrollmagic

Hey this is the plugin of Scrollmagic.io I am using this in my work.
But this is slow. How increase the duration time I want to change the content faster.
I looked at documentation but not much clear in docs.
Please help me out
//First the variables our app is going to use need to be declared
//References to DOM elements
var $window = $(window);
var $document = $(document);
//Only links that starts with #
var $navButtons = $("nav a").filter("[href^=#]");
var $navGoPrev = $(".go-prev");
var $navGoNext = $(".go-next");
var $slidesContainer = $(".slides-container");
var $slides = $(".slide");
var $currentSlide = $slides.first();
//Animating flag - is our app animating
var isAnimating = false;
//The height of the window
var pageHeight = $window.innerHeight();
//Key codes for up and down arrows on keyboard. We'll be using this to navigate change slides using the keyboard
var keyCodes = {
UP : 38,
DOWN: 40
}
//Going to the first slide
goToSlide($currentSlide);
/*
* Adding event listeners
* */
$window.on("resize", onResize).resize();
$window.on("mousewheel DOMMouseScroll", onMouseWheel);
$document.on("keydown", onKeyDown);
$navButtons.on("click", onNavButtonClick);
$navGoPrev.on("click", goToPrevSlide);
$navGoNext.on("click", goToNextSlide);
/*
* Internal functions
* */
/*
* When a button is clicked - first get the button href, and then slide to the container, if there's such a container
* */
function onNavButtonClick(event)
{
//The clicked button
var $button = $(this);
//The slide the button points to
var $slide = $($button.attr("href"));
//If the slide exists, we go to it
if($slide.length)
{
goToSlide($slide);
event.preventDefault();
}
}
/*
* Getting the pressed key. Only if it's up or down arrow, we go to prev or next slide and prevent default behaviour
* This way, if there's text input, the user is still able to fill it
* */
function onKeyDown(event)
{
var PRESSED_KEY = event.keyCode;
if(PRESSED_KEY == keyCodes.UP)
{
goToPrevSlide();
event.preventDefault();
}
else if(PRESSED_KEY == keyCodes.DOWN)
{
goToNextSlide();
event.preventDefault();
}
}
/*
* When user scrolls with the mouse, we have to change slides
* */
function onMouseWheel(event)
{
//Normalize event wheel delta
var delta = event.originalEvent.wheelDelta / 30 || -event.originalEvent.detail;
//If the user scrolled up, it goes to previous slide, otherwise - to next slide
if(delta < -1)
{
goToNextSlide();
}
else if(delta > 1)
{
goToPrevSlide();
}
event.preventDefault();
}
/*
* If there's a previous slide, slide to it
* */
function goToPrevSlide()
{
if($currentSlide.prev().length)
{
goToSlide($currentSlide.prev());
}
}
/*
* If there's a next slide, slide to it
* */
function goToNextSlide()
{
if($currentSlide.next().length)
{
goToSlide($currentSlide.next());
}
}
/*
* Actual transition between slides
* */
function goToSlide($slide)
{
//If the slides are not changing and there's such a slide
if(!isAnimating && $slide.length)
{
//setting animating flag to true
isAnimating = true;
$currentSlide = $slide;
//Sliding to current slide
TweenLite.to($slidesContainer, 1, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});
//Animating menu items
TweenLite.to($navButtons.filter(".active"), 0.5, {className: "-=active"});
TweenLite.to($navButtons.filter("[href=#" + $currentSlide.attr("id") + "]"), 0.5, {className: "+=active"});
}
}
/*
* Once the sliding is finished, we need to restore "isAnimating" flag.
* You can also do other things in this function, such as changing page title
* */
function onSlideChangeEnd()
{
isAnimating = false;
}
/*
* When user resize it's browser we need to know the new height, so we can properly align the current slide
* */
function onResize(event)
{
//This will give us the new height of the window
var newPageHeight = $window.innerHeight();
/*
* If the new height is different from the old height ( the browser is resized vertically ), the slides are resized
* */
if(pageHeight !== newPageHeight)
{
pageHeight = newPageHeight;
//This can be done via CSS only, but fails into some old browsers, so I prefer to set height via JS
TweenLite.set([$slidesContainer, $slides], {height: pageHeight + "px"});
//The current slide should be always on the top
TweenLite.set($slidesContainer, {scrollTo: {y: pageHeight * $currentSlide.index() }});
}
}
body, div, p {
margin: 0;
padding: 0;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
letter-spacing: 0.0625em;
}
a {
text-decoration: none;
}
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 100;
}
nav ul {
list-style: none;
text-align: center;
margin-top: 30px;
}
nav ul li {
display: inline-block;
margin-right: 20px;
}
nav ul li:last-child {
margin-right: 0;
}
#back-to-tutorial {
margin-left: 100px;
}
nav a {
position: relative;
top: 0;
padding: 10px 20px;
font-weight: normal;
font-size: 20px;
text-align: center;
border-radius: 4px;
background-color: #FFFFFF;
color: #83C78E;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
nav a.active {
top: -4px;
background-color: #69C773;
color: #FFFFFF;
-webkit-box-shadow: 0 4px 0 0 #51a65f;
-moz-box-shadow: 0 4px 0 0 #51a65f;
box-shadow: 0 4px 0 0 #51a65f;
}
.slides-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 10;
}
.slide {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.slide .centered {
width: 60%;
margin: 200px auto 0;
}
.slide .centered h1 {
text-align: center;
}
.slide .centered p {
text-align: center;
margin-top: 20px;
font-size: 20px;
}
#slide-1 {
background-color: #FFFFFF;
}
#slide-2 {
background-color: #45959b;
}
#slide-3 {
background-color: #778899;
}
#slide-4 {
color: #FFFFFF;
background-color: #291F37;
}
.go-prev, .go-next {
cursor: pointer;
font-weight: bold;
text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/plugins/CSSPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/plugins/ScrollToPlugin.min.js"></script>
<nav>
<ul>
<li>Slide 1</li>
<li>Slide 2</li>
<li>Slide 3</li>
<li>Slide 4</li>
</ul>
</nav>
<div class="slides-container">
<div class="slide" id="slide-1">
<div class="centered">
<h1>Fullscreen slides with GSAP</h1>
<p>Let's go to the <span class="go-next">next slide</span>.</p>
</div>
</div>
<div class="slide" id="slide-2">
<div class="centered">
<h1>It is so easy to navigate through slides</h1>
<p>You can go back to <span class="go-prev">previous slide</span> or go to the <span class="go-next">next slide</span>.</p>
</div>
</div>
<div class="slide" id="slide-3">
<div class="centered">
<h1>Use mouse wheel</h1>
<p>No, really. Try to scroll up and down with the mouse wheel to switch between slides.</p>
</div>
</div>
<div class="slide" id="slide-4">
<div class="centered">
<h1>... Or use keyboard arrows</h1>
<p>You go to previous and next slide, using up and down keyboard arrows.</p>
</div>
</div>
</div>
This is the link of scroll.io docs http://scrollmagic.io/docs/ScrollMagic.Scene.html#duration
How to apply this I bit confused please have a look
It's actually a TweenLite parameter: https://greensock.com/tweenlite
Change
TweenLite.to($slidesContainer, 1, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});
To a lower value, e.g.:
TweenLite.to($slidesContainer, 0.2, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});

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>

How do you create 3 adjustable divs?

What I want:
| A | | B | | C |
^ ^
When you move the handles left and right A, B, and C resize accordingly
| A | | B | | C |
What I have is the || between B and C sliding, but not resizing B and all I get on the other one is the resize cursor. Basically C is a curtain and covers A and B. I did get min size working for C.
| A | C |
I broke somebody else's perfectly good code to get this far:
var isResizing = false,
who='',
lastDownX = 0;
$(function () {
var container = $('#container'),
left = $('#left'),
right = $('#right'),
middle = $('#middle'),
hand2 = $('#hand2'),
handle = $('#handle');
handle.on('mousedown', function (e) {
isResizing = true;
who=e.target.id;
lastDownX = e.clientX;
});
$(document).on('mousemove', function (e) {
var temp, min;
// we don't want to do anything if we aren't resizing.
if (!isResizing)
return;
min=container.width() * 0.1;
temp = container.width() - (e.clientX - container.offset().left);
if (temp < min)
temp = min;
if (who == 'handle')
right.css('width', temp);
if (who == 'hand2')
left.css('width', temp);
}).on('mouseup', function (e) {
// stop resizing
isResizing = false;
});
});
body, html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
/* Disable selection so it doesn't get annoying when dragging. */
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: moz-none;
-ms-user-select: none;
user-select: none;
}
#container #left {
width: 40%;
height: 100%;
float: left;
background: red;
}
#container #middle {
margin-left: 40%;
height: 100%;
background: green;
}
#container #right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 200px;
background: rgba(0, 0, 255, 0.90);
}
#container #handle {
position: absolute;
left: -4px;
top: 0;
bottom: 0;
width: 80px;
cursor: w-resize;
}
#container #hand2 {
position: absolute;
left: 39%;
top: 0;
bottom: 0;
width: 80px;
cursor: w-resize;
}
<div id="container">
<!-- Left side -->
<div id="left"> This is the left side's content!</div>
<!-- middle -->
<div id="middle">
<div id="hand2"></div> This is the middle content!
</div>
<!-- Right side -->
<div id="right">
<!-- Actual resize handle -->
<div id="handle"></div> This is the right side's content!
</div>
</div>
Been playing with it here: https://jsfiddle.net/ju9zb1he/5/
I was looking for a solution that required less extensive CSS. It does have one minor bug(FIXED), but hopefully this should get you started. Here is a DEMO.
Also I aimed to use DOM Traversal methods like .next() and .prev() that way it wouldn't be so attribute dependent, and would be easily reusable if you needed a feature like this multiple times on a page.
Edit - Further Explanation
The idea here is onClick of a .handle we want to gather the total width (var tWidth) of the .prev() and .next() divs relative to the .handle in the DOM. We can then use the start mouse position (var sPos) to substract the amount of pixels we've moved our mouse (e.pageX). Doing so gives us the correct width that the .prev() div should have on mousemove. To get the width of the .next() div we need only to subtract the width of the .prev() div from the total width (var tWidth) that we stored onClick of the .handle. Hope this helps! Let me know if you have any further questions, however I will likely be unavailable till tomorrow.
HTML
<div class="container">
<div id="left"></div>
<div id="l-handle" class="handle"></div>
<div id="middle"></div>
<div id="r-handle" class="handle"></div>
<div id="right"></div>
</div>
CSS
#left, #middle, #right {
display: inline-block;
background: #e5e5e5;
min-height: 200px;
margin: 0px;
}
#l-handle, #r-handle {
display: inline-block;
background: #000;
width: 2px;
min-height: 200px;
cursor: col-resize;
margin: 0px;
}
jQuery
var isDragging = false,
cWidth = $('.container').width(),
sPos,
handle,
tWidth;
$('#left, #middle, #right').width((cWidth / 3) - 7); // Set the initial width of content sections
$('.handle').on('mousedown', function(e){
isDragging = true;
sPos = e.pageX;
handle = $(this);
tWidth = handle.prev().width() + handle.next().width();
});
$(window).on('mouseup', function(e){
isDragging = false;
});
$('.container').on('mousemove', function(e){
if(isDragging){ // Added an additional condition here below
var cPos = sPos - e.pageX;
handle.prev().width((tWidth / 2) - cPos); // This was part of the bug...
handle.next().width(tWidth - handle.prev().width());
// Added an update to sPos here below
}
});
Edit
The bug was caused by 2 things.
1) On mousemove we were dividing the total width by two, instead of an updated mouse offset.
2) The sPos was not updating on mousemove, and stayed a static number based off of the click location.
Resolution
Update the sPos on mousemove that way the mouse offset is accurately based off of the previous mousemove position, rather than the click position. When this is done we can then subtract the .next() div's width from the total width. Then we subtract our current mouse position from the remaining width. The fiddle has been updated as well.
$('.container').on('mousemove', function(e){
var cPos = sPos - e.pageX;
if(isDragging && ((tWidth - handle.next().width()) - cPos) <= tWidth){
handle.prev().width((tWidth - handle.next().width()) - cPos);
handle.next().width(tWidth - handle.prev().width());
sPos = e.pageX;
}
});
Edit
Added an additional condition on mousemove to prevent the drag from exceeding the total width (var tWidth).
Can you please explain what you're trying to accomplish?
I don't believe you need to use position: absolute. The premise of absolute positioning is to override the margin and padding imposed on an element by its parent.
You don't need to do this, all elements have relative positioning by default which makes them push eachother around and don't allow overlapping.
I'm probably missing something, but I think this is what you want with nothing but some very basic CSS: http://jsfiddle.net/3bdoazpk/
<div class='first'>
asdf
</div><div class='second'>
dasdf
</div><div class='third'>
sadf
</div>
body {
margin: 0;
}
div {
display: inline-block;
height: 100%;
}
.first, .third {
width: 40%;
}
.first {
background-color: red;
}
.second {
background-color: blue;
width: 20%;
}
.third {
background-color: green;
}

Categories

Resources