3
\$\begingroup\$

I created a simple modal that when a user scrolls down a blog post, a modal pops up. If the user wants to sign up for newsletter, then a form pops up. The only external library I used was body-scroll-lock that helps mitigate some issues with modals/forms on iOS.

I'm curious about the need to remove event listeners and other pitfalls that I may be overlooking. Should I be using more es6 type conventions? The code is just before the </body> tag. Here it is in action: https://develop--tanyamark-prod.netlify.com/blog/do-you-eat-when-youre-hungry-stop-when-youre-full/

// Wait at least 2s to so CTA
var wait = window.setTimeout(showCta, 2000);

function showCta() {
    // Only show CTA on post pages.
    if (document.querySelector('.post-single') === null) {
        return;
    }

    var screenWidth = window.innerWidth ||
                      document.documentElement.clientWidth ||
                      document.body.clientWidth;

    var bodyTag = document.getElementsByTagName('body')[0];
    var blogCta = document.getElementById("blog-cta");
    var openFormButton = document.getElementById("open-cta");
    var closeButtonUnsubmitted = document.getElementById("close-cta");
    var submittedCloseButton = document.getElementById("submitted-close");

    // Wait to show cta until user scrolls down page.
    bodyTag.onscroll = function () {
        if ( window.pageYOffset > (document.body.clientHeight / 4) ) {
            blogCta.classList.remove("hide");
        }
    };

    var openForm = function(e) {
        if (screenWidth < 901) {
            blogCta.classList.add("mobile-blog-cta");
            bodyScrollLock.disableBodyScroll(blogCta);            
        }

        // Show the form.
        document.getElementById("cta-ck-form").style.display = 'block';

        // Remove click event from button.
        openFormButton.removeEventListener('click', openForm);

        // Hide openFormButton
        openFormButton.style.display = 'none';
    };

    var removeCTA = function() {
        blogCta.classList.remove("mobile-blog-cta");

        if (screenWidth < 901) {
            bodyScrollLock.clearAllBodyScrollLocks();
        }

        // Set inline so it doesn't show more than once.
        blogCta.style.display = 'none';
    };

    // Register events
    openFormButton.addEventListener('click', openForm);
    closeButtonUnsubmitted.addEventListener('click', removeCTA);
    submittedCloseButton.addEventListener('click', removeCTA);
}

/partials/_cta.html (The form itself is a convert kit embed)

<div id="blog-cta" class="blog-cta hide">
    <div class="cta-content">
        <p id="cta-message">Hi, It's Tanya. Like what you're reading? Get tips once a week on <em>nourishing your whole self.</em></p>
        <div id="open-cta" class="button pink">Yes, please!</div>
        <div id="cta-ck-form" class="ck_form_container ck_inline" data-ck-version="6">
            <div class="ck_form ck_naked">
                <div class="ck_form_fields">
                    <div id="ck_success_msg" style="display:none;">
                        <p>Success! Check your email to confirm your subscription.</p>
                        <button id="submitted-close">Close</button>
                    </div>
                    <!--  Form starts here  -->
                    <form id="ck_subscribe_form" class="ck_subscribe_form" action="https://app.convertkit.com/landing_pages/309440/subscribe" data-remote="true">
                        <input type="hidden" value="{&quot;form_style&quot;:&quot;naked&quot;}" id="ck_form_options">
                        <input type="hidden" name="id" value="309440" id="landing_page_id">
                        <input type="hidden" name="ck_form_recaptcha" value="" id="ck_form_recaptcha">
                        <div class="ck_errorArea">
                            <div id="ck_error_msg" style="display:none">
                                <p>There was an error submitting your subscription. Please try again.</p>
                            </div>
                        </div>
                        <div class="ck_control_group ck_email_field_group">
                            <label id="ck-test" class="ck_label" for="ck_emailField" style="display: none">Email Address</label>
                            <input type="text" name="first_name" class="ck_first_name" id="ck_firstNameField" placeholder="First Name" required="required">
                            <input type="email" name="email" class="ck_email_address" id="ck_emailField" placeholder="Email Address" required>
                        </div>
                        <div class="ck_control_group ck_captcha2_h_field_group ck-captcha2-h" style="position: absolute !important;left: -999em !important;">
                            <input type="text" name="captcha2_h" class="ck-captcha2-h" id="ck_captcha2_h" placeholder="We use this field to detect spam bots. If you fill this in, you will be marked as a spammer.">
                        </div>
                        <button class="subscribe_button ck_subscribe_button btn fields" id="ck_subscribe_button">
                            Subscribe
                        </button>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <div class="container-author-pic">
        <div class="incoming-message"><span>1</span></div>
        <img class="article-author-pic" src="/img/tanya-cup-prof.jpg" alt=""/>
        <div class="mobile-header">Tanya</div>
        <div id="close-cta">X</div>
    </div>
</div>

/partials/_cta.css (Using postcss-cssnext plugin)

.blog-cta {
  display: flex;
  flex-direction: row;
  position: fixed;
  bottom: 80px;
  right: 30px;
  z-index: 820;
  animation: grow .5s ease-in-out;

  @media all and (max-width: 600px) {
    right: 0;
    margin: 15px;
  }

}

@keyframes grow {
  0% {
    display: none;
    opacity: 0;
    transform: scale(0);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.cta-content {
  position: relative;
  display: flex;
  flex-direction: column;
  max-width: 300px;
  background-color: white;
  box-shadow: 0 0 30px rgba(42, 63, 253, .4);
  margin-right: 15px;
}

.cta-content::after {
  position: absolute;
  display: block;
  content: "";
  width: 0;
  height: 0;
  left: 100%;
  top: 45px;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 10px solid #fff;

  @media all and (max-width: 600px) {
    top: 30px;
  }
}

#cta-message {  
  color: #1c3f55;
  font-size: 17px;
  line-height: 22px;
  padding: 12px;
  margin: 0;
}

#open-cta {
  cursor: pointer;
}

.mobile-header {
  /* Will show on mobile  */
  display: none;
}

.incoming-message {
  width: 20px;
  height: 20px;
  background-color: red;
  border-radius: 24px;
  color: white;
  font-size: 14px;
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
}

#close-cta {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: -15px;
  right: -15px;
  font-family: var(--sans-serif-stack);
  color: #a2a1a1;
  font-size: 14px;
  cursor: pointer;
  height: 16px;
  width: 16px;
  padding: 5px;
  border-radius: 16px;
  background: #f1f1f5;
}

#close-cta:hover {
  color: black;
  transition: color .2s ease-in-out;
  transition: font-size .2s ease-in-out;
}

/********************/
/* Convert Kit Form */
/********************/

#cta-ck-form {
  display: none;
  animation: grow .3s ease-in-out;
}

.ck_form, .ck_form * {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.ck_errorArea {
    display: none;
    /* temporary */
}

.ck_form input[type="text"]:focus,
.ck_form input[type="email"]:focus {
    outline: none;
    border-color: #aaa;
}

.ck_converted_content {
    display: none;
    padding: 5%;
    background: #fff;
}

.ck_form.ck_naked.width400 .ck_subscribe_button,
.ck_form.ck_naked.width400 input[type="text"],
.ck_form.ck_naked.width400 input[type="email"] {
    width: 100%;
    float: none;
    margin-top: 5px;
}

.ck_slide_up, .ck_modal,
.ck_slide_up .ck_naked,
.ck_modal .ck_naked {
    min-width: 400px;
}

.page .ck_form.ck_naked {
    margin: 50px auto;
    max-width: 700px;
}

.ck_slide_up.ck_form_v6, .ck_modal.ck_form_v6,
.ck_slide_up.ck_form_v6 .ck_naked, .ck_modal.ck_form_v6 .ck_naked {
    min-width: 0 !important;
}

.ck_form_v6 #ck_success_msg {
    padding: 0px 10px;
}

@media all and (max-width: 403px) {
    .ck_form_v6.ck_modal .ck_naked {
        padding-top: 30px;
    }
}

@media all and (max-width: 499px) {
    .ck_form_v6.ck_modal .ck_naked+.ck_close_link {
        color: #fff;
        top: 10px;
    }
}

.ck_form_v6.ck_slide_up .ck_naked+.ck_close_link {
    right: 10px;
    top: -5px;
}

@media all and (min-width: 600px) {
    .ck_form_v6.ck_slide_up .ck_naked+.ck_close_link {
        right: 35px;
    }
}

/************************/
/* ConvertKit overrides */
/************************/

.blog-cta .ck_form.ck_naked p {
  font-size: 17px;
  line-height: 20px;
}

.blog-cta .ck_form.ck_naked .ck_form_fields {
    padding: 12px;
}

.blog-cta .ck_form.ck_naked input[type="text"],
.blog-cta .ck_form.ck_naked input[type="email"] {
    padding: 10px 8px;
    border: 1px solid #d6d6d6;
    height: 40px;
    font-size: 18px;
}

.blog-cta .ck_form.ck_naked .ck_subscribe_button,
.blog-cta #ck_success_msg button {
    color: #fff;
    font-size: 18px;
    background: #db65cb;
    cursor: pointer;
    border: none;
    height: 44px;
    margin-top: 10px
}

.blog-cta #ck_success_msg button {
  padding: 0 20px;
  display: block;
  margin: 0 auto;
}

/*************************/
/* Mobile + Small Screen */
/*************************/

.mobile-blog-cta.blog-cta {
  bottom: initial;
  flex-direction: column-reverse;
  justify-content: flex-end;
  align-items: center;
  margin: 0;
  background: #f6f6f6;
  position: fixed;
  top: 0;
  height: 100vh;
  width: 100%;
  right: 0;
  animation: anim .5s ease-in-out;

  @media (max-height: 370px), (max-width: 320px) {
    height: 100vh;
  }
}

@keyframes anim {
  0% {
    transform: scale(0);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.mobile-blog-cta .cta-content {
  margin: 10px 10px;
  max-width: 600px;
  background-color: white;
  padding: 30px;
  box-shadow: 0 2px 20px 0 rgba(0,0,0,.15);

  @media (max-height: 370px), (max-width: 320px) {
    background-color: initial;
    padding: 0;
    box-shadow: initial;
  }
}

.mobile-blog-cta .cta-content #cta-message {
  padding-top: 0;
}

.mobile-blog-cta .cta-content::after {
  display: none;
}

.mobile-blog-cta .container-author-pic {
  width: 100%;
  height: 30px;
  background: #fff;
  padding: 10px 0;
  margin-bottom: 30px;
  box-shadow: 0 0 20px rgba(0,0,0,.5);
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.mobile-blog-cta .article-author-pic {
  margin-top: 30px;
  border: #fff 5px solid;
}

.mobile-blog-cta .mobile-header{
  display: inline-block;
  line-height: 50px;
  font-weight: 600;
}

.mobile-blog-cta .incoming-message {
  display: none;
}

.mobile-blog-cta #close-cta {
  position: relative;
  font-size: 20px;
  color: initial;
  top: initial;
  right: initial;
  height: 22px;
  width: 22px;
}

.mobile-blog-cta #ck_firstNameField, .mobile-blog-cta #ck_emailField {
  width: 100%;
  margin-bottom: 10px;
}

.mobile-blog-cta .ck_form.ck_naked .ck_subscribe_button,
.mobile-blog-cta #ck_success_msg button {
  width: 100%;
}
\$\endgroup\$
6
  • \$\begingroup\$ Where's the HTML? \$\endgroup\$ – FreezePhoenix Jan 20 '19 at 19:37
  • 1
    \$\begingroup\$ Anything that's code. \$\endgroup\$ – FreezePhoenix Jan 20 '19 at 19:40
  • 2
    \$\begingroup\$ Ok, btw, you can embed code in your post, as opposed to linking it. \$\endgroup\$ – FreezePhoenix Jan 20 '19 at 19:42
  • 1
    \$\begingroup\$ Added the html and css. I linked to the live site only to demonstrate the feel/flow of the modal. And, I should add, of course, feed back on html/css is always nice as well. \$\endgroup\$ – Mox Jan 20 '19 at 19:47
  • 1
    \$\begingroup\$ Where is bodyScrollLock defined? \$\endgroup\$ – guest271314 Jan 20 '19 at 23:46

Your Answer

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

Browse other questions tagged or ask your own question.