Creating Pull to Refresh with HTML, CSS, and JavaScript

Faraz

By Faraz -

Learn how to implement Pull to Refresh using HTML, CSS, and JavaScript to boost user engagement on your web app.


Creating Pull to Refresh with HTML, CSS, and JavaScript.jpg

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Preview
  6. Conclusion

Welcome to a comprehensive guide on implementing Pull to Refresh using HTML, CSS, and JavaScript. In this post, we'll walk you through each step to create a user-friendly web application feature.

Understanding Pull to Refresh

Before we dive in, let's understand what Pull to Refresh is and why it's crucial for enhancing user experience.

How it works:

Pull to Refresh allows users to reload content on a webpage by pulling it downward. This gesture triggers a refresh action, making your web app feel more interactive.

Let's start implementing the Pull to Refresh component using HTML, CSS, and JavaScript step by step.

Join My Telegram Channel to Download the Project Source Code: Click Here

Prerequisites:

Before starting this tutorial, you should have a basic understanding of HTML, CSS, and JavaScript. Additionally, you will need a code editor such as Visual Studio Code or Sublime Text to write and save your code.

Source Code

Step 1 (HTML Code):

To create Pull to Refresh, you'll need to structure your HTML properly. Here's how to do it:

  1. Step 1: Add a scrollable container for your content.
  2. Step 2: Include the content you want to refresh inside this container.

Let me explain each part of it:

1. <!DOCTYPE html>: This declaration defines the document type and version of HTML being used, which is HTML5 in this case.

2. <html lang="en">: The <html> element is the root element of the HTML document. The lang attribute specifies the language of the document, which is English in this case.

3. <head>: The <head> section contains metadata about the document, such as character encoding, title, and links to external resources. Here's what's inside the <head>:

  • <meta charset="UTF-8">: This meta tag defines the character encoding of the document as UTF-8, which is a widely used character encoding for handling text.
  • <meta http-equiv="X-UA-Compatible" content="IE=edge">: This meta tag is primarily for Internet Explorer and instructs it to use the latest rendering engine.
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">: This meta tag is used for responsive design, ensuring that the webpage adapts to the width of the device's screen and starts at an initial zoom level of 1.0.
  • <title>Pull to Refresh</title>: This sets the title of the web page, which typically appears in the browser's title bar or tab.
  • <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">: This is a link to an external CSS stylesheet (reset.min.css) hosted on a content delivery network (CDN). It's used to reset or normalize default CSS styles in web browsers.
  • <link rel="stylesheet" href="styles.css">: This is another link to an external CSS stylesheet (styles.css) hosted locally or on the same server as the HTML file. It's used to apply custom styles to the web page.

4. <body>: The <body> element contains the content that is visible on the web page. Here's what's inside the <body>:

  • <div class="center">: A <div> element with a class of "center" is used to center the content of the web page horizontally.
  • <div class="iphone">: This <div> represents an element styled to resemble an iPhone.

5. Inside the "iphone" div:

  • <div class="iphone__upper">: A sub-division within the iPhone element.
  • <span class="speaker_yo">: A <span> element with a class of "speaker_yo," which represent the speaker area on the iPhone.
  • <div class="list__wrapper">: This is a wrapper for a list.
  • Inside the "list__wrapper":
  • <div class="svg__wrapper">: Another wrapper for SVG (Scalable Vector Graphics) elements.
  • Two SVG elements are embedded within this wrapper. They appear to be used for creating visual effects on the web page.
  • <ul class="list">: An unordered list (<ul>) with a class of "list" that contains a list of items.
  • Inside the "list," there are five list items (<li>), each containing various <span> elements, which will be used for displaying some kind of content.

6. <script> tags at the end: These are JavaScript script tags that load external JavaScript libraries and a local script file. They are responsible for adding functionality to the web page.

  • <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>: This imports the jQuery library, which is a popular JavaScript library for simplifying DOM manipulation and adding interactivity to web pages.
  • <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>: This imports the Velocity.js library, which is used for animations and transitions in JavaScript.
  • <script src="script.js"></script>: This imports a local JavaScript file named "script.js," which contains custom JavaScript code for this web page.

Step 2 (CSS Code):

Next, you'll want to make the Pull to Refresh feature visually appealing. Use CSS for this:

  1. Step 1: Style the container to make it visually distinct.
  2. Step 2: Add a loading animation or icon for visual feedback.
  3. Step 3: Ensure responsive design for different screen sizes.

Let's break down the code and explain each part:

1. body, html: These selectors are targeting the body and html elements of the web page. They are setting the height and width to 100%, making sure the entire page takes up the available viewport space. Additionally, they are setting the display property to "table," which is an unusual choice and is not commonly used in modern web development. The background color is set to a light grayish color (#F4F4F6).

2. .center: This is a CSS class selector called "center." It is used to center content on the page. It sets the width to 100% and the display property to "table-cell," which is often used in conjunction with the parent elements having a "display: table" property to center content vertically.

3. .iphone: This class selector is used to style an element that resembles an iPhone. It gives the element a border, a fixed width of 320px, and a maximum height of 500px. The element is centered on the page horizontally using margin: 50px auto. It also has a box shadow with a series of offset values and opacity settings, creating a 3D-like effect.

4. .iphone__upper: This class selector styles an upper part of the iPhone element. It has a height of 50px, a background color of #C0C4D7, and a higher z-index to place it on top of other elements. This upper section visually represents the top of an iPhone.

5. .iphone__upper .speaker_yo: This selector targets an element with the class "speaker_yo" within the ".iphone__upper" section. It sets rounded corners using different browser-specific properties, a fixed height of 8px, and a background color of #F4F4F4. This element visually represents the speaker area of the iPhone.

6. .list__wrapper: This selector is used to style a wrapper element. It uses CSS3's translate3d transform to move the element up by 183 pixels and has a white background color.

7. .list: This class is applied to a list element. It removes list-style and sets padding and margin to zero. It also changes the cursor style to a grabbing hand when hovering over the list, providing a drag-and-drop effect.

8. .list__item: This class is used to style individual items within the list. It sets padding and a white background color for list items.

9. .list__item .avatar: This selector is used to style an element with the class "avatar" within list items. It sets a background color, border radius, width, and height, creating a circular avatar-like shape.

10. .line-top, .line-mid, .line-bottom: These classes are used to style three lines with rounded corners and a specific height. They represent graphical elements within the design of the iPhone.

11. .svg__wrapper: This selector styles an element that appears to contain SVG graphics. It sets a background color and cursor style. When active, it changes the cursor to a grabbing hand. There are SVG elements positioned within this wrapper using translate3d transforms.

12. .svg__wrapper svg #progress: This targets the #progress element within SVG graphics. It specifies stroke-dashoffset and stroke-dasharray properties, potentially for creating a progress indicator animation.

13. .svg__wrapper .border: This selector is used to style a border element positioned at the top of the .svg__wrapper element. It has a white background color.

body, html {
  height: 100%;
  width: 100%;
  display: table;
  background-color: #F4F4F6;
}

.center {
  width: 100%;
  display: table-cell;
  vertical-align: middle;
}

.iphone {
  border: 1px solid #C0C4D7;
  width: 320px;
  max-height: 500px;
  margin: 50px auto;
  overflow: hidden;
  box-shadow: 1px 1px 0 0.2px rgba(236, 237, 242, 0.99167),2px 2px 0 0.4px rgba(236, 237, 242, 0.98333),3px 3px 0 0.6px rgba(236, 237, 242, 0.975),4px 4px 0 0.8px rgba(236, 237, 242, 0.96667),5px 5px 0 1px rgba(236, 237, 242, 0.95833),6px 6px 0 1.2px rgba(236, 237, 242, 0.95),7px 7px 0 1.4px rgba(236, 237, 242, 0.94167),8px 8px 0 1.6px rgba(236, 237, 242, 0.93333),9px 9px 0 1.8px rgba(236, 237, 242, 0.925),10px 10px 0 2px rgba(236, 237, 242, 0.91667),11px 11px 0 2.2px rgba(236, 237, 242, 0.90833),12px 12px 0 2.4px rgba(236, 237, 242, 0.9),13px 13px 0 2.6px rgba(236, 237, 242, 0.89167),14px 14px 0 2.8px rgba(236, 237, 242, 0.88333),15px 15px 0 3px rgba(236, 237, 242, 0.875),16px 16px 0 3.2px rgba(236, 237, 242, 0.86667),17px 17px 0 3.4px rgba(236, 237, 242, 0.85833),18px 18px 0 3.6px rgba(236, 237, 242, 0.85),19px 19px 0 3.8px rgba(236, 237, 242, 0.84167),20px 20px 0 4px rgba(236, 237, 242, 0.83333),21px 21px 0 4.2px rgba(236, 237, 242, 0.825),22px 22px 0 4.4px rgba(236, 237, 242, 0.81667),23px 23px 0 4.6px rgba(236, 237, 242, 0.80833),24px 24px 0 4.8px rgba(236, 237, 242, 0.8),25px 25px 0 5px rgba(236, 237, 242, 0.79167),26px 26px 0 5.2px rgba(236, 237, 242, 0.78333),27px 27px 0 5.4px rgba(236, 237, 242, 0.775),28px 28px 0 5.6px rgba(236, 237, 242, 0.76667),29px 29px 0 5.8px rgba(236, 237, 242, 0.75833),30px 30px 0 6px rgba(236, 237, 242, 0.75),31px 31px 0 6.2px rgba(236, 237, 242, 0.74167),32px 32px 0 6.4px rgba(236, 237, 242, 0.73333),33px 33px 0 6.6px rgba(236, 237, 242, 0.725),34px 34px 0 6.8px rgba(236, 237, 242, 0.71667),35px 35px 0 7px rgba(236, 237, 242, 0.70833),36px 36px 0 7.2px rgba(236, 237, 242, 0.7),37px 37px 0 7.4px rgba(236, 237, 242, 0.69167),38px 38px 0 7.6px rgba(236, 237, 242, 0.68333),39px 39px 0 7.8px rgba(236, 237, 242, 0.675),40px 40px 0 8px rgba(236, 237, 242, 0.66667),41px 41px 0 8.2px rgba(236, 237, 242, 0.65833),42px 42px 0 8.4px rgba(236, 237, 242, 0.65),43px 43px 0 8.6px rgba(236, 237, 242, 0.64167),44px 44px 0 8.8px rgba(236, 237, 242, 0.63333),45px 45px 0 9px rgba(236, 237, 242, 0.625),46px 46px 0 9.2px rgba(236, 237, 242, 0.61667),47px 47px 0 9.4px rgba(236, 237, 242, 0.60833),48px 48px 0 9.6px rgba(236, 237, 242, 0.6),49px 49px 0 9.8px rgba(236, 237, 242, 0.59167),50px 50px 0 10px rgba(236, 237, 242, 0.58333),51px 51px 0 10.2px rgba(236, 237, 242, 0.575),52px 52px 0 10.4px rgba(236, 237, 242, 0.56667),53px 53px 0 10.6px rgba(236, 237, 242, 0.55833),54px 54px 0 10.8px rgba(236, 237, 242, 0.55),55px 55px 0 11px rgba(236, 237, 242, 0.54167),56px 56px 0 11.2px rgba(236, 237, 242, 0.53333),57px 57px 0 11.4px rgba(236, 237, 242, 0.525),58px 58px 0 11.6px rgba(236, 237, 242, 0.51667),59px 59px 0 11.8px rgba(236, 237, 242, 0.50833),60px 60px 0 12px rgba(236, 237, 242, 0.5),61px 61px 0 12.2px rgba(236, 237, 242, 0.49167),62px 62px 0 12.4px rgba(236, 237, 242, 0.48333),63px 63px 0 12.6px rgba(236, 237, 242, 0.475),64px 64px 0 12.8px rgba(236, 237, 242, 0.46667),65px 65px 0 13px rgba(236, 237, 242, 0.45833),66px 66px 0 13.2px rgba(236, 237, 242, 0.45),67px 67px 0 13.4px rgba(236, 237, 242, 0.44167),68px 68px 0 13.6px rgba(236, 237, 242, 0.43333),69px 69px 0 13.8px rgba(236, 237, 242, 0.425),70px 70px 0 14px rgba(236, 237, 242, 0.41667),71px 71px 0 14.2px rgba(236, 237, 242, 0.40833),72px 72px 0 14.4px rgba(236, 237, 242, 0.4),73px 73px 0 14.6px rgba(236, 237, 242, 0.39167),74px 74px 0 14.8px rgba(236, 237, 242, 0.38333),75px 75px 0 15px rgba(236, 237, 242, 0.375),76px 76px 0 15.2px rgba(236, 237, 242, 0.36667),77px 77px 0 15.4px rgba(236, 237, 242, 0.35833),78px 78px 0 15.6px rgba(236, 237, 242, 0.35),79px 79px 0 15.8px rgba(236, 237, 242, 0.34167),80px 80px 0 16px rgba(236, 237, 242, 0.33333),81px 81px 0 16.2px rgba(236, 237, 242, 0.325),82px 82px 0 16.4px rgba(236, 237, 242, 0.31667),83px 83px 0 16.6px rgba(236, 237, 242, 0.30833),84px 84px 0 16.8px rgba(236, 237, 242, 0.3),85px 85px 0 17px rgba(236, 237, 242, 0.29167),86px 86px 0 17.2px rgba(236, 237, 242, 0.28333),87px 87px 0 17.4px rgba(236, 237, 242, 0.275),88px 88px 0 17.6px rgba(236, 237, 242, 0.26667),89px 89px 0 17.8px rgba(236, 237, 242, 0.25833),90px 90px 0 18px rgba(236, 237, 242, 0.25),91px 91px 0 18.2px rgba(236, 237, 242, 0.24167),92px 92px 0 18.4px rgba(236, 237, 242, 0.23333),93px 93px 0 18.6px rgba(236, 237, 242, 0.225),94px 94px 0 18.8px rgba(236, 237, 242, 0.21667),95px 95px 0 19px rgba(236, 237, 242, 0.20833),96px 96px 0 19.2px rgba(236, 237, 242, 0.2),97px 97px 0 19.4px rgba(236, 237, 242, 0.19167),98px 98px 0 19.6px rgba(236, 237, 242, 0.18333),99px 99px 0 19.8px rgba(236, 237, 242, 0.175),100px 100px 0 20px rgba(236, 237, 242, 0.16667),101px 101px 0 20.2px rgba(236, 237, 242, 0.15833),102px 102px 0 20.4px rgba(236, 237, 242, 0.15),103px 103px 0 20.6px rgba(236, 237, 242, 0.14167),104px 104px 0 20.8px rgba(236, 237, 242, 0.13333),105px 105px 0 21px rgba(236, 237, 242, 0.125),106px 106px 0 21.2px rgba(236, 237, 242, 0.11667),107px 107px 0 21.4px rgba(236, 237, 242, 0.10833),108px 108px 0 21.6px rgba(236, 237, 242, 0.1),109px 109px 0 21.8px rgba(236, 237, 242, 0.09167),110px 110px 0 22px rgba(236, 237, 242, 0.08333),111px 111px 0 22.2px rgba(236, 237, 242, 0.075),112px 112px 0 22.4px rgba(236, 237, 242, 0.06667),113px 113px 0 22.6px rgba(236, 237, 242, 0.05833),114px 114px 0 22.8px rgba(236, 237, 242, 0.05),115px 115px 0 23px rgba(236, 237, 242, 0.04167),116px 116px 0 23.2px rgba(236, 237, 242, 0.03333),117px 117px 0 23.4px rgba(236, 237, 242, 0.025),118px 118px 0 23.6px rgba(236, 237, 242, 0.01667),120px 120px 0 rgba(236, 237, 242, 0);
}

.iphone__upper {
  height: 50px;
  background-color: #C0C4D7;
  z-index: 2;
  position: relative;
}
.iphone__upper .speaker_yo {
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
  border-radius: 8px;
  height: 8px;
  width: 50%;
  left: 50%;
  bottom: 12px;
  -moz-transform: translate(-50%, 0);
  -ms-transform: translate(-50%, 0);
  -webkit-transform: translate(-50%, 0);
  transform: translate(-50%, 0);
  position: absolute;
  background-color: #F4F4F4;
}

.list__wrapper {
  -moz-transform: translate3d(0, -183px, 0);
  -ms-transform: translate3d(0, -183px, 0);
  -webkit-transform: translate3d(0, -183px, 0);
  transform: translate3d(0, -183px, 0);
  background-color: white;
}

.list {
  list-style-type: none;
  padding-left: 0;
  margin: 0;
  position: relative;
  cursor: -webkit-grab;
  cursor: grab;
}
.list:active {
  cursor: grabbing;
  cursor: -moz-grabbing;
  cursor: -webkit-grabbing;
}

.list__item {
  padding: 15px;
  background-color: white;
  position: relative;
}
.list__item .avatar {
  display: inline-block;
  background-color: #C0C4D7;
  border-radius: 4px;
  width: 60px;
  height: 60px;
}

.line-top,
.line-mid,
.line-bottom {
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
  border-radius: 8px;
  height: 8px;
  width: 50%;
  margin-left: 12px;
  position: absolute;
  background-color: #C0C4D7;
}

.line-top {
  top: 22px;
  width: 100px;
}

.line-mid {
  bottom: 40px;
}

.line-bottom {
  width: 65%;
  bottom: 26px;
}

.svg__wrapper {
  position: relative;
  z-index: 10;
  background-color: #8B90B1;
  cursor: -webkit-grab;
  cursor: grab;
}
.svg__wrapper:active {
  cursor: grabbing;
  cursor: -moz-grabbing;
  cursor: -webkit-grabbing;
}
.svg__wrapper svg:first-child {
  -moz-transform: translate3d(0, 93px, 0);
  -ms-transform: translate3d(0, 93px, 0);
  -webkit-transform: translate3d(0, 93px, 0);
  transform: translate3d(0, 93px, 0);
}
.svg__wrapper svg:nth-child(2) {
  position: absolute;
  top: 93px;
  left: 116px;
}
.svg__wrapper svg #progress {
  stroke-dashoffset: 345.6;
  stroke-dasharray: 345.6;
}
.svg__wrapper .border {
  position: absolute;
  top: 100%;
  width: 100%;
  height: 20px;
  background-color: #fff;
} 

Step 3 (JavaScript Code):

Now, let's add the functionality with JavaScript:

  1. Step 1: Detect when the user is pulling down.
  2. Step 2: Determine the threshold for a successful pull.
  3. Step 3: Trigger a refresh function when the threshold is met.
  4. Step 4: Update the content and reset the UI.

I'll break down the code step by step:

1. $(document).ready(function() { ... });: This code is wrapped in a document ready event handler, which means it will only run after the document (HTML) has fully loaded. This is a common practice to ensure that the JavaScript code runs when the HTML elements it depends on are available.

2. Variables are defined:

  • START, LIMIT, LIST, CURVE, CIRCLE, FRICTION, FPS, DIFFERENCE, ANIMATING, TRANSLATE_HEIGHT, REACHED_END, CURVE_HEIGHT, START_CURVE, and END_CURVE are all declared as variables with various values. These variables are used throughout the script to control different aspects of the animation.

3. Event listeners:

  • There's an event listener attached to the .list__wrapper element for both 'touchstart' and 'mousedown' events. When the user interacts with this element, it triggers the scrolling animation.
  • The touchstart and mousedown events are used to detect the start of a touch or mouse interaction, and the touchmove and mousemove events are used to track the movement of the user's finger or mouse. This allows the animation to respond to user input.

4. The backToStart() function:

  • This function is called when the user ends their interaction (via touchend or mouseup events) with the .list__wrapper element.
  • It animates the list to return to its initial position and adjusts the opacity of elements during the animation.

5. Other helper functions:

  • translateSVG(offset) is used to translate the SVG element (the curve) as the user scrolls.
  • setOpacity(distance) adjusts the opacity of elements based on the user's scrolling distance.
  • runAnimation() function is responsible for running the main animation sequence when the user reaches a certain scrolling distance.

6. The outerCurve(height) and createCurve(height) functions modify the SVG curve element to create the effect of the curve changing shape as the user scrolls.

$(document).ready(function () {
  var START = undefined,
    LIMIT = 100,
    LIST = $('.list__wrapper'),
    CURVE = $('#curve'),
    CIRCLE = $('#circle'),
    FRICTION = 1,
    FPS = 35,
    DIFFERENCE,
    ANIMATING,
    TRANSLATE_HEIGHT = 90,
    REACHED_END = false,
    CURVE_HEIGHT = 190,
    START_CURVE = 'M-10 90 Q 161 90 332 90',
    END_CURVE = 'M-10 90 Q 161 120 332 90';

  $('.list__wrapper').on('touchstart mousedown', function (event) {
    event.stopPropagation();
    event.preventDefault();
    START =
      event.clientY ||
      event.originalEvent.touches[0].clientY ||
      event.originalEvent.changedTouches[0].clientY;

    $(window).on('touchmove mousemove', function (event) {
      event.stopPropagation();
      event.preventDefault();

      if (ANIMATING) {
        return false;
      }
      if (event.type === 'touchmove') {
        var touch =
          event.originalEvent.touches[0] ||
          event.originalEvent.changedTouches[0];
        DIFFERENCE = (START - touch.clientY) * -1;
      } else {
        DIFFERENCE = (START - event.clientY) * -1;
      }

      if (DIFFERENCE < TRANSLATE_HEIGHT) {
        translateSVG(DIFFERENCE);
        setOpacity(DIFFERENCE);
        REACHED_END = false;
      } else if (DIFFERENCE > TRANSLATE_HEIGHT && DIFFERENCE < CURVE_HEIGHT) {
        outerCurve(DIFFERENCE);
        setOpacity(DIFFERENCE);
        REACHED_END = false;
      } else if (DIFFERENCE >= CURVE_HEIGHT) {
        REACHED_END = true;
      }
    });
  });

  $(window).on('touchend mouseup', function (event) {
    event.stopPropagation();
    event.preventDefault();
    START = 0;
    if (REACHED_END) {
      runAnimation();
    } else {
      backToStart();
    }
    $(window).off('mousemove');
  });

  function backToStart() {
    if (DIFFERENCE > TRANSLATE_HEIGHT) {
      setTimeout(function () {
        $({
          x: parseInt($('.list__wrapper').css('transform').split(',')[5]),
        }).animate(
          {
            x: -183,
          },
          {
            duration: 300,
            step: function (now) {
              $('.list__wrapper').css({
                transform: 'translate3d(0,' + now + 'px,0)',
              });
            },
          }
        );
      }, 100);
      $('.list').velocity({
        opacity: 1,
        duration: 300,
        delay: 200,
      });
      $('#curve').velocity(
        {
          tween: [90, DIFFERENCE],
        },
        {
          duration: 150,
          loop: false,
          /*easing: [ 300, 8 ],*/
          easing: 'easeOutCubic',
          progress: function (e, c, r, s, t) {
            if (t > 90) {
              $('#curve').attr('fill', '#8B90B1');
            } else {
              $('#curve').attr('fill', 'white');
            }
            createCurve(t);
          },
        }
      );
    } else {
      $({
        x: parseInt($('.list__wrapper').css('transform').split(',')[5]),
      }).animate(
        {
          x: -183,
        },
        {
          duration: 300,
          step: function (now) {
            $('.list__wrapper').css({
              transform: 'translate3d(0,' + now + 'px,0)',
            });
          },
        }
      );
      $('.list').velocity({
        opacity: 1,
        duration: 300,
        delay: 200,
      });
    }
  }

  function translateSVG(offset) {
    var dist = offset - 183;
    if (dist > -188) {
      $(LIST).css({
        transform: 'translate3d(0,' + dist + 'px,0)',
      });
    }
  }

  function setOpacity(distance) {
    distance = 140 - distance;
    var pct = distance / 140;
    $('.list').css({
      opacity: pct,
    });
  }

  function runAnimation() {
    ANIMATING = true;

    $('svg:first-child').css({
      filter: 'url(#goo)',
      '-webkit-filter': 'url(#goo)',
      '-moz-filter': 'url(#goo)',
      '-o-filter': 'url(#goo)',
      '-ms-filter': 'url(#goo)',
    });
    $('#curve').velocity(
      {
        tween: [90, 200],
      },
      {
        duration: 700,
        loop: false,
        easing: [0, 3, 0.3, 0.4],
        progress: function (e, c, r, s, t) {
          if (t > 90) {
            $('#curve').attr('fill', '#8B90B1');
          } else {
            $('#curve').attr('fill', 'white');
          }
          createCurve(t);
        },
      }
    );
    setTimeout(function () {
      $('#circle_group').attr({
        cy: 110,
      });
      $('#circle').attr({
        fill: 'rgba(255,255,255,1)',
      });
      $('#circle').velocity(
        {
          cy: 45,
        },
        {
          duration: 200,
          easing: 'easeOutSine',
        }
      );

      $('#progress').velocity(
        {
          strokeDashoffset: 0,
        },
        {
          duration: 800,
          delay: 300,
        }
      );
      $('svg:nth-child(2)').velocity(
        {
          scale: 1.15,
          opacity: 0,
        },
        {
          duration: 400,
          delay: 1200,
          easing: [0.11, 1, 0.34, 0.98],
        }
      );
      setTimeout(function () {
        $('#curve').attr('d', END_CURVE);
      }, 1450);
      setTimeout(function () {
        $('svg:first-child').css({
          filter: 'none',
          '-webkit-filter': 'none',
          '-moz-filter': 'none',
          '-o-filter': 'none',
          '-ms-filter': 'none',
        });
      }, 1800);
      $('#circle').velocity(
        {
          cy: 140,
        },
        {
          duration: 450,
          delay: 1300,
          complete: function () {
            $('#curve').attr('d', START_CURVE);
            $({
              x: parseInt($('.list__wrapper').css('transform').split(',')[5]),
            }).animate(
              {
                x: -183,
              },
              {
                step: function (now) {
                  $('.list__wrapper').css({
                    transform: 'translate3d(0,' + now + 'px,0)',
                  });
                },
              }
            );
            $('.list').velocity(
              {
                opacity: 1,
              },
              500
            );
            $('#circle').attr('cy', 190);
            $('#progress').css({
              strokeDashoffset: 345.6,
            });
            $('svg:nth-child(2)').velocity(
              {
                scale: 1,
                opacity: 1,
              },
              0
            );
            REACHED_END = false;
            ANIMATING = false;
          },
        }
      );
    }, 50);
  }

  function outerCurve(height) {
    var FRICTION_HEIGHT = height * FRICTION;
    var d = 'M0 90 Q 161 ' + FRICTION_HEIGHT + ' 322 90';
    $(CURVE).attr({
      d: d,
      fill: '#8B90B1',
    });
  }

  function createCurve(height) {
    var FRICTION_HEIGHT = height * FRICTION;
    var d = 'M-10 90 Q 161 ' + FRICTION_HEIGHT + ' 332 90';
    $(CURVE).attr('d', d);
  }
});

Final Output:

Creating Pull to Refresh with HTML, CSS, and JavaScript.gif

Conclusion:

Congratulations! You've successfully created a Pull to Refresh feature using HTML, CSS, and JavaScript. This user-friendly addition will improve your web app's interactivity and engagement.

With this comprehensive guide, you're ready to enhance your web application with Pull to Refresh, ensuring a seamless and engaging user experience.

Code by: Jonas Badalic

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post