I have been experimenting with recreating the recent Apple Mac retrospective using only CSS and JavaScript to create a small timeline of projects. While I have successfully implemented the layout for the full-screen hero and the expand-on-hover effect, I am facing an issue with achieving smooth scrolling for the timeline in the second half of the screen. Even when scrolling slowly, there is noticeable jitteriness in Google Chrome 32.0.1700.102 on Mac OS X. You can access the files needed for this project here.
I have two specific questions:
Can you provide a solution using pure CSS/JavaScript to fix the smooth scrolling issue? I would prefer guidance on debugging this example rather than redirecting me to another working solution.
In addition, what steps should I take to identify and isolate the problem during the debugging process? I attempted to collect a JavaScript CPU Profile but did not find any problematic areas that require attention.
Basic Structure
The timeline is structured as a navigation element (nav
) containing an ordered list where each list item (li
) represents a project.
<nav id='timeline'>
<ol>
<li class='project' id='zero'>
<div class='description'>
<h2> Project 0 </h2>
<span> The project that changed everything </span>
<div class='icon'></div>
</div> <!-- div.description -->
</li> <!-- li.project#zero -->
</ol>
</nav> <!-- nav#timeline -->
An event loop is used to detect mouse position globally and handle scroll detection,
// Event loop to update global mouseX, mouseY positions and handle scroll detection
var mouseX = null;
var mouseY = null;
var scrollTimeline = null;
var updateInterval = 10;
var scrolling = false;
window.onmousemove = function(event) {
mouseX = event.clientX;
mouseY = event.clientY;
if (!scrollTimeline) {
scrollTimeline = window.setInterval(scroll, updateInterval);
}
};
This event loop calls a scroll handler every 10ms,
function scroll(event) {
var buffer = window.innerWidth/4;
var distanceToCenter = Math.abs(window.innerWidth/2-mouseX);
var speed = distanceToCenter/(window.innerWidth/2);
if (mouseX < buffer) {
scrolling = true;
scrollLeft(speed);
}
else if ((window.innerWidth - mouseX) < buffer) {
scrolling = true;
scrollRight(speed);
}
else {
scrolling = false;
window.clearInterval(scrollTimeline);
scrollTimeline = null;
}
}
The scrolling effect is achieved by adjusting the left
attribute of the navigation container using functions such as scrollRight
and scrollLeft
, based on the mouse position.
function scrollRight(speed) {
var leftPixels = parseInt(getStyleProp(timeline, 'left'), 10);
var toShift = Math.pow(speed,3)*updateInterval;
var newLeft = leftPixels - toShift;
if (newLeft >= -1400 && newLeft <= 0) {
timeline.style.left = newLeft + 'px';
}
}
A handy utility function called getStyleProp
is used to retrieve style properties like the computed left
attribute.
// Utility function to grab style properties when unset
function getStyleProp(elem, prop){
if(window.getComputedStyle)
return window.getComputedStyle(elem, null).getPropertyValue(prop);
else if(elem.currentStyle) return elem.currentStyle[prop]; //IE
}
What I've Tried
In my attempts to resolve the issue, I have:
- Removed some CSS transitions creating the scalloped effect
- Opted for one image instead of six images
- Adjusted the
left
attribute incrementally rather than in large increments - Eliminated text content and respective transitions
- Removed certain list items within the navigation container, which temporarily resolved the problem, although I am uncertain how this led to the observed jitteriness.
Thank you for your assistance!