Basically, I've created some kind of Autolog which has a scrollable DIV using the CSS code below
.myClass {
position: relative;
padding: 39px 14px 14px;
margin-bottom: -1px;
border: 1px solid #ddd;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
height: 200px;
overflow: auto;
}
Basically, data is being placed inside this div dynamically using JQuery as shown below which is fetched from an external source
$.each(data.search, function (i, v) {
$('.myClass').append('my content here');
});
The div is looks as simple as this
<div class="myClass">
</div>
What i want the div to do, is as the content is becoming overflow i want the scrollbar at the side to automatically scroll to the bottom to follow the AutoLog instead of having to manually keep scrolling the bar to the bottom yourself, I'm sure this can be acheived via Javascript but not sure how, if anyone could point me in the right direction that'd be great,
I recently did something similar, where I had a "console" (a div) I was printing to and when it overflowed, you followed it down. here was my "println" function:
printLn: function(str, clss) {
con.print(str, clss);
$output.append('<br/>').animate({ scrollTop: $output.prop('scrollHeight') }, 1);
},
Basically update scrollTop to the new scrollHeight, which more or less says "scroll as far as the scroll height allows" so you "stick" to the bottom.
EDIT
For your situation doing something like:
$.each(data.search, function (i, v) {
$div = $('.myClass');
$div.append('my content here').animate({ scrollTop: $div.prop('scrollHeight') }, 1);
});
This sets the scrollTop property of your div to the max, so it will scroll to the bottom.
Add this to your script after appending content and it should work ..
$(".myClass").animate({
scrollTop: $(".myClass").scrollHeight
}, 300);
// Get the number of pixels scrolled
var intElemScrollTop = element.scrollTop;
intElemScrollTop is an integer corresponding to number of pixels that element's content has been scrolled upward.
// Set the number of pixels scrolled
element.scrollTop = intValue;
check the link https://developer.mozilla.org/en-US/docs/DOM/element.scrollTop
Related
I'm creating a secondary view that will pop-up on clicking on a link. Content within this secondary view is vertically scrollable and horizontally fixed. The issue is: when scroll reach to the top/bottom of the secondary view, the background page will scroll as well, also if attempt to scroll left/right, the background page will also scroll.
I did some search online but mostly suggest to modify the body css. Due to project constraint, we are not allowed to modify any attribute on body. So I'm trying to find a solution without making css change.
I was trying to achieve using this approach:
secondaryView.addEventListener('wheel', (event) => {
if (//mouse scroll up and secondaryView is at top
|| //mouse scroll down and secondaryView is at bottom
|| //mouse scroll left or right) {
event.preventDefault();
}
});
However, the problem is I don't know how to detect whether mouse scroll is horizontal, not able to rely on event.deltaX since it will be non-zero sometimes when scrolling up or down as well.
This problem has a lot of solutions (see this huge Q&A for options), one of which is listening for scroll event instead of the wheel one (after all, you do not want to be limited to mouse wheel, do you?).
The easiest version (given that for some reason you cannot modify styling) is to keep track of the last known scroll position of the primary view (or the window) and as soon as the secondary view is shown (a boolean flag should suffice), start snapping the primary to it with scrollTo.
The rest depends on your exact requirements - if you need the primary to be scrollable while the secondary is open, things become complex (a solution for mouse-based devices may be to track cursor position to determine what is scrolled).
(() => {
const p = document.getElementById("primary");
const s = document.getElementById("secondary");
const b = document.getElementById("show");
let secondaryShown = false;
b.addEventListener("click", () => {
if (secondaryShown) {
s.classList.remove("shown");
secondaryShown = false;
return;
}
s.classList.add("shown");
secondaryShown = true;
});
let lknownYPos = window.scrollY,
lknownXPos = window.scrollX;
window.addEventListener("scroll", ({
target,
currentTarget
}) => {
if (secondaryShown) {
window.scrollTo(lknownXPos, lknownYPos)
}
lknownWindowPos = window.scrollY;
}, true);
})();
body {
margin: 0;
}
.subcontent {
height: 300vh;
width: 300vw;
}
#primary {
width: 200vw;
height: 200vh;
}
#secondary {
overflow-x: scroll;
width: 50vw;
height: 50vh;
background-color: rgba(0, 0, 0, 0.25);
z-index: 9999;
color: white;
display: none;
font-size: 2rem;
text-align: center;
}
.shown {
display: block !important;
}
<div class="content">
<div id="primary">
<button id="show">Switch secondary</button>
<div id="secondary">
<p>Secondary</p>
<div class="subcontent"></div>
</div>
</div>
</div>
I have this page (https://www.datacoral.com/architecture/) that has a left sidebar with five bullet points. What I want to happen is as the user scrolls past these five div's on the right hand column, the text in one of these bullet points adds a class called 'bolder' and the text become a font-weight of 700 to let the user know what point they are in on the page. As the pass by that same div, the class disappears and ends up in the next bullet point since you're now passing by another div.
I've got it partially working but it's not hitting the right point of the div at all. Seems to add the class as you are passing the bottom of the div instead of the top.
This is the code I'm currently working with. Anyone know what I might be doing wrong so this can function properly?
Note: Should mention I'm basically duplicating this code five times and just swapping out the numbers.
jQuery(function(){
jQuery(window).scroll(function() {
var scroll = jQuery(window).scrollTop(); // how many pixels you've scrolled
var os = jQuery('#guide_body-0').offset().top; // pixels to the top of div1
var ht = jQuery('#guide_body-0').height(); // height of guide_body-0 in pixels
if(scroll > os + ht){
jQuery('.scroll-nav-0').addClass('bolder');
}
});
});
I think firing a function on scroll like that gets a little bit crazy. I always delay the function until the scrolling has stopped.
As far as the catch point, i think your code is applying the classes when the element has moved out of view. i would use the bottom of the browser screen as a reference point.
Think about it like this:
$(window).scrollTop() returns 0 at the top of the page.
$('#guide_body-0').offset().top returns 1000px.
So $(window).scrollTop() is equal to $('#guide_body-0').offset().top when that element is at the top of the screen.
Add $('#guide_body-0').height() to the equation and that puts the scroll position (the top of the screen) at the bottom of the element.
What you need to do is check if the offset.top property of the element is in a scroll position which puts it above the bottom of the screen.
UPDATE
The code here is for a custom solution. But if you are looking for a way to just add simple animations to elements as they scroll into view, check out wow.js and animate.css
https://wowjs.uk/
https://animate.style/
// Init variable for timer
let timer;
// Get target element
const el = $("#4");
// Get viewport height
const screen = window.innerHeight;
// Fire callback on window scroll
$(window).scroll(function() {
// Clear timeout just in case
clearTimeout(timer);
// Check if the element already has the class
if (!el.hasClass("active")) {
// Set a delay timer then run the function
timer = setTimeout(check_el_pos, 300);
}
});
function check_el_pos() {
// Clear the timer
clearTimeout(timer);
// Get current scroll position
let scroll_pos = $(window).scrollTop();
// This is the math here. Add scroll position to screen height and you get the bottom of the screen. When that value equals the top offset of the element, we are there.
if (scroll_pos + screen > el.offset().top) {
console.log(scroll_pos + screen);
console.log(el.offset().top);
// Add the classes to the element. Boom, we're done.
el.removeClass("active").addClass("active");
}
}
body,
html {
padding: 0;
margin: 0;
}
.example-grid {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
display: grid;
grid-gap: 40px;
}
.example-grid>li {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
height: 65vh;
background: slategray;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: #fff;
font-size: 2em;
line-height: 1em;
transition: background-color 1s;
transition-timing-function: ease-out;
}
.example-grid>li:nth-child(even) {
background: coral;
}
.example-grid>li.active {
background: aquamarine;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="example-grid">
<li id="1">1</li>
<li id="2">2</li>
<li id="3">3</li>
<li id="4">4</li>
<li id="5">5</li>
<li id="6">6</li>
<li id="7">7</li>
</ul>
I am currently coding a simple MENU button that is fixed in the top right of the screen.
With the text it is normally Black, but I want to be able to change the text to White when it is within a certain Div on a page so it is still visible on the dark background images.
I had set up two .CSS classes and tried to get them to switch on scroll but I cannot figure it out.
Anyone know how I can achieve this result?
HTML
<div class="NavigationButton menu_white">
MENU
</div>
CSS
.NavigationButton {
position: fixed;
top: 5%;
right: 5%;
z-index: 99999;
font-family: neuzeit-grotesk, sans-serif;
font-weight: 700;
color: inherit;
}
.menu_white {
color: #fff;
}
.menu_black {
color: #000;
}
(Not My Site) Example site: http://flavinsky.com/home/amaio
Just without the snap scroll
Thanks
You can use jQuery to get the scroll position and toggle the classes based on where the dark background element is. Here is an example
$(document).ready(function(){
$(window).scroll(function(){
var light_pos = $('#white_div').offset().top;
var light_height = $('#white_div').height();
var menu_pos = $('.NavigationButton').offset().top;
var scroll = $(window).scrollTop();
if(menu_pos > light_pos && menu_pos < (light_pos + light_height)) {
$('.NavigationButton').addClass('menu_black');
$('.NavigationButton').removeClass('menu_white');
}
else {
$('.NavigationButton').removeClass('menu_black');
$('.NavigationButton').addClass('menu_white');
}
})
})
and here is a working fiddle https://jsfiddle.net/atqkuwhs/
A possible solution is to get the offset of the div and the menu from the top of the page and apply your wanted changes once they intersect.
I have an HTML video player with Javascript generated controls(with background images of SVG graphics). I'm having an issue using the css calc() function, and need to resize the div's based on the video controls bar. So when the window is expanded/contracted, the controls need to adjust accordingly.
The controls div:
//Controls Wrapper
videoObj.controlsWrapper = document.createElement("div");
videoObj.controlsWrapper.className = "video-controls";
The controls are generated dynamically, so for instance, the play button is generated by this:
videoObj.playBtn = document.createElement("button");
videoObj.playBtn.className = "play btn";
So the question is how to adjust the size of the play button(which is a background of an SVG graphic), to a percentage(about 25%) of the height of the controls wrapper div.
jsfiddle
This is the easiest way... try resizing the box :)
The parent is relative. The child is absolute. Setting the top, left, right and bottom all to 0 will actually create a spider web effect ( or stretch effect ). I used different pixels so you could see the reaction. otherwise the child will cover the parent. Hope this helps.
http://jsfiddle.net/m5wm1rLs/
.parent{
position: relative;
width: 100px;
height: 100px;
background-color: red;
}
.child{
position: absolute;
top: 3px;
bottom: 20px;
left: 3px;
right: 20px;
background-color: green;
}
<div class="parent">
<div class="child"></div>
</div>
To test that this works, you can make parent resizable:
$('.parent').resizable();
Resizing it to 25% of the parent div height is relatively easy, but only doable with a scripting language. As far as CSS has come by allow calc(), it has no support for pulling the sizes of designated elements.
Here's a simple script I threw together for you:
window.onload = function() {
resize();
}
window.onresize = function() {
resize();
}
function resize() {
document.getElementsByClassName('play')[0].style.width = (document.getElementsByClassName('timeline')[0].offsetHeight * .25) + 'px';
}
JSFiddle: http://jsfiddle.net/zq2vzkk5/
I recommend you use ids to identify the elements you want to pull the values from, but if the positions of the elements won't change on the page, then classes are fine. You just have to update which instance of the class you want to pull the value from if it does change.
If you want a jQuery variation, I can supply that, too.
I hope this helps.
Edit:
Here's the jQuery variation:
$(function() {
resize();
$(window).resize(function() {
resize();
});
});
function resize() {
$('.play').first().width($('.timeline').first().outerHeight() * .25);
}
JSFiddle: http://jsfiddle.net/s51vrca2/
You can do this without JS :
.play {
height: 25%;
}
I have a .wall div with a some .toy divs inside it. I want to arrange the toys inside the wall. float:left property has done it for me nicely.
Now the problem is I want to add position:absolute for the toy divs to make it draggable later. How can I do this either via Javascript or via CSS?
Applying position:absolute, all toys will come to the top left corner of the wall overlying and hiding each other.
The width and height of the wall is constant but the width and height of the toys is variable, also the number of toy divs is dynamic and as the number increases toys need to arrange as rows.
Any suggessions will be helpful, please note the I can not avoid the use of position:absolute for dragging.
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<style>
body{
text-align:center;
}
.clearfix{
clear:both;
}
.wall {
border: 5px solid #cde;
margin:auto;
width:200px;
padding:10px;
}
.toy{
background-color: #BBCCEE;
border:1px solid #8899BB;
margin:5px;
width: auto;
padding:5px;
float:left;
}
.tall{
padding-top:10px;
}
</style>
<script>
$(document).ready(function() {
$('.toy').each(function(index) {
var position = $(this).offset();
var prevPosition = $(this).prev().offset();
$(this).css({
//top: position.top,
//left:position.left,
//position:'absolute',
});
});
});
</script>
<div class='wall'>
<div class='toy'>T1</div>
<div class='toy'>T2</div>
<div class='toy'>T3333333</div>
<div class='toy'>T4</div>
<div class='toy'>T5</div>
<div class='toy tall'>T6</div>
<div class='toy'>T7</div>
<div class='toy'>T8</div>
<div class='clearfix'></div>
</div>
Here is the code at JSBin.
Add
position:relative
To the wall div
I am working on a website that does exactly that (sorry for the non-english stuff):
http://moveit.canassa.com/cartao/4/
The link is now broken but here is a jsFiddle that shows what I am talking about:
http://jsfiddle.net/canassa/Z9N3L/
The "toy" div is using a position absolute:
.toy{
width: 100px;
height: 25px;
position: absolute;
z-index: 0;
}
The problem with the position absolute is that the toy will be relative to page and not the "wall" container, in order to fix that you must make the wall container relative:
#wall{
position: relative;
overflow: hidden;
}
The overflow:hidden is also a nice trick that I found. It makes the draggable objects go "under" the wall container.
There is no big secret to make it draggable, using jQuery:
// Creates a toy div inside the wall
$(MV.wallId).append('<div class="toy" id="' + this.getId() + '"></div>');
box = this.getBox(); // return the "toy" that I've just created.
$('#' + this.getId()).draggable(); // make it draggable
This would be a lot easier if you just used the jQueryUI .draggable(). It doesn't require the elements to be positioned.
If you're dead set on using this plugin, then you have the right idea. Let the elements flow into place and then calculate their position and set position: absolute and whatever the left and top end up being at runtime.
Set the .wall to be position: relative. Then:
var tPos;
$('.toy').each(function(index) {
tPos = $(this).position();
$(this).css({
left: tPos.left,
top: tPos.top
});
};
$('.toy').css({
position: absolute
});
The height of the .wall and the width of each .toy collapse when the toys are absolutely positioned but you can just add a few more lines to get/set their width and height in the above .each loops.
This obviously doesn't work if new toys can be added dynamically without a page reload as you suggest. To handle that you could switch them back to position: relative, add the new one, get the position of the new one in the flow, then set the position and switch back to position: absolute. Any elements that had been dragged out of place would be gaps in the flow, but I don't see any easy way around that.
the element in that the absolute should be positioned, must have the style position:relative.
(must be a parent of the target element)
The container div for every .toy must have position:relative set. That way, the position 0 for its children elements becomes its top left corner. Like this:
<div class="parent">
<div class="child">Blah.</div>
<div class="child">Blah.</div>
</div>
And:
.parent {
position: relative;
}
.child {
position: absolute;
left: 10px; /* This is 10 pixels from the parents left side */
top: 10px; /* This is 10 pixels from the parents top side */
}
Good luck.