Scroll Indicator

Create a simple scroll indicator for your website. An animated arrow to show that content is below the fold.

scroll arrow

Take a look at the demo over on Codepen.


While working on a new site that should debut soon as the home for an app development studio that I am helping to start, I began playing around with a large, almost full-screen, header. I wanted to clearly indicate more information on scroll and developed a quick CSS arrow indicator. After playing with it more on Codepen, I decided to add some extra functionality and debut it there. Here is a more detailed write-up on how to create something similar for yourself.

Want to integrate the arrow on a Wordpress site? Skip the below tutorial and check out Scroll Indicator in Wordpress instead. It includes all the information on how to take the code and add it to a Wordpress theme.

The basic HTML

First things first: the HTML. The overall layout is super basic, but you can add content in the holes.

<section class="header">
<section class="main">
  <a class="arrow-wrap" href="#content">
    <span class="arrow"></span>


The CSS is where most of the interesting bits happen. First, we can make the header section of the page actually take up most of the page. For this we will use calc() to keep things just below 100%.

html, body {
  height:100%; /* allows us to size the header height based as a percent */

.header {
  height:calc(100% - 3em); /* subtract an amount of space for your arrow element */

.main {

With that we have the header defined and a content section just below it. Now for the CSS arrow. For this, we will use a pseudo element to create an arrow from two triangles.

/* the wrapper element that will become the outer circle */
.arrow-wrap {
  padding:4em 2em;
  box-shadow:0px 0px 5px 0px #333;

/* a triangle to make the main part of the arrow. Adjust the border-color to fit your needs */
.arrow {
  width: 0px;
  height: 0px;
  border-style: solid;
  border-width: 3em 3em 0 3em;
  border-color: #ffffff transparent transparent transparent;
  -webkit-transform:rotate(360deg);/* added for better anti-aliasing on webkit browsers */

/* a pseudo element arrow placed on top of the other one with the same color as the wrapper */
.arrow:after {
  width: 0px;
  height: 0px;
  border-style: solid;
  border-width: 3em 3em 0 3em;
  border-color: #111 transparent transparent transparent;
  -webkit-transform:rotate(360deg);/* added for better anti-aliasing on webkit browsers */


Now we can add a bit of CSS animation to make the arrow bounce after a delay.

  @-webkit-keyframes arrows {
    0% { top:0; }
    10% { top:12%; }
    20% { top:0; }
    30% { top:12%; }
    40% { top:-12%; }
    50% { top:12%; }
    60% { top:0; }
    70% { top:12%; }
    80% { top:-12%; }
    90% { top:12%; }
    100% { top:0; }
  .arrow-wrap .arrow {
    -webkit-animation: arrows 2.8s 0.4s;
    -webkit-animation-delay: 3s;

Play around the with animation as you will. It could be done it any number of ways, but stepping it by 10% seemed like a simple way of doing what I wanted. Make it spin, change color, whatever you want.

Adding some jQuery

scroll arrow transparency

Part of what I wanted to accomplish, however, was making the arrow disappear as the user actually did scroll. The arrow is only useful until the user realizes that there is something below the fold. To do this, we need to lean a bit on jQuery. The easiest thing is to follow the code below and pay attention to the comments.

//this is where we apply opacity to the arrow
$(window).scroll( function(){

  //get scroll position
  var topWindow = $(window).scrollTop();
  //multiply by 1.5 so the arrow will become transparent half-way up the page
  var topWindow = topWindow * 1.5;
  //get height of window
  var windowHeight = $(window).height();
  //set position as percentage of how far the user has scrolled 
  var position = topWindow / windowHeight;
  //invert the percentage
  position = 1 - position;

  //define arrow opacity as based on how far up the page the user has scrolled
  //no scrolling = 1, half-way up the page = 0
  $('.arrow-wrap').css('opacity', position);


Now, as the user scrolls, the arrow will become more transparent and eventually disappear. It provides a nice smooth effect. You can change the rate at which the transparency is applied by editing the multiplier on the topWindow variable: a higher multiplier = quicker disappearance.

Wrapping Up

Now you have the majority of the demo finished. I stole a snippet from CSS-Tricks to add some smooth scrolling when the user clicks on the arrow to scroll down, but you can implement this in many different ways. Grab the code, make it your own, and enjoy!

Happy coding.

47 thoughts on “Scroll Indicator

  • I would like to use this in a Bootstrap Modal. I have tried to apply the code but with no success. I am not sure where in the modal I would place the div, subsequently I am not sure how I would adjust the code so it fades in the right place. The modals are in the ‘Information’ list of links to the right of the page via the url provided.

    Any help is appreciated!

    • Hi, Steven. Great to hear that you want to implement this. Where to place the div within your modal is hard to say without seeing what you want to achieve there (i.e. what you want to be place above the arrow).

      For the rest, however, you should just have to fiddle a bit with the jQuery. In the above example, I am getting the scroll position and info based on the window size. For a modal implementation, you would want to take these measurements based on the HTML wrapper for the scrolling modal window. For your case you could replace (as an example) $(window) with $(.modal-body). In final implementation you wouldn’t want to do this using the class, though.. define ids and use those instead, if you have multiple modal windows).

      Then getting the arrow to fade properly can be adjusted in the math of how (in the above example) topWindow is calculated.

      Hope this helps! If not, feel free to comment again :)

  • Thank you for this. I am having a bit of a problem. When I put in this code I had to change the html, body {height:100%; to 0. Either way, the arrow/circle remained at the top, not the bottom of my header. What might I need to change?

    • Glad you are trying to implement this. The reason for having declared the html and body to height 100% was to allow the header to fit the height of the current window. In your site, it seems that the header will have a fixed height, thus the header doesn’t need to dynamically change to fit the viewport. For this, then, you should just be able to place the arrow within the header and position it absolutely at the bottom of the header. Note that the header needs to have position:relative; declared (or absolute, but only if necessary for other formatting).

      Let me know if this fixes your issue. If not, some clarification is probably needed. A link to a version of the site you are working on with the broken arrow would be most helpful. Good luck!

  • Hi there rob

    I have used your arrow in my site but for some reason the disappearing arrow doesn’t work. Any ideas?

    thanks for your help

    • Hello! Am glad you are working on adding the arrow to your site. I looked quickly at it and your site is throwing an error that $ is undefined. What this likely means (based on some really quick digging) is that you aren’t properly loading jQuery onto the page. Since you are using squarespace (which is a pretty cool tool), you should maybe take a look at this:

      Once you do that, you can give it another go :) I also noticed that you have the arrow positioned rather haphazardly. I would suggest placing it within the ‘banner-thumbnail-wrapper’ div at the top of your page, if at all possible. Then you can position it absolutely to fit just at the bottom of the image. I am not sure how one would do this in squarespace, however, so you may have to do some googling if you don’t know. Feel free to ping me with any more questions and happy coding!

  • Thanks again Rob

    that has sorted it out.
    Yeah i cant position the arrow anywhere i want unless i go into developer mode – which with my experience level is probably not a good idea. Just have to put it where the squarespace interface lets me.

    thanks again for your help

  • I was able to get the arrow and all that on the square space site but is there a way to make the circle smaller? And is there a way to have it so it’s transparent right off the bat?

    Thank you!

    • Hi Daniel!

      I am glad you are using the arrow on your site. I built it specifically using “ems” to define the sizes so that it could remain very flexible. For those that don’t know, an “em” is a flexible size unit that is based (roughly) on the width on the “m” character. What this means for web design is that you can set all units to use “ems” and they will inherit the specified size of the font. For this case, all we need to do is change the “font-size” declaration in the .arrow-wrap class. Currently it is set to 0.5ems… to make the arrow smaller, just make this value smaller.

      So, for example, to reduce the size by 50%, you just need to change the following in the CSS file:

      .arrow-wrap {

      And make it a smaller value.

      In quickly testing this, I noticed that it can make the arrow look a bit funky at certain sizes. This is due to the “left” position of the psuedo-element (.arrow:after). If you do notice the arrow is looking weird, you probably need to find the following:

      .arrow:after {
          left:; /* this may need some very minor tweaking for best results */

      Now, on to making the arrow transparent from the beginning. To do so, you need to go into the jQuery code provided. Here, all you need to do is find the line:

      position = 1 - position;

      and make the position variable a smaller value, such as:

      position = 1 - position - 0.3;

      This will make the opacity of the arrow begin at 70% rather than 100%. If you used “0.5″ instead of “0.3″, for example, the opacity would start at 50%.

      I hope that helps and was all understandable! If you need more help, feel free to send me an email and I can take a look specifically at your code.

      Happy coding!

  • Hi! great tool! I’ve a question, please. How can i do to inverse wor? I mean, start invisible and when scroll fade to visible? i cant figure that… Thanks!
    PD: I have to indicate both: to scroll down when start, and scroll up when ive just scrolled down. Thanks again!

    • Hello! To make the arrow become visible as the user scrolls down, just remove this line of code:

      position = 1 - position;

      In the current code, this flips the position value, so removing it means it will work in the opposite direction :)

    • I realized I may have made this too simple and you may be wanting to anchor the arrow to the bottom and have it fade in when the user hits the bottom of the page. If that is the case, here is some code to help you :)

      $(window).scroll( function(){
        var windowHeight = $(window).height();
        var docHeight = $(document).height();
        var docBottom = docHeight - windowHeight;
        var windowPos = $(window).scrollTop();
        var windowPos = docBottom - windowPos;
        var windowPos = windowPos * 1.3;
        var position = windowPos / windowHeight;
        var position = 1 - position;
        $('.arrow-wrap').css('opacity', position);

      It is finding the height of the whole page, then finding what section of that is equal to the bottom “section” of the page (a section being equal to the height of the window). I think this should work regardless of the height of the page, but I could be wrong ;)

      You will, of course, have to change the CSS around for the arrow to have it appear where you want it, but the jQuery should do the rest. Let me know if you have issues!

  • So, this looks awesome, and I’d really love to implement it.. but so far, I have had zero luck. I’ll admit that I have absolutely zero coding knowledge, and am working from the SquareSpace platform as well. I have some code injected into my footer to make the banner only on my homepage fullscreen, and I’m not sure if that’s interfering, but when I add this code (not even sure if I’m putting it in the right place), I get nothing. Any advice or help would be incredibly appreciated. Thanks either way. :)

    • Glad you like it! I haven’t specifically worked with SquareSpace before, so I can only be of limited help here, but it is likely that the code isn’t being injected in the right space. If you are still working on this and want some help, feel free to email me a link to the site where you have it implemented and I can take a look in the code side and see if there are some answers there :)

    • Glad you are using it on your site! I just took a look, but it seems like you got the scrolling working already :) If you ever want to use it to scroll to a specific target on a page, just use the “id” as the anchor target (like I do in the example with href=”#content”, where “content” is the id of the scroll target).

      • Hi Rob!

        I was looking for a simple way to add this feature to my site and came across your coding. I’m having a bit of a tough time tailoring it however. I’ve got a decent understanding but I’m no pro when it comes to this stuff. My site is responsive and I can’t seem to figure out what coding I should add to make the arrow responsive. On a mobile below 460px width the arrow is in no mans land. Could you point in the right direction? or perhaps is there something I can write in that below a certain screen width that the arrow disappears?

        • Hi Tyrone!

          I just took a look at your site to see what was going on with the arrow and think I understand what is going on. It really depends a bit on exactly what you are hoping to do with it. If you take a look at the example above, you will see that I positioned the arrow within the content (white) section of the page. Thus it always stays glued to the top of the white section. It seems that you are positioning the arrow from the top of the top section of your page, which means that the arrow cannot flow or respond to the height of the content there. I would suggest either placing the arrow within the content section and positioning it based on a top value from there (this can also be negative, if you want to floating somewhat in the top section), or placing it based on the bottom of the top section (replace the “top:” value with “bottom:”).

          Let me know if this helps or if you are looking for something else there :)

          • Hey Rob,

            Thanks a lot for even taking the time to respond!
            I’m getting ready to sit down and attack this again. I’ll take your advice into consideration and see if I can make this happen.



          • Just wanted to give you an update!
            I’m 99% percent there. The only issue I’m having now is the arrow doesn’t appear properly on an iPad otherwise I’ve got it working flawlessly even responsively so pretty stoked.

            Thanks again for everything!

    • Though iframes can be quite a pain, that doesn’t seem to be what is going on here. For this page, you are using a jquery.sticky.js file that is intended to apply exactly the behavior that you are seeing — it takes the div “sticker-sticky-wrapper” you have in your page and adds a class to it to make the div stick to the top of the page after you have scrolled beyond a certain point. From what I can see, this isn’t doing anything except cause the weird behavior you are seeing. Are you intending to use this sticky behavior for anything?

      To fix it, the easiest thing is to:
      - Change the class and id of the div (id=”sticker-sticky-wrapper”

      If you aren’t planning on using the sticky.js on your page, you should also delete the call to the file from your HTML — no reason to load a file if you aren’t using it:
      - Remove the following from the bottom of the page:

      <script src="js/jquery.sticky.js"></script>
      • Thanks for the quick response! I had intended to use the other jquery plugin, but it isn’t necessary anymore. Thanks again.

  • That is a great scroller. Only one question. How can i change the size of the botton. I would like it to be a little bit smaller and more transparent. How can i do that?

    • Hi! To change the size and transparency of the button, you just need to play a bit with the CSS. To change the size, simply change the “font-size:0.5em;” declaration in the “.arrow-wrap” CSS class. If you decrease the “em” value of the font-size, it will decrease the size of everything within the wrapper. Give “font-size:0.4em;” a try.

      To change the transparency, you will need to edit the jQuery a bit. The line position = 1 - position; defines the starting value of the transparency as 1 (fully opaque). To reduce this, change the “1″ value to something less. Try replacing it with position = 0.8 - position;

  • Hi Rob,
    I’d like to use this into WordPress any idea on how to integrate it into a template or maybe did you already packaged it for this CMS?

  • Love this setup! I was wondering, do you have any advice for adding multiple arrows on a page? For example, I’m looking to use this to put at the bottom of 3 or 4 containers on the same page, each link taking the user to the next section below.

    While getting the arrows in place is easy enough, they all fade when I scroll a little bit – then they aren’t visible for the instances on the other divs.

  • Pingback: Scroll Indicator in Wordpress | Rob Sawyer Design

  • This has solved my portfolio site dilemma! I’m just starting out with web design (I’m a packaging designer by trade) And coupled with Bootstrap, Code Academy, Google searches, and Profanity, this tutorial/demo has saved my sanity.

    Thank you for this. I hope one day to be able to write this kind of thing myself.

  • Hi Rob,
    Say, is there a simple way to make the arrow stay hidden, once the user scrolled down (in the event that they scroll up again)?
    Thanks so much for offering this!

    • Hi Surya!

      Certainly! It depends a bit on exactly what behavior you want, but it would involve (in the jQuery code) setting a variable or storage item and then changing it once the user has scrolled. You can then wrap the line that changes the opacity in an if statement that checks against the state of the variable/storage item.

      I threw together a quick fork of the codepen with this implemented for you to have a look at:

      As noted in the code comments, you could replace the variable with a sessionStorage or localStorage item. If you aren’t familiar with these, a sessionStorage item is data saved throughout the session of the browser (until the user closes the browser). A localStorage item is saved indefinitely (until your or the user deletes it specifically) — like a cookie, but much nicer. What this means in this case, if you used them, would be that you could keep the arrow hidden for the session or indefinitely after the user scrolled the first time, if you wanted.

      Let me know if you have any other questions :) Otherwise, happy coding!

  • Hi Rob, first of all, I love this, great execution. Secondly, I’m trying to get it working on a Squarespace website and I’ve almost totally successfully got it operational. The one thing I’m really struggling to get it to do right now is scroll very far. Perhaps about 20% of the page. I’m targeting the main #page content div but even if I set a large static height on this div, it doesn’t seem to make a difference.

    Is there any chance you would mind please taking a quick look at my site and seeing if there’s something obvious I’m missing? The specific page is:

    I’d be amazingly grateful.

    - Matthew

    • Hi Matthew,

      Glad you are getting some use out of it! So the way the scrolling works when you use an anchor tag to link to an ID on the page is that it will scroll the viewport until the top of the scroll target is at the top of the viewport (or as close as it can go). In your page, the #page section is already near the top of the page, thus clicking on the arrow doesn’t make the page move up very much.

      Important to ask here is: to what point do you want the arrow to scroll the page? For example, if you just want it to scroll up roughly the size of the viewport (the current view of the page), you could set the link of the arrow to the id of the arrow, thus clicking it would scroll the page until the arrow was up at the top.

      Let me know if you have any more questions!

      • I just wanted to say thank you so much for replying so quickly and with the exactly the answer I needed. Really appreciate you checking this out for me. You rock!

        - Matthew

  • Hello! I really love the arrow and I am glad you are able to share with us:) I am using the divi theme and want to put this at the bottom of a section to scroll to another section. When I paste the code into the Custom CSS of the section I get nothing. Do you have any idea of where I am suppose to place this?

    • Hi Tyler!

      Glad to hear that you like it! I am assuming you mean that you want to integrate it into a WordPress theme? If so, I would suggest taking a look at this post: Scroll Indicator in WordPress. Due to the idiosyncrasies of WordPress, I put it together to exactly explain how to get this to work in a WordPress theme. It also includes a section related to where to put the CSS.

      If this doesn’t help you out, then just give me a shout and I will see how I can help (and let me know if you are not referring to WordPress).

  • hey whats up man i used your code for the scroll arrow and it works but im having an issue with it showing up above my header/banner image and not below it . it pretty much pushes the rest of my page down to be their

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>