26

How do I style a button, with a shadow, so that it looks like it is pressed in?

I tried using box-shadow: ... ;. But this didn't have any affect.

Red
  • 6,599
  • 9
  • 43
  • 85
philr
  • 1,860
  • 1
  • 21
  • 31

7 Answers7

50

By creatively styling the :active or :focus pseudo classes using a box-shadow: inset ...;

Using the :active pseudo class:

button {
  background: #ededed;
  border: 1px solid #ccc;
  padding: 10px 30px;
  border-radius: 3px;
  cursor: pointer;
}

button:active {
  background: #e5e5e5;
  -webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
     -moz-box-shadow: inset 0px 0px 5px #c1c1c1;
          box-shadow: inset 0px 0px 5px #c1c1c1;
   outline: none;
}
<button>
  Click me
</button>

Using the :focus pseudo class:

button {
  background: #ededed;
  border: 1px solid #ccc;
  padding: 10px 30px;
  border-radius: 3px;
  cursor: pointer;
}

button:focus {
  background: #e5e5e5;
  outline: none;
  -webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
     -moz-box-shadow: inset 0px 0px 5px #c1c1c1;
          box-shadow: inset 0px 0px 5px #c1c1c1;
}
<button>
  Click me
</button>
Red
  • 6,599
  • 9
  • 43
  • 85
  • thanks for this active: alternative, helpful for me! but you got lots of thumbs up for the original, maybe there is a market for buttons that get pressed and stay down :D (maybe leave both options?) – Andrew Feb 20 '18 at 14:27
  • @Jacques Thats wierd, I just tested it and it works fine. And it should work fine, what exacly doesn't work? – Red Jul 10 '18 at 06:37
  • @Red Sorry I realised I was not clear enough. When using the `:active`pseudo class, it works, but not with the `:focus`. Nothing happens then when clicking on the button. No change of background colour. – Jacques Jul 11 '18 at 02:00
  • @Jacques It works here, using FireFox Quantum v61. `:focus` changes background-color and shadow – Red Jul 11 '18 at 06:35
  • @Red That's weird it works on your version and not on mine then. Tried with FF Developer Edition with same negative result. – Jacques Jul 11 '18 at 16:48
  • @Jacques Which operating system are you using? – Red Jul 12 '18 at 06:34
  • @Red I am using MacOSX Yosemite (10.10.5) – Jacques Jul 13 '18 at 21:27
14

As an alternative to buttons, there is also a possibility to simply use checkbox with the pseudo-class :checked to toggle between states.

label.label-checkbox {
  cursor: pointer;
}


label.label-checkbox input {
  position: absolute;
  top: 0;
  left: 0;
  visibility: hidden;
  pointer-events: none;
}

label.label-checkbox span {
  padding: 11px 21px;
  border: 1px solid #ccc;
  display: inline-block;
  color: #202020;
  border-radius: 6px;
  margin: 7px;
  background: #f5f5f5;
  user-select: none;
}

label.label-checkbox input:checked + span {
  box-shadow: inset 1px 2px 5px #777;
  transform: translateY(1px);
  background: #e5e5e5;
}
<h1>Pressed buttons with Checkbox</h1>

<label class="label-checkbox">
  <input type="checkbox">
  <span>Checkbox</span>
</label>
<label class="label-checkbox">
  <input type="checkbox" checked>
  <span>Styled</span>
</label>
<label class="label-checkbox">
  <input type="checkbox">
  <span>As</span>
</label>
<label class="label-checkbox">
  <input type="checkbox" checked>
  <span>Pressed</span>
</label>
<label class="label-checkbox">
  <input type="checkbox">
  <span>Buttons</span>
</label>
Sondre
  • 251
  • 2
  • 5
7

The best way is to nudge the button lower on the page. Using transformY would be the most straight-forward. However that can mess up the layout of other things in the page. So I think that it is better to use margin to temporarily lower the button, such as,

button {
    background-color: white;
    padding: 10px;
    vertical-align: top;
    box-shadow: 2px 1px 2px gray;
    margin: 4px 10px 4px 10px;
}

button:active {
    box-shadow: 0 0 0 white;
    margin: 6px 10px 2px 10px;
}
<button>click me</button>
<button>click me</button>
<br>
<button>click me</button>
<button>click me</button>

As in the example, you can take away 2px from the bottom margin, and add 2px to the top margin, therefore you preserve the total size of the button.

You need vertical-align in case there are more than one button.

John Henckel
  • 10,274
  • 3
  • 79
  • 79
  • 1
    You've got it backwards. First of all, there's no `transformY`. Changing the margin can mess up the layout of other things in the page, but you're accounting for that in your example because you're changing both the top _and_ the bottom margin. `transform: translateY(2px)` will not affect the layout of other elements. If you wanted a button with no margin, it wouldn't work as well. Note in [this example](https://codepen.io/VAggrippino/pen/Jjdaavz) that the button which changes its margin when you click it forces the other elements to move, but the button which uses the transform doesn't. – Vince Mar 23 '20 at 09:19
  • 1
    @Vince thanks for pointing that out. I don't remember the particulars. When I tried it last year, the margin trick definitely worked better. But I see your pen works better with translateY. – John Henckel Mar 24 '20 at 21:18
3

I think that the best way to make a button looks like it's pressed it's to make it a little darker.

button{
  background-color: #03A9F4;
  border: none;
  padding: 15px 25px;
  text-transform: uppercase;
  color: white;
  font-weight: 700;
  border-radius: 3px;
}
button:hover, button:focus{
  background-color: #0074a9;
  outline: none;
}
<button>Button</button>
therealbischero
  • 224
  • 1
  • 11
  • 4
    too basic, by making it change color on hover before clicking, it gives 0 impression of a press happening. – Andrew Feb 16 '18 at 19:35
0

If you think visually about what happens when a push-button (like on an old-style stereo system) is pushed in, the button moves back. Visually, the face of the button is darker. The text on the button is inset. The border of the button is dark.

The other answers here all give part of the answer.

This visually does all of the above:

.btnPushed {
  color: #efefef; //orig text color was #FFF
  text-shadow: -1px -1px 0px #777, -1px -1px 0px #777;
  box-shadow: inset 1px 1px 4px #222;
  transform: translateY(1px); /*  Add per Vince's helpful comment  */
}

As you might notice, we apply the styling by adding a class.

$('button').click(function(){
  $('button').removeClass('depressed');
  $(this).addClass('depressed');
});
button {
   border: 1px solid black;
   border-radius: 3px;
   color: #f5f5f5;
   background-color: #b8860b;
   background-image: linear-gradient(-180deg,#6699FF,#3473F5 90%);
   cursor: pointer;
   font-size: 14px;
   line-height: 20px;
   outline: none; /* Removes Chrome's blue outline */
   margin: 2px;
}
button:active{
}
.depressed{
   color: #efefef;
   text-shadow: -1px -1px 0px #777, -1px -1px 0px #777;
   box-shadow: inset 1px 1px 3px #222;
   margin: 3px -1px -1px 3px; /* T R B L */
   transform: translateY(1px);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<button>Button1</button>
<button>Button2</button>
<button class="depressed">Button3</button>
<button>Button4</button>

To avoid the adjustment (movement) of the other buttons due to the margin change, just put each button into a fix-size div. That way the buttons move around within their divs, without affecting the other buttons inside their own divs.

$('button').click(function(){
  $('button').removeClass('depressed');
  $(this).addClass('depressed');
});
div {
   display: inline-block;
   width: 65px;
   height: 25px;
}
button {
   border: 1px solid black;
   border-radius: 3px;
   color: #f5f5f5;
   background-image: linear-gradient(-180deg,#6699FF,#3473F5 90%);
   cursor: pointer;
   font-size: 14px;
   line-height: 20px;
   outline: none; /* Removes Chrome's blue outline */
   margin: 2px;
}
button:active{
}
.depressed{
   color: #efefef;
   text-shadow: -1px -1px 0px #777, -1px -1px 0px #777;
   box-shadow: inset 1px 1px 3px #222;
   margin: 3px -1px -1px 3px; /* T R B L */
   transform: translateY(1px);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div><button>Button1</button></div>
<div><button>Button2</button></div>
<div><button class="depressed">Button3</button></div>
<div><button>Button4</button></div>

Update:

Added transform: translateY(1px), per Vince's helpful comment below.

halfer
  • 19,824
  • 17
  • 99
  • 186
cssyphus
  • 37,875
  • 18
  • 96
  • 111
  • 1
    That's a lot of overhead for a simple button effect. Why not just use the `:active` pseudo class? I don't like the text shadow, but that's just an opinion. [My example](https://codepen.io/VAggrippino/pen/yLNxxGj) is inspred by yours, but doesn't need an entire JavaScript library to get the desired effect. – Vince Mar 23 '20 at 09:38
  • You codepen adds `transform: translateY(1px);`, which I like very much. *(In fact, I'd intended to include that in my answer but forgot.)* However, I disagree with using the `:active, :focus` pseudo-classes, since that only works as long as the button keeps the focus. In your example, as soon as you click another part of the screen, you lose the depressed button effect. On a 1970s car stereo, it wouldn't do if the preset-station button popped back out when you adjust the volume...? As for the use of jQuery, it is absolutely not needed merely to apply a class - it was just a preference here. – cssyphus Mar 23 '20 at 16:35
  • @cssyphus Wouldn't it be better to use checkbox for that functionality? Then design it like a button or whatever. – Sondre Mar 08 '21 at 10:35
  • Hi @Sondre The purpose was to create a visual indication that one (within a group of buttons) is pushed in, like the 1970s car radio. Sure, we could use checkboxes for that purpose (although radio buttons are even more to the point) but those are more difficult to style. Designers have been using Divs and Buttons as radio buttons for years now for that reason. A long time ago I found some perfect examples (html/css), but they were so easily found at that time that I didn't bookmark them thinking I would have no problem finding them in future. Silly me. – cssyphus Mar 08 '21 at 15:47
  • Hi @cssyphus! Yes, I understand, seemed like it would be better to structure as checkbox and avoid the use of JavaScript. Created an example here: https://jsfiddle.net/L8y4mwhe/ – Sondre Mar 09 '21 at 14:35
  • I like that example, Sondre. Please add it to the list of answers for this question *(in the answer editor, press [Ctrl]+[m] to add a jsfiddle-like snippet inside your SO answer)* and you will get a guaranteed upvote from me. Then, if you wouldn't mind, please `@cssyphus` me in a comment and let me know you added your answer - I don't want to forget to check for it. – cssyphus Mar 09 '21 at 14:56
-2

.button{
color: white;
background-color: blue;
padding: 8px 25px;
border-radius : 7px;
}
.button:active {
    box-shadow: 0 0 0 black;
    margin: 3px 0 0 0 ;
}
<input type="button" class="button" value="Enter">
  • 1
    I wonder, could you edit this answer to explain why it answers the question? Often some supporting body text goes a long way to educating future readers. – halfer Mar 09 '21 at 20:23
-3

button{
background-color:grey;
padding:10px;
border:none;
color:white;

}
button:hover{
background-color:black;
color:white;
}
<button class"b1">button</button>