7
\$\begingroup\$

I am working on a website with an animation that runs at the beginning before the content of the homepage becomes visible. I've looked at some examples of preloaders and now use that code with some setTimeout to implement the desired effect. The effect works the way it should but I think the code it's a bit messy. is there be a better way to write that? It would be great if someone had a suggestion.

Here is the code and and a working HTML in which everything is bind together:

The javascript

setTimeout(function () {
                    function run() {
                            var wrp = document.getElementById("i-w");
                            var swp = document.getElementById("pink");
                            wrp.className += "loaded";
                            swp.classList.add('fd');}
                    if (document.readyState != 'loading') run();
                    else if (document.addEventListener) document.addEventListener(
                            'DOMContentLoaded', run);
                    else document.attachEvent('onreadystatechange', function () {
                            if (document.readyState == 'complete') run();
                    });
            }, 2650);
            setTimeout(function () {
                    var swp = document.getElementById("pink");
                    swp.classList.remove('fd');  
            }, 3000);

The HTML

<!DOCTYPE html>
<html lang="en">

<head>
        <title>itr test</title>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
                body {
                        margin: 0;
                        padding: 0;
                        background:yellow;
    
}
                #i-w {
                        z-index: 9999;
                        visibility: visible;
                        -webkit-transform: translateY(0%);
                        transform: translateY(0%);
                        -webkit-transition: -webkit-transform .4s ease-in-out;
                        transition: transform .4s ease-in-out;
                        will-change: transform;
                }

                #i-w.loaded {
                        visibility: hidden;
                        -webkit-transform: translateY(-100%);
                        transform: translateY(-100%);
                        -webkit-transition: -webkit-transform 1.3s cubic-bezier(.96, 0, .07, 1), visibility 0s 1.9s;
                        transition: transform 1.3s cubic-bezier(.96, 0, .07, 1), visibility 0s 1.9s;
                }

                #i-w .itr {
                        z-index: 100000;
                        position: fixed;
                        width: 100%;
                        height: 100%;
                        top: 0;
                        left: 0;
                        background: #0f0a05;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        text-align: center;
                }

                #i-w {
                        position: fixed;
                        width: 100%;
                        height: 100%;
                        top: 0;
                        left: 0;
                }
                
                .container {
                        background: pink;
                        display: flex;
                        flex-direction: column;
                        min-height: 100vh;
                        justify-content: center;
                        align-items: center;
                        transform: translateY(0);
                        transition: transform .7s cubic-bezier(.96, 0, .07, 1);
                        will-change: transform; 
                }
                .container.fd {
                        transform: translateY(100%);  
                        transition: transform .1s cubic-bezier(.96, 0, .07, 1);
}
                .hdg {

                        font-family: Helvetica, sans-serif;
                        text-transform: uppercase;
                        text-align: center;
                        color: #000;
                        font-size: 18vw;
                }
                .itr-hdg {
                        font-family: Helvetica, sans-serif;
                        text-transform: uppercase;
                        text-align: center;
                        color: green;
                        font-size: 8vw;   
                        opacity: 1;
                        visibility: hidden;
                        will-change: transform;
                        transform: translate3d(0, 150%, 0) skewY(18deg) scale(1);
                        animation: fd-i 1.3s .6s cubic-bezier(.86,0,.07,1) forwards, trlt-i 1.5s 1s cubic-bezier(.23, 1, .32, 1) forwards, trlt-o .5s 2.9s cubic-bezier(.23, 1, .32, 1) forwards, fd-o .4s 3s ease forwards;

                }

                @keyframes trlt-i {
                        to {
                                -webkit-transform: translateZ(0);
                                transform: translateZ(0);
                        }
                }

                @keyframes trlt-o {
                        from {
                                -webkit-transform: translateZ(0);
                                transform: translateZ(0);
                        }

                        to {
                                -webkit-transform: translate3d(0, -150%, 0) skewY(0deg) scale(1);
                                transform: translate3d(0, -150%, 0) skewY(0deg) scale(1);
                        }
                }

                @keyframes fd-i {
                        0% {
                                opacity: 0;
                                visibility: hidden;
                        }

                        to {
                                opacity: 1;
                                visibility: visible;
                        }
                }

                @keyframes fd-o {
                        0% {
                                opacity: 1;
                                visibility: visible;
                        }

                        to {
                                opacity: 0;
                                visibility: hidden;
                        }
                }
        </style>
        <script>
                  setTimeout(function () {
                        function run() {
                                var wrp = document.getElementById("i-w");
                                var swp = document.getElementById("pink");
                                wrp.className += "loaded";
                                swp.classList.add('fd');

                        }
                        if (document.readyState != 'loading') run();
                        else if (document.addEventListener) document.addEventListener(
                                'DOMContentLoaded', run);
                        else document.attachEvent('onreadystatechange', function () {
                                if (document.readyState == 'complete') run();
                        });
                }, 2650);
                setTimeout(function () {
                        var swp = document.getElementById("pink");
                        swp.classList.remove('fd');  
                }, 3000);
        </script>
</head>

<body>
        <div id="i-w">
                <div class="itr">
                                <div class="itr-hdg">
                                        <h1>&#11014; intro &#11014;</h1>
                                </div>
                </div>
        </div>
      
        <div class="container" id="pink">
                <h1 class="hdg">hello</h1>
        </div>
       
</body>

</html>

\$\endgroup\$
4
\$\begingroup\$

I would make the following recommendations to clean it up for future maintainability and readability:

  • Clean up and remove the anonymous functions.
    • They aren't really needed here and just create extra clutter, decreasing readability.
  • Remove the additional setTimeout call and just call to show when you're done loading.
  • Use more meaningful names.
    • It was hard to understand what your code was doing, what each element was, and it took me some time to clean it up due to that.
    • Using more meaningful names helps readability, and thus improves maintainability.
  • Ensure you're only creating CSS classes once.
    • You had two instances of #i-w that could be one instead.
  • Remove the usage of events unless needed.
    • I wouldn't rely on the DOM events unless you're only focused on the page content and visuals.
    • A reusable loader would begin loading and then show that it's loading until it's done loading, not when the DOM is done.
    • A good additive to this is to include the event check once you're done loading just in case you finish before the DOM does.
  • Do not redefine variables.
    • You'll notice that I removed one variable (wrp) because it was only used once.
    • Also, if you're going to need a variable later, you can pass it to the next function, or you can create it globally at the top of the function that created it for later access.
    • I wouldn't create it globally unless you need to, and in this case, I don't think you do since your only variables are wrp and swp which are both used by the pre-loader only.

Other than that, it's visually appealing, and a great implementation! Keep up the good work!

// Begin loading our stuff from DB, files, etc.
function beginLoading() {
  // Perform some kinds of loading tasks.
  for (var i = 0; i < 65535; i++)
    i++;

  // Check the DOM before updating.
  checkDOMForLoadingCompleted();
}

// Since we're done loading, we want to make sure the DOM is too.
function checkDOMForLoadingCompleted() {
  if (document.readyState != 'loading')
    loadingCompleted();
  else if (document.addEventListener)
    document.addEventListener('DOMContentLoaded', loadingCompleted);
  else
    document.attachEvent('onreadystatechange', onReadyStateChange);
}
function onReadyStateChange() {
  if (document.readyState == 'complete')
    loadingCompleted();
}

// Loading has completed on our side and the DOM's so we can complete the pre-loader's life cycle.
function loadingCompleted() {
  document.getElementById("pre-loader").classList.add("loaded");
  var loadedContent = document.getElementById("loaded-content");
  loadedContent.classList.add("fd");
  showLoadedContent(loadedContent);
}
function showLoadedContent(loadedContent) {
  loadedContent.classList.remove("fd");
}


// This is to simulate starting a loading process.
//    Instead of using setTimeout, just call the begin loading function to start your loading process.
//beginLoading();
callBeginLoadingOnTimeout();
function callBeginLoadingOnTimeout() {
  setTimeout(beginLoading, 2650);
}
body {
	margin: 0;
	padding: 0;
	background: yellow;
}
.pre-loader {
	z-index: 9999;
	visibility: visible;
	-webkit-transform: translateY(0%);
	transform: translateY(0%);
	-webkit-transition: -webkit-transform 0.4s ease-in-out;
	transition: transform 0.4s ease-in-out;
	will-change: transform;
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
}
.pre-loader.loaded {
	visibility: hidden;
	-webkit-transform: translateY(-100%);
	transform: translateY(-100%);
	-webkit-transition: -webkit-transform 1.3s cubic-bezier(0.96, 0, 0.07, 1), visibility 0s 1.9s;
	transition: transform 1.3s cubic-bezier(0.96, 0, 0.07, 1), visibility 0s 1.9s;
}
.pre-loader .intro-wrapper {
	z-index: 100000;
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	background: #0f0a05;
	display: flex;
	justify-content: center;
	align-items: center;
	text-align: center;
}
.container {
	background: pink;
	display: flex;
	flex-direction: column;
	min-height: 100vh;
	justify-content: center;
	align-items: center;
	transform: translateY(0);
	transition: transform 0.7s cubic-bezier(0.96, 0, 0.07, 1);
	will-change: transform;
}
.container.fd {
	transform: translateY(100%);
	transition: transform 0.1s cubic-bezier(0.96, 0, 0.07, 1);
}
.heading {
	font-family: Helvetica, sans-serif;
	text-transform: uppercase;
	text-align: center;
	color: #000;
	font-size: 18vw;
}
.intro-heading {
	font-family: Helvetica, sans-serif;
	text-transform: uppercase;
	text-align: center;
	color: green;
	font-size: 8vw;
	opacity: 1;
	visibility: hidden;
	will-change: transform;
	transform: translate3d(0, 150%, 0) skewY(18deg) scale(1);
	animation: to-visible 1.3s 0.6s cubic-bezier(0.86, 0, 0.07, 1) forwards,
		to-zero-translation-z 1.5s 1s cubic-bezier(0.23, 1, 0.32, 1) forwards,
		to-transform-tss 0.5s 2.9s cubic-bezier(0.23, 1, 0.32, 1) forwards,
		to-hidden 0.4s 3s ease forwards;
}
@keyframes to-zero-translation-z {
	to {
		-webkit-transform: translateZ(0);
		transform: translateZ(0);
	}
}
@keyframes to-transform-tss {
	from {
		-webkit-transform: translateZ(0);
		transform: translateZ(0);
	}
	to {
		-webkit-transform: translate3d(0, -150%, 0) skewY(0deg) scale(1);
		transform: translate3d(0, -150%, 0) skewY(0deg) scale(1);
	}
}
@keyframes to-visible {
	from {
		opacity: 0;
		visibility: hidden;
	}
	to {
		opacity: 1;
		visibility: visible;
	}
}
@keyframes to-hidden {
	from {
		opacity: 1;
		visibility: visible;
	}
	to {
		opacity: 0;
		visibility: hidden;
	}
}
<div id="pre-loader" class="pre-loader">
	<div class="intro-wrapper">
		<div class="intro-heading">
			<h1>&#11014; intro &#11014;</h1>
		</div>
	</div>
</div>
<div class="container" id="loaded-content">
	<h1 class="heading">hello</h1>
</div>

\$\endgroup\$
  • 1
    \$\begingroup\$ Thank you for taking the time to describe your changes and recommendations in such detail. I'll take a closer look at that in the next few days, and if I have any questions, I'd like to come back to that. Thanks again for your support! \$\endgroup\$ – mm_bln Sep 9 at 20:43
  • \$\begingroup\$ Thank's again. I tried your suggestion but in order to maintain the effect of dragging the loaded content into the field of view, while the preloader screen is moving up, I had to use a second timeout. I also had to declare the variable loadedContent inside that timeout once again and changed the "container*" to "#loaded-content*" in the css part. Should i post the code somewhere? \$\endgroup\$ – mm_bln Sep 15 at 14:05
1
\$\begingroup\$

Define your variables at the top of your script outside of the setTimeout. That way, you only need to define every variable once. Also, you can make them const, since they won't change.

The same goes for the run() function. Declare it outside of the setTimeout. You just want to call it inside the setTimeout. I hope this is helpful for you.

const wrp = document.getElementById("i-w");
const swp = document.getElementById("pink");


function run() {
    wrp.className += "loaded";
    swp.classList.add('fd');
}


setTimeout(function () {

    if (document.readyState != 'loading') run();
    else if (document.addEventListener) document.addEventListener('DOMContentLoaded', run);
    else document.attachEvent('onreadystatechange', function () {
        if (document.readyState == 'complete') run();
    });
}, 2650);

setTimeout(function () {
    swp.classList.remove('fd');  
}, 3000);
\$\endgroup\$
  • \$\begingroup\$ Thanks for the advice and the clarification. \$\endgroup\$ – mm_bln Sep 9 at 20:19
  • \$\begingroup\$ It doesn't work i get a "Uncaught TypeError: Can not read property 'className' from null" it seems the variables not being passed. \$\endgroup\$ – mm_bln Sep 15 at 14:14
  • 1
    \$\begingroup\$ Try moving the script to the bottom of your document, just before the closing body tag. The error occurs because the script gets executed before the HTML elements get rendered. \$\endgroup\$ – Dennis Fink Sep 15 at 15:01
  • \$\begingroup\$ Ahh i see, my mistake. Now it works. Thanks! \$\endgroup\$ – mm_bln Sep 15 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.