How can I make an Upvote/Downvote button?

20,267

Solution 1

You could do it by adding a different picture to the background, one for every state of the button. There is however a cleaner, easier, more modern way of achieving this result: Sprites.

A sprite is an image that is saved as a part of a larger image. One of the biggest advantages of using sprites is the reduction of round-trips to the server for all the images to just one request for the Sprites. The element to display a picture has the image as background. The background is moved relative to the element so the element displays only part of the image. Like when you move a photo-frame over a poster (or in this case: moving the poster under the frame)

At SO they make an image that contains all the states for the button. They give the element for the button (a span in this case) a fixed width and height and add the background to it with CSS. Then toggle a class for the state (on or off) with javascript on the click event. Now the only thing you have to do in CSS is change the position of the background with CSS classes:

The up/down sprite image

for (const btn of document.querySelectorAll('.vote')) {
  btn.addEventListener('click', event => {
    event.currentTarget.classList.toggle('on');
  });
}
.vote {
  display: inline-block;
  overflow: hidden;
  width: 40px;
  height: 25px;
  cursor: pointer;
  background: url('http://i.stack.imgur.com/iqN2k.png');
  background-position: 0 -25px;
} 


.vote.on {
  background-position: 0 2px;
}
Click to vote (using sprites): <span class="sprite vote"> </span>

You can easily add more states to the sprites like 'hover' and 'active' just the same way. SO even puts all the images for the whole page in a single image. You can verify this with firebug or the Chrome developer tools. Look for 'sprites.png'.

Update (2020)

It's been 10 years since I answered this question and in this time, the landscape has changed. Now you can use inline svg as well to achieve this effect. I've updated the code snippet to use svg. This is how stackoverflow currently does this.

It works by toggling the color property of a surrounding span element on button click. The span element contains an inline svg image of an arrow. The fill property of the path that makes up the arrow is initialized with currentColor, which instructs it to take whatever is the current text color.

for (const btn of document.querySelectorAll('.vote')) {
  btn.addEventListener('click', event => {
    event.currentTarget.classList.toggle('on');
  });
}
.vote {
  display: inline-block;
  cursor: pointer;
  color: #687074
} 


.vote.on {
  color: #f48024
}
Click to vote (using svg): 
<span class="vote">
  <svg width="36" height="36">
    <path d="M2 10h32L18 26 2 10z" fill="currentColor"></path>
  </svg>
</span>

Solution 2

You can do it by using two simple images ... design two images in some image editors like Photoshop, if u don't have MSPaint...

CSS code is

#voting{
   width:30px;
   height:40px;
}
.upvote{
   width:30px;
   height: 20px;
   cursor: pointer;
}
.downvote{
   width:30px;
   height: 20px;
   background: url('downvote.jpg') 0 0 no-repeat;
   cursor: pointer;
}

HTML code :

<div id="voting">
    <div class="upvote"></div>
    <div class="downvote"></div>
</div>
Share:
20,267

Related videos on Youtube

user519753
Author by

user519753

Updated on July 09, 2022

Comments

  • user519753
    user519753 almost 2 years

    This is just for the styling, I'm trying to make an upvote/downvote the same way that it's done on SO and Reddit, from what I can see they use arrow images as backgrounds and then position it, but I'm a CSS newbie and I need someone to walk me through it. Thanks in advance.

  • Waleed Al-Balooshi
    Waleed Al-Balooshi over 13 years
    +1 The technique is called CSS Sprites and provides better performance than the alternative, which is to have a separate image for each button state. You will probably want to add all four states into one image then change the background as Jan specified.
  • Jan
    Jan over 13 years
    Yes, but for this application it is pretty basic. You should learn the basics anyway if you want to develop for the web.
  • StoopidDonut
    StoopidDonut over 9 years
    @Jan Exactly what I was looking for!
  • David Weisser
    David Weisser over 3 years
    How would you incorporate a downvote option? A second sprite?
  • Jan
    Jan over 3 years
    @DavidWeisser you would add two more sprites for the downvote button in the same image and use the same technique to position the background in a way that it toggles between those two states. Alternatively you can use inline svg to achieve the same effect , I updated the answer to include that technique (SO has been updated in the meantime to use this technique)
  • zoldxk
    zoldxk almost 3 years
    Can you add the svg path for the upvote >