1
\$\begingroup\$

I built a 404 page which involves parallax scrolling text. The program updates the position of 100-200 text nodes at each animation frame called with window.requestAnimationFrame. It runs decently well on my MacBook (although it occupies significant CPU), but on weaker computers like my phone, it runs very sluggishly.

How can I optimize my code to achieve better performance?

var scene;
function randint(low, high) { // Return a random integer between low and high
 return Math.floor(( Math.random()*(high-low) ))+low;
}
// Add a layer to the scene
function addLayer() {
 // Make a "layer" in the parallax animation
 var layer = document.createElement("div");
 // Give it a random Z value (0 to 1)
 layer.setAttribute("class", "layer");
 layer.setAttribute("data-z", Math.random().toFixed(2));
 // Make a div inside that says "404"
 layer.appendChild(document.createTextNode("404"));
 // Random X position
 layer.style.left = randint(-10, window.innerWidth) + "px";
 // Below bottom of screen
 layer.style.top = window.innerHeight + "px";
 // Font size and weight based on Z value
 var z = parseFloat(layer.getAttribute("data-z"));
 layer.style.fontSize = Math.floor(z * 150) + "px";
 layer.style.fontWeight = Math.ceil(z * 4) * 100;
 // Random opacity
 layer.style.opacity = (Math.random() / 10).toFixed(2);
 // Add nodes to appropriate parents
 scene.appendChild(layer);
}
function updatePositions() {
 var layers = scene.getElementsByTagName("div");
 var layer, div, z;
 for (var i = 0; i < layers.length; i++) {
 layer = layers[i];
 z = parseFloat(layer.getAttribute("data-z"));
 y = parseInt(layer.style.top.slice(0, layer.style.top.length - 2));
 layer.style.top = (y - Math.ceil(z * 10)).toFixed(2) + "px";
 if (y < (-150)) { // Max fontsize is 150px
 scene.removeChild(layer);
 }
 }
}
function updateColor() {
 var hue = (parseFloat(document.body.getAttribute("data-hue")) + 0.25) % 360;
 document.body.setAttribute("data-hue", hue.toString());
 var hex = chroma(hue, 1, 1, "hsv").brighten().hex();
 document.body.style.color = hex;
 document.getElementsByTagName("a")[0].style.backgroundColor = hex;
}
function update() {
 addLayer();
 updatePositions();
 updateColor();
 window.requestAnimationFrame(update); // Recur
}
scene = document.getElementById("scene");
window.requestAnimationFrame(update);
body {
 background-color: #222;
 margin: 0;
 width: 100vw;
 height: 100vh;
 /* Global font settings */
 color: #fff;
 font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
#scene {
 position: fixed;
 top: 0;
 left: 0;
 padding: 0;
 margin: 0;
 width: 100%;
 height: 100%;
 overflow: hidden;
}
.layer {
 position: absolute;
}
.main {
 position: fixed;
 top: 0;
 left: 0;
 width: 100%;
 text-align: center;
 opacity: 0.5;
}
h1 {
 font-size: 200px;
 margin-bottom: 0;
}
.main p {
 font-size: 150%;
 margin-top: 0;
}
.main a {
 color: #222;
 background-color: #fff;
 padding: 10px;
 text-decoration: none;
 font-size: 150%;
 font-weight: 600;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.1.1/chroma.min.js"></script>
<body data-hue="0">
 <!-- Background -->
 <div id="scene"></div>
 <!-- Foreground -->
 <div class="main">
 <h1>404</h1>
 <p>That page couldn't be found.</p>
 <a href="http://luke.deentaylor.com/">Home</a>
 </div>
</body>

Running this snippet in full window will more accurately emulate how it will appear on my website.

Here's a JSFiddle if it's preferred.

asked Jun 2, 2016 at 21:34
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Use Chrome profiler, it shows that removeChild is slow -> re-use a container when 404 is out of view, do the same for addLayer. Also that coloring is slow, write your own HSL without sqrt using formulas in easyrgb.com (PS. not a JS dev). \$\endgroup\$ Commented Jun 2, 2016 at 23:54

1 Answer 1

1
\$\begingroup\$

According to my experience, web animations don't use CPU as such, but rather prefer the GPU at times for rendering. On phones, custom animations like yours will run without any moderation of fps, and so a lag is kinda expected. On top of it, js doesn't use parallel threads of course, so it won't even use the remaining core if they are available.

What I'd suggest is use some good library to run these. I remember using Three.js and it ran on my Lumia 520 at 8FPS but still without lag, as the animation was optimized for low FPS. The same ran on my PC at 60FPS smoothly just the same.

Hope this helps.

answered Jun 6, 2016 at 7:24
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.