How to disable scroll left? - javascript

I got a div element ("#parent") that includes multiple child elements (".item"). I want to enable scrolling the parent element just in one direction (left OR right). Otherwise nothing should happen.
See my code:
$("#parent").scroll(function() {
// >>> scroll event
// >>> console.log("SCROLLED " + new Date().getMilliseconds())
})
#container {
position: absolute;
width: 100%;
height: 100%;
}
#parent {
position: relative;
width: 90%;
height: 40%;
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
background: red;
}
.child {
display: inline-block;
position: relative;
margin-left: 3%;
width: 40px;
height: 40px;
background: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
<div class="child">9</div>
<div class="child">10</div>
<div class="child">12</div>
<div class="child">13</div>
<div class="child">14</div>
<div class="child">15</div>
<div class="child">16</div>
<div class="child">17</div>
<div class="child">18</div>
<div class="child">19</div>
<div class="child">20</div>
</div>
</div>
So to my question: I'd like to disable scrolling the element to the right hand side (backwards). I'd like to just enable the scroll of the items to the left hand side (forward).
How can I use jQuery to implement this method? Any help would be very appreciated. Thanks in advance!

The following code should do the job1.
previousX stores the last position that the element was scrolled to on the X axis.
When the scroll event triggers, newX is set to the scrollLeft() value (this returns how far the element has been scrolled from it's left-most side, in pixels).
If this value is greater than previousX, then they have scrolled to the right, so we allow the scroll, and update previousX to the new x value.
If the value is lesser than previousX, they have scrolled to the right - so we need to cancel the scroll. To do this, we can use the scrollLeft() function again - but this time, we provide a value to it - this allows us to set the scroll position; rather than retrieve it. By setting it to previousX, we can prevent the scroll.
Note that if the value is equal, we do nothing.
let previousX = -1;
$("#parent").scroll(function(e){
let newX = $("#parent").scrollLeft();
if (newX>previousX) {
previousX = newX;
}
else if (newX<previousX) {
$("#parent").scrollLeft(previousX);
}
})
#container {
position: absolute;
width: 100%;
height: 100%;
overflow:hidden;
}
#parent {
position: relative;
width: 90%;
height: 40%;
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
background: red;
}
.child {
display: inline-block;
position: relative;
margin-left: 3%;
width: 40px;
height: 40px;
background: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
<div class="child">9</div>
<div class="child">10</div>
<div class="child">12</div>
<div class="child">13</div>
<div class="child">14</div>
<div class="child">15</div>
<div class="child">16</div>
<div class="child">17</div>
<div class="child">18</div>
<div class="child">19</div>
<div class="child">20</div>
</div>
</div>
1: Unfortunately, it doesn't seem to work at all when I use it with my Magic Trackpad - but when dragging the scroll bars it works just fine. I haven't tested it on a touch-screen device / Windows / using a proper mouse & scroll wheel, so I don't know how it behaves in those cases either. It would definitely be worth you doing some proper testing / improving this code, as it probably will not work in all cases, or even catch all possible scroll events.

Related

How to re-create Facebook image modal?

I want to create something almost exactly like the Facebook image modal wherein the image is fixed while a user scrolls through the comments. I am messing with different ways to apply overflow: hidden to one div and overflow: scroll to the other. I even looked into applying it to their parent. Here is the code I've tried:
<div class="row container border border-primary">
<div class="image col border">
Image
</div>
<div class="text-section col border">
Comments
</div>
</div>
div.image {
height: 300px;
overflow: hidden;
}
div.text-section {
height: 1000px;
overflow: scroll;
}
div.container {
height: 300px;
}
Plunkr
I supposed a code like this. The blue (image) remains fixed on the left, while you can scroll the green section (comments) on the right
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
#container { background: red; width: 400px; height: 150px; display: flex; }
#image { background: url("https://i1.adis.ws/i/canon/canon-pro-best-landscape-lenses-1-1140?w=200&aspect=4:3&qlt=70&sm=aspect&fmt=jpg&fmt.options=interlaced&fmt=jpg&fmt.options=interlaced&bg=rgb(255,255,255)"); width: 200px; height: 150px; }
#comments { background: #eee; width: 200px; overflow: scroll; padding: 0 10px 20px 10px; font-family: Verdana; color: black; }
</style>
</head>
<body>
<div id="container">
<div id="image"></div>
<div id="comments">
<h3 style="color: red;">Comments</h3>
<p>Nice!</p>
<p>Good!</p>
<p>Wonderful</p>
<p>Bah...</p>
<p>Strange</p>
<p>Nice again</p>
<p>Amazing</p>
<p>Beautiful</p>
<p>Great</p>
<p>I don’t like it</p>
<p>Yes, nice</p>
<p>Super</p>
<p>Normal</p>
<p>Ok...</p>
<p>Nice</p>
<p>Bah</p>
<p>Great</p>
<p>Nice</p>
<p>I like it</p>
<p>Normal</p>
</div>
</div>
</body>
</html>
I don't have facebook so cant look at the behaviour, but you could put position: sticky; on the image container, that will keep it in place. It also depends on your browser support, like ie11 does not support it, but there are more ways to do this. Let me know if you need a more cross browser solution.
.container {
max-height: 600px;
height: 100%;
overflow: auto;
position: relative;
}
div.image {
height: 300px;
background-color: deepskyblue;
position: sticky;
top: 0;
}
div.text-section {
height: 1000px;
background-color: aqua;
}
<div class="row container border border-primary">
<div class="image col border">
Image
</div>
<div class="text-section col border">
Comments
</div>
</div>

How to prevent scroll direction?

Note: This question is an update to How to disable scroll left?.
I'd like to get an div-element that is just scrollable into ONE directions (in my case only "right"). Scrolling to the left direction should get canceled.
I've developed some jQuery code that should be able to prevent the scrolling in the unwanted direction, what kind of is working so far!
But I got some issues because scrolling to the prevented direction obviously looks super sticky & ugly.
let value = $("#parent").scrollLeft()
$("#parent").scroll(function(e) {
let direction = (this.scrollLeft > value) ? 'right' : ((this.scrollLeft === value) ? false : 'left');
console.log(direction)
if (direction == "left") {
this.scrollLeft = value;
e.preventDefault();
e.stopPropagation();
}
value = $("#parent").scrollLeft()
})
#container {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
#parent {
position: relative;
width: 90%;
height: 80%;
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
background: red;
}
.child {
display: inline-block;
position: relative;
margin-left: 3%;
width: 40px;
height: 40px;
background: gray;
}
.as-console-wrapper {
height: 20px!important;
}
.as-console-row {
background: green!important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
<div class="child">9</div>
<div class="child">10</div>
<div class="child">12</div>
<div class="child">13</div>
<div class="child">14</div>
<div class="child">15</div>
<div class="child">16</div>
<div class="child">17</div>
<div class="child">18</div>
<div class="child">19</div>
<div class="child">20</div>
</div>
</div>
Have a look: Scrolling back looks super ugly:
How to fix this?

Sticky floating bar : accurate position

I am looking for a better solution to sticky bar issue.
The '-----' between 2nd & 3rd box is a threshold from where the sticky bar should get display. When its displayed, it overlaps the 3rd box completely.
In the real solution, I have added css (margin-top) using jquery to push this element below; but the problem is it's lagging in Firefox. One can see this space for fractions of seconds on UI.
What is the best solution to achieve the output ( or avoid margin-top) ?
$(document).ready(function(){
function toggleDock() {
if($(window).scrollTop() >= $('.second').offset().top+$('.second').height()) {
$('.sticky').show();
}
else {
$('.sticky').hide();
}
}
$(window).bind('scroll',toggleDock);
});
.box {
border: 1px dotted red;
height: 100px;
width: auto;
margin: 20px 0;
}
.sticky {
height: 80px;
border: 1px dotted green;
margin: 20px 0;
display: none;
position: sticky;
top: 20px;
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body class='page docked'>
<div class='sticky'>
</div>
<div class='box'>
First
</div>
<div class='box second' >
2nd
</div>
-------
<div class='box'>
3rd
</div>
<div class='box'>
4th
</div>
<div class='box'>
5th
</div>
<div class='box'>
6th
</div>
<div class='box'>
7th
</div>
<div class='box'>
8th
</div>
</body>
UPDATED ANSWER
I think you need to keep your sticky div in the normal flow, and position: sticky is probably not the right choice here. Here is an example :
$(document).ready(function(){
function toggleDock() {
if($(window).scrollTop() >= $('.second').offset().top+$('.second').height()) {
$('.sticky').show();
}
else {
$('.sticky').hide();
}
}
$(window).bind('scroll',toggleDock);
});
.box {
border: 1px dotted red;
height: 100px;
width: auto;
margin: 20px 0;
}
.sticky {
height: 100px;
border: 1px dotted green;
margin: 20px 0;
top: 40px;
display: none;
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body class='page docked'>
<div class='box'>
First
</div>
<div class='box second' >
2nd
</div>
-------
<div class='sticky'>
</div>
<div class='box'>
3rd
</div>
<div class='box'>
4th
</div>
<div class='box'>
5th
</div>
<div class='box'>
6th
</div>
<div class='box'>
7th
</div>
<div class='box'>
8th
</div>
</body>
A nice document about CSS flow : http://marksheet.io/css-the-flow.html
position: sticky is not detailed there, but from this document, you'll see that a sticky element is positioned relatively to its containing element when it's visible, and becomes fixed (that is, it is taken out of the normal document flow) when its containing element is not visible :
A stickily positioned element is an element whose computed position value is sticky. It's treated as relatively positioned until its containing block crosses a specified threshold, at which point it is treated as fixed.
Hope this helps!
This is due to position: sticky. Using position: fixed alternatively will help you.
.sticky {
height: 80px;
border: 1px dotted green;
margin: 20px 0;
display: none;
top: 20px;
background: green;
position: fixed;
width: calc(100% - 40px); /* subtract the 20px taken by the left and right margins */
}

DIV centered when other div removed

I have two div's next to each other - left one and right one.
There is possibility, that the right one will be gone, then i want the left one to be centered.
HTML
<div class="contener">
<div class="left"></div>
<div class="right></div>
</div>
CSS:
.left {
width: 75%;
height: 240px;
float: left;
}
.right {
width: 25%;
height: 250px;
float: right;
}
.contender{
text-align:center;
}
.left {
width: 75%;
height: 240px;
text-align:left;
display:inline-block;
zoom:1;
*display:inline;
}
.right {
width: 25%;
height: 250px;
text-align:left;
display:inline-block;
zoom:1;
*display:inline;
}
the asterisk(*) is used to fix ie7 so it's a bit of a hack.
You can set the display property of .left and .right to inline-block and set the text-align:center for the parent element as jayaguilar pointed out. However, not that this won't work with the exact html and css you've.
You need to either remove the line break between inline elements in your html markup as follows:
<div class="container">
<div class="left"></div><div class="right"></div>
</div>
or comment it out
<div class="container">
<div class="left"></div><!--
--><div class="right">
</div>
or reduce their width to something less than 100% in order to accommodate the whitespace after inline-block elements.
Demo (click the remove button)
<div class="contener">
<div class="left"></div>
<div class="right"></div>
</div>
And now some easy jQuery:
$(".right").click(function() {
$(this).hide();
$(".left").css({ 'text-align': 'center'});
});
So with that we make "desapear" the right one, and then you do what you want with the left one! :)

How to get exact width of flexbox by getComputedStyle?

I have a problem to get exact width of flexbox after rendering contents.
I am working on a Windows 8 application (mean ie10 specific).
Here is the code:
[HTML]
<html>
<head>
<title>flexbox test</title>
</head>
<body>
<div class='container'>
<div class='viewport'>
<div class='canvas'>
<div class="item"> A </div>
<div class="item"> B </div>
<div class="item"> C </div>
<div class="item"> D </div>
<div class="item"> E </div>
<div class="item"> F </div>
<div class="item"> G </div>
<div class="item"> H </div>
<div class="item"> I </div>
<div class="item"> J </div>
</div>
</div>
</div>
<hr style="width: 600px; text-align: left;">
<div class="outbox"></div>
<script>tester();</script>
</body>
</html>​
[CSS]
.container {
width: 400px;
height: 200px;
border: 1px solid black;
}
.container .viewport {
width: inherit;
height: inherit;
position: absolute;
overflow: auto;
}
.container .viewport .canvas{
display: -ms-flexbox;
-ms-flex: 0 0 auto;
-ms-flex-pack: start;
-ms-flex-flow: row none;
-ms-flex-align: start;
-ms-flex-item-align: start;
-ms-flex-line-pack: start;
position: relative;
}
.container .viewport .canvas .item {
width: 100px; height: 100px;color: #fff;
background-color: black;
margin: 10px;
}
[JAVASCRIPT]
(function tester(){
var canvas = document.querySelector('.canvas');
var style = document.defaultView.getComputedStyle(canvas, null);
function addToOutbox(str){
var outbox = document.querySelector('.outbox');
outbox.innerText = 'Width: ' + str;
}
addToOutbox(style.width);
})();
I was expecting width to be something else as there is a scroll bar.
Outer container width is 400px, middle one is inheriting width and height with overflow: auto and inner most is expandable.
There are eight items in flexbox with width and height 100px each. So I was expecting the flexbox width abot 900px (i.e. 100px*8 + margin-left and margin-right for each item) but still getting 400px only which is parent dimensions. Am I missing something?
Here is the link to JS Fiddle: http://jsfiddle.net/pdMSR/ [Open with ie10 only]
The element really is 400px. The flex items that are positioned past 400px are actually overflowing.
It sounds like what you are really trying to get is the scrollWidth. If you pass in canvas.scrollWidth to your addToOutbox function you'll get what you are looking for.

Categories