I want make a moving infinite text like this text(We are trusted by over 28,000...) in this link . I already tried something but I have not reached exactly what I want. It is close but not infinite.
<h1 class="deneme display-1 " id="movingtext">We are trusted by over 28,000 clients to power stunning websites.We are trusted by over 28,000 clients to power stunning websites.</h1>
window.addEventListener('scroll', () => {
var elemen = document.getElementById("movingtext");
elemen.style = "left:-450px"
var rect = elemen.getBoundingClientRect();
var rect1 = rect.left;
var scrolled = window.scrollY;
var deg = (rect1 + scrolled) / 1.8;
elemen.style = "left:" + deg + "px";
console.log(rect.left, rect.right);
})
As you can see in the following screenshots this is not infinite either:
first row with "We are trusted by over 28,000..."
and second row
It's just that on normal screen you can't reach the end of the element.
You can accomplish something similar by adding an listener on scroll and transforming the element you want to be moved retative to window.pageYOffset value.
Something like:
window.addEventListener('scroll', () => {
const movingtext = document.getElementById("movingtext");
const scrolled = window.pageYOffset;
//feel free to play with this value to change the speed of the transform ( the `* 3` part)
const left = scrolled * 3;
movingtext.style.transform = `translate3d(-${left}px, 0px, 0px)`;
})
.wrapper {
height: 300vh;
padding-top: 100vh;
max-width: 100vw;
overflow: hidden;
}
.infinite-text {
display: inline-block;
overflow: hidden;
white-space: nowrap;
}
<div class="wrapper">
<h1 class="infinite-text" id="movingtext">We are trusted by over 28,000 clients to power stunning websites.We are trusted by over 28,000 clients to power stunning websites.</h1>
</div>
Please note that this is a draft. You might want to play with sizes and speed of transform or other attributes.
Please note that for this example the container has max-width: 100vw; and overflow: hidden (so it won't display a scrollbar for the element that is bigger than the screen), and the element itself has white-space: nowrap;
Related
I'm trying to emulate a nice scrollbar that i saw on the website https://doughellmann.com/blog/. (You must be on a screen bigger than 955px to view the sidebar) However, my sidebar is fixed and if it overflows in the y direction a side bar appears so on the screen you have two scroll bars - One for the sidebar and the other for the page. However, I don't want that. I want the user to go the bottom of the sidebar and then fix it self like it did on this webiste. Here's how my code looks right now
.sidebar{
display: block;
background-color: #1056b1;
width: 30%;
height: 100%;
position: fixed;
display: flex;
flex-direction: column;
align-items: center;
overflow-y: scroll;
}
.content-on-the-right{
margin-left: 31%;
}
Does anybody know how i could solve this problem using vanilla javascript or reactjs or even css if that's possible?
I'm sure there's a more efficient way to do this but I believe this will get you started on getting what you want. For this example, let's say your sidebar has an id of sidebar.
When the window loads, you can add an EventListener that will call a function that will check the elements offsets. You can take it from there:
window.addEventListener("scroll", DoScroll, false);
function DoScroll() {
var sidebar = document.getElementById('sidebar');
var sidebarHeight = document.getElementById('sidebar').offsetHeight;
var winHeight = window.innerHeight;
var offset = sidebarHeight - window.pageYOffset;
if (offset < winHeight) {
sidebar.style.position = "fixed";
sidebar.style.bottom = 0;
} else {
sidebar.style.position = "static";
}
}
Here's my JSFiddle that demos this.
P.S. I know the name of the function kinda sucks but am a bit burned out... you can give it a more descriptive name.
I have a music player with an animated bar that displays the current position in the song. It is rendered with requestAnimationFrame and works by changing the width style of the div to X%, where X is the percentage of time through the current song.
This causes huge CPU use in Chrome I believe due to the constant reflow work being done each frame. What are other options I can use to eliminate reflows and reduce CPU?
Two other requirements: this web page is a web UI over a back end music server. It's not using any HTML5 media elements. As such, the page may be loaded when the song is already partially over, so the position will not always animate between 0 and 100.
The below fiddle shows up at about 30% CPU on my machine, which seems a bit high to animate a rectangle.
var pos = 0;
var s = document.getElementById('i');
f = function() {
window.requestAnimationFrame(f);
pos += .03;
s.style.width = pos + '%';
}
f();
#i {
background-color: red;
position: absolute;
}
<div id="i">
</div>
There are a number of ways you could make a pure CSS progress bar that won’t cause a relayout, here are a few examples:
animation - http://jsbin.com/yoqabe/edit?html,css,js,output
I think one of the most performant ways would be to use an animation to control the background position of a linear-gradient. The only downside is that you can only play/pause the animation.
background-position - http://jsbin.com/veyibe/edit?html,css,js,output
If you need the ability to update the position with JS, then I would suggest updating the background-position of a gradient and applying CSS transitions, debouncing to avoid updating too quickly.
translateX: http://jsbin.com/zolurun/edit?html,js,output
You could also use CSS transforms to slide the progress bar inside of a container, which should also avoid a repaint.
These links might also be useful:
List of CSS layout, paint, and composite triggers: http://csstriggers.com
Debounce info: https://davidwalsh.name/javascript-debounce-function
You can consider using other CSS properties which don't require layout opearations, such as background-size.
And use CSS animations instead of requestAnimationFrame.
var bar = document.getElementById('i');
function playSong(currentTime, duration) {
bar.style.animationDuration = duration + 's';
bar.style.animationDelay = - currentTime + 's';
}
playSong(3, 10);
#i {
height: 1em;
background-image: linear-gradient(red, red);
background-repeat: no-repeat;
animation: bar linear;
}
#keyframes bar {
from { background-size: 0% 100%; }
to { background-size: 100% 100%; }
}
<div id="i"></div>
If you use position: absolute or position: fixed on the progress bar itself, it should prevent large reflows on the page.
Use timeupdate, The time indicated by the element's currentTime attribute has changed.
Try this:
var audio = document.getElementById("audio");
function updateProgress() {
var progress = document.getElementById("progress");
var value = 0;
if (audio.currentTime > 0) {
value = Math.ceil((100 / audio.duration) * audio.currentTime);
}
progress.style.width = value + "%";
}
audio.addEventListener("timeupdate", updateProgress, false);
#progressBar {
border: 1px solid #aaa;
color: #fff;
width: 295px;
height: 20px;
}
#progress {
background-color: #ff0000; // red
height: 20px;
display: block;
height: 100%;
width: 0;
}
<div id="progressBar"><span id="progress"></span>
</div>
<audio id="audio" controls>
<source src="http://www.w3schools.com/tags/horse.ogg" type="audio/ogg" />
<source src="http://www.w3schools.com/tags/horse.mp3" type="audio/mpeg" />Your browser does not support the audio element.
</audio>
The script you present is not very relevant to the one you desire, you animate on requestAnimationFrame but in reality you will animate every time the "song percentage" changes.
Assuming that you have a function (e.g. getSongPer()) that returns the current percentage of played song:
var oldPos, pos = 0;
var s = document.getElementById('i');
f = function() {
oldPos = pos;
pos = getSongPer();
if(oldPos !== pos){
s.style.width = pos + '%';
}
if(pos<100){
window.requestAnimationFrame(f);
}
}
f();
I didn't test it, but I expect it to be lighter, also, the performance will be affected by the precision of the percentage, e.g. there will be about 100 animation changes if you have zero digit precision and around ten times more for every digit after.
CSS:
#progress-bar {
background-color: red;
height: 10px;
width: 100%;
transform-origin: 0 0;
}
JS:
'use strict'
var progressBar = document.getElementById('progress-bar')
function setProgress(percentage) {
requestAnimationFrame(function () {
progressBar.style.transform = 'scaleX(' + percentage + '%)'
})
}
setProgress(10)
When setting the width to 100% you get a full width colored bar.
Then we can apply the scale transform to set the width of the bar without reflowing.
But oh, it scales to the middle. We can fix that by setting the origin of the transform to the top left corner using transform-origin: x y, with x and y being 0.
Then we wrap the style change in requestAnimationFrame to let the browser optimize when to apply the change.
Bam! You have a performant zero reflow progress bar.
The Fiddle: http://jsfiddle.net/4WFrJ/
My Problem:
I can't wrap my head around the behaviour of this setup.
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all. Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
My browser is Chrome.
My Aim: achieve a fluid motion with the images disappearing when out of bounds of the parent element, whatever the magnification percentage.
I am in search of the basic rules, that govern these strange processes, from which I hope to learn new things.
The Code:
HTML:
<div id = "presentation">
<ul>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image1.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image2.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image3.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image4.jpg"> </li>
</ul>
</div>
CSS:
html, body {
margin: 0;
}
#presentation {
padding: 10px;
width: 900px;
margin: 50px auto;
overflow: hidden;
}
#presentation ul {
list-style-type: none;
margin: 0;
}
#presentation ul li {
display: inline-block;
}
.pres-item {
height: 150px;
width: auto;
position: relative;
left: 0;
}
.pres-image {
width: inherit;
height: inherit;
}
JS (with jQuery):
$(document).ready(function(){
var presentation = $('#presentation');
var interval = setInterval(function() {
console.log('intervaling');
$('.pres-item').css('left', '+=1');
}, 60);
});
The Image:
The Thanks:
THANKS PEOPLE (in advance)
<script>
// too much code, but it explains..
// do this in ur interval...
var getCurrent_left = $('.pres-item').css('left');
var newCurrent_left = getCurrent_left.split['px'];
var newCurrent_left = parseInt(newCurrent_left[0]) + 1;
var newCurrent_left = parseInt(newCurrent_left);
$('.pres-item').css({"left", newCurrent_left});
// you can use parseFloat(var, 2) for decimal
</script>
My Problem:
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all.
I'm not sure this is actually a problem. They appear to move slower when zoomed out because they travel fewer screen pixels for each viewport pixel.
Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
Apparently Chrome does not always return that CSS property as an integer. You can see the same effect in this code:
var presentation = document.getElementById('presentation');
var items = presentation.getElementsByClassName('pres-item');
var interval = setInterval(function () {
[].forEach.call(items, function (x) {
var lastLeft = getComputedStyle(x, null).getPropertyValue('left');
console.log(lastLeft);
x.style.left = (parseFloat(lastLeft) + 1) + 'px';
})
}, 60);
I'm not sure if this is a problem or not. You could easily avoid it by keeping track of the offset in a separate variable and incrementing it during your loop instead of computing it from the element's current style.
var presentation = $('#presentation');
var left = 0;
var interval = setInterval(function() {
++left;
$('.pres-item').css('left', left + 'px');
}, 60);
I have two columns in my HTML page.
<div id="content">
<div id="left"></div>
<div id="right"></div>
</div>
Each of them occupies half of the page
#content {
height: 100%;
}
#left, #right {
float: left;
width: 50%;
height: 100%;
overflow: auto;
}
I'd like the boundary between left and right halves to be adjustable by the user. That is, the user can move the boundary to the left or to the right as he/she browses the page. Is it possible to do that somehow?
Yes, but it requires JavaScript. To apply it, you could of course just set the width of each of the sides:
var leftPercent = 50;
function updateDivision() {
document.getElementById('left').style.width = leftPercent + '%';
document.getElementById('right').style.width = (100 - leftPercent) + '%';
}
Now you can adjust the division with, say leftPercent = 50; updateDivision(), but the user isn't going to do that. There are multiple different ways you could present this to the user. Probably the best-suited way would be a little line in the middle they could drag. For this, you could use a little CSS for the positioning:
#content {
position: relative;
}
#divider {
position: absolute;
/* left to be set by JavaScript */
width: 1px;
top: 0;
bottom: 0;
background: black;
cursor: col-resize;
/* feel free to customize this, of course */
}
And then make sure you've got a div with an id of divider in content and update updateDivision to also update the left of divider:
document.getElementById('left').style.left = leftPercent + '%';
Then you just need a little logic to handle the dragging. (Here, I've put all of the elements into appropriately-named variables):
divider.addEventListener('mousedown', function(e) {
e.preventDefault();
var lastX = e.pageX;
document.documentElement.addEventListener('mousemove', moveHandler, true);
document.documentElement.addEventListener('mouseup', upHandler, true);
function moveHandler(e) {
e.preventDefault();
e.stopPropagation();
var deltaX = e.pageX - lastX;
lastX = e.pageX;
leftPercent += deltaX / parseFloat(document.defaultView.getComputedStyle(content).width) * 100;
updateDivision();
}
function upHandler(e) {
e.preventDefault();
e.stopPropagation();
document.documentElement.removeEventListener('mousemove', moveHandler, true);
document.documentElement.removeEventListener('mouseup', upHandler, true);
}
}, false);
You should be able to read it to see how it works, but in short: It listens for when someone presses on the divider. When they do, it'll attach listeners to the page for when they move their mouse. When they do, it updates the variable and calls updateDivision to update the styles. When eventually it gets a mouseup, it stops listening on the page.
As a further improvement, you could make every element have an appropriate cursor style while dragging so your cursor doesn't flash while dragging it.
Try it out.
There's nothing in the divisions so nothing will happen. It's like writing:
<h1></h1>
And changing the CSS for h1 and expecting something to be there
I am trying to create a page that is an endless scrolling loop both up and down.
At the moment I am using jquery to relocate content from the top of the page to the bottom. This creates a nice seemless loop when you scroll down but I would like it to work when the user scrolls up too.
The problem seems to be that even if content is positioned in negative vertical space on the page the scroll will not extend to that space. As far as I am aware there is no way to override this so I am looking for some type of work around.
I have thoughts of using javascript to disable the scrolling and using the scroll event to reposition the elements but there are already lots of absolute positioned elements and animation happening on the page so I'm concerned about performance taking that route.
Any other leads?
OK... I worked it out.
I adapted this script which instantly relocates the scroll location to the top of the page when you get to the bottom and to the bottom when you reach the top.
$(window).scroll(function() {
if ( $(window).scrollTop() >= 18830 ) {
$(window).scrollTop(201);
}
else if ( $(window).scrollTop() == 0 ) {
$(window).scrollTop(18629);
}
});
And then I made sure that the content at the bottom and the top of the page was identical. I thought that there would be a flash or something when this relocation happened but it's smooth!
The solution I like the best is this one (code), because it adds elements at the bottom before the bottom is reached, making sure that scrolling remains continuous (even with smooth scrolling on). However, it doesn't work that well on mobile phones where scrolling can happen pretty quickly. I recommend Marijn Haverbeke's wonderful article on fake scrollbars in CodeMirror where he deals with similar issues.
I leave you with some snippets.
First, some background. Why would we want to fake a scrollbar to begin with?
In order to remain responsive when huge documents are loaded in, CodeMirror does not render the whole document, but only the part of it that is currently scrolled into view. This means that the amount of DOM nodes it creates is limited by the size of the viewport, and the browser relayouts triggered by changes to the text are relatively cheap.
And further down...
Then, it listens to wheel events, but never calls preventDefault on them or does scrolling in response to them. Instead, it responds by setting a timeout to observe the amount of pixels that the wheel event did scroll the content, and uses that to tweak its delta-to-pixel rate at run-time.
Clone your HTML body two (or three) times (in javascript or otherwise). Start the page in the middle copy instead of the top, and then you can handle scrolling however you like.
Any other leads?
Seen these?
5 jQuery infinite Scrolling Demos
jsfiddle that I cannot find origin of. (I didn't write and don't know who did)
As many have suggested, if your page doesn't look exactly the same at the top and at the bottom you’ll need to clone your content to make it look like it does. I’ve made an example using this technique that works pretty smooth:
/*
Ininite looping scroll.
Tested and works well in latest Chrome, Safari and Firefox.
*/
(function (window) {
'use strict';
var doc = document,
body = doc.body,
html = doc.documentElement,
startElement = doc.getElementsByClassName('is-start')[0],
clones = doc.getElementsByClassName('is-clone'),
disableScroll = false,
docHeight,
scrollPos,
clonesHeight,
i;
function getScrollPos() {
return (window.pageYOffset || html.scrollTop) - (html.clientTop || 0);
}
function getDocHeight() {
return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
}
function getClonesHeight() {
i = 0;
clonesHeight = 0;
for (i; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
docHeight = getDocHeight();
clonesHeight = getClonesHeight();
window.addEventListener('resize', function () {
scrollPos = getScrollPos();
docHeight = getDocHeight();
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
window.scroll(0, 1); // Scroll 1 pixel to allow upwards scrolling.
}
}, false);
window.addEventListener('scroll', function () {
if (disableScroll === false) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= docHeight) {
// Scroll to the top when you’ve reached the bottom
window.scroll(0, 1); // Scroll 1 pixel to allow upwards scrolling.
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the top of the clones when you reach the top.
window.scroll(0, docHeight - clonesHeight);
disableScroll = true;
}
if (disableScroll) {
// Disable scroll-repositioning for a while to avoid flickering.
window.setTimeout(function () {
disableScroll = false;
}, 100);
}
}
}, false);
// Needs a small delay in some browsers.
window.setTimeout(function () {
if (startElement) {
// Start at the middle of the starting block.
window.scroll(0, Math.round(startElement.getBoundingClientRect().top + document.body.scrollTop - (window.innerHeight - startElement.offsetHeight) / 2));
} else {
// Scroll 1 pixel to allow upwards scrolling.
window.scroll(0, 1);
}
});
}(this));
section {
position: relative;
text-align: center;
height: 80vh;
}
.red {
background: #FF4136;
}
.green {
background: #2ECC40;
}
.blue {
background: #0074D9;
}
.orange {
background: rebeccapurple;
}
h1 {
margin: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
font-size: 5vw;
color: #fff;
text-transform: uppercase;
}
body {
font-family: "Avenir Next", Montserrat, Helvetica, sans-serif;
font-weight: normal;
font-size: 100%;
}
::scrollbar {
display: none;
}
<section class="green">
<h1>One</h1>
</section>
<section class="red">
<h1>For</h1>
</section>
<section class="blue">
<h1>All</h1>
</section>
<section class="orange">
<h1>And</h1>
</section>
<section class="blue">
<h1>All</h1>
</section>
<section class="red">
<h1>For</h1>
</section>
<!--
These following blocks are the same as the first blocks to get that looping illusion going. You need to add clones to fill out a full viewport height.
-->
<section class="green is-clone is-start">
<h1>One</h1>
</section>
<section class="red is-clone">
<h1>For</h1>
</section>
Building up on Mahmoud's answer, I hacked up this in a few minutes.
It works somewhat (at least on Firefox) when scrolling either with keys or with mouse wheel, but it gets all glitchy when dragging the scrollbar. Depending on how the div heights relate to the viewport height, all kinds of fireworks can happen too.
Still, I hope this can help you get on the right direction.
function onScroll(){
var SAFETY_MARGIN = 50,
scrollPos = $(this).scrollTop(),
docHeight = $(document.body).height(),
winHeight = $(window).height(),
firstDiv = $('body>div:first-child')[0],
lastDiv = $('body>div:last-child')[0],
lowerLimit = SAFETY_MARGIN,
higherLimit = docHeight - SAFETY_MARGIN;
// Scrolling too high
if( scrollPos <= lowerLimit ){
// Move content to top;
$(lastDiv).prependTo(document.body);
// Adjust scroll position to compensate
// for the new content at the top
$(window).scrollTop(scrollPos + $(lastDiv).height());
}
// Scrolling too low
else if( scrollPos + winHeight >= higherLimit ){
// Move content to bottom
$(firstDiv).appendTo(document.body);
// Adjust scroll position to compensate
// for the missing content at the top
$(window).scrollTop(scrollPos - $(firstDiv).height());
}
}
$(window).scroll(onScroll);
$(window).load(function(){
var $body = $(document.body);
$(window).scrollTop($body.height() / 2);
});
</script>
</head>
<body>
<div style="height: 600px; background-color: red"> </div>
<div style="height: 600px; background-color: green"> </div>
<div style="height: 600px; background-color: blue"> </div>
</body>
</html>