Reputation: 7956
I have an image element that I want to change on click.
<img id="btnLeft">
This works:
#btnLeft:hover {
width: 70px;
height: 74px;
}
But what I need is:
#btnLeft:onclick {
width: 70px;
height: 74px;
}
But, it doesn't work, obviously. Is it possible at all to have onclick
behavior in CSS (i.e., without using JavaScript)?
Upvotes: 530
Views: 1827870
Reputation: 21100
The best way (actually the only way*) to simulate an actual click event using only CSS (rather than just hovering on an element or making an element active, where you don't have mouseUp) is to use the checkbox hack. It works by attaching a label
to an <input type="checkbox">
element via the label's for=""
attribute.
This feature has broad browser support (the :checked
pseudo-class is IE9+).
Apply the same value to an <input>
's ID attribute and an accompanying <label>
's for=""
attribute, and you can tell the browser to re-style the label on click with the :checked
pseudo-class, thanks to the fact that clicking a label will check and uncheck the "associated" <input type="checkbox">
.
* You can simulate a "selected" event via the :active
or :focus
pseudo-class in IE7+ (e.g. for a button that's normally 50px
wide, you can change its width while active
: #btnControl:active { width: 75px; }
), but those are not true "click" events. They are "live" the entire time the element is selected (such as by Tabbing with your keyboard), which is a little different from a true click event, which fires an action on - typically - mouseUp
.
label {
display: block;
background: lightgrey;
width: 100px;
height: 100px;
}
#demo:checked + label {
background: blue;
color: white;
}
<input type="checkbox" id="demo"/>
<label for="demo">I'm a square. Click me.</label>
Here I've positioned the label right after the input in my markup. This is so that I can use the adjacent sibling selector (the + key) to select only the label that immediately follows my #demo
checkbox. Since the :checked
pseudo-class applies to the checkbox, #demo:checked + label
will only apply when the checkbox is checked.
#btnControl {
display: none;
}
#btnControl:checked + label > img {
width: 70px;
height: 74px;
}
<input type="checkbox" id="btnControl"/>
<label class="btn" for="btnControl"><img src="https://picsum.photos/200/300" id="btnLeft" /></label>
With that being said, there is some bad news. Because a label can only be associated with one form control at a time, that means you can't just drop a button inside the <label></label>
tags and call it a day. However, we can use some CSS to make the label look and behave fairly close to how an HTML button looks and behaves.
#btnControl {
display: none;
}
.btn {
width: 60px;
height: 20px;
background: silver;
border-radius: 5px;
padding: 1px 3px;
box-shadow: 1px 1px 1px #000;
display: block;
text-align: center;
background-image: linear-gradient(to bottom, #f4f5f5, #dfdddd);
font-family: arial;
font-size: 12px;
line-height:20px;
}
.btn:hover {
background-image: linear-gradient(to bottom, #c3e3fa, #a5defb);
}
.btn:active {
margin-left: 1px 1px 0;
box-shadow: -1px -1px 1px #000;
outline: 1px solid black;
background-image: linear-gradient(to top, #f4f5f5, #dfdddd);
}
#btnControl:checked + label {
width: 70px;
height: 74px;
line-height: 74px;
}
<input type="checkbox" id="btnControl"/>
<label class="btn" for="btnControl">Click me!</label>
Most of the CSS in this demo is just for styling the label element. If you don't actually need a button, and any old element will suffice, then you can remove almost all of the styles in this demo, similar to my second demo above.
Upvotes: 603
Reputation: 6770
If for some reason you can't use JavaScript, the following workaround is your best bet to create a toggle button. The <details>
HTML element creates a disclosure widget to hide and show content. We're going to (ab)use the <details>
element and some CSS, so let's call it the "details hack".
Here's a basic example.
details[open] summary {
color: red;
}
<details>
<summary>Toggle</summary>
</details>
Clicking the <summary>
element toggles the <details>
' open
attribute and the <summary>
's style. You can also toggle the style of the <details>
' next siblings.
details[open] summary {
color: red;
}
details[open] ~ p {
color: blue;
}
<details>
<summary>Toggle</summary>
</details>
<p>Hello, world!</p>
An advantage of this method over the checkbox hack is that the button is keyboard accessible.
<summary>
's contents can be any heading content, plain text, or HTML that can be used within a paragraph.<summary>
's display
default value is list-item
. To remove the list item's triangle ::marker
, change the value to inline-flex
, for example.summary {
display: inline-flex;
}
Alternatively, you may use one of the following rules:
summary {
list-style: none;
}
summary::marker {
content: none;
}
To remove the disclosure triangle in Safari, use the following as well:
summary::-webkit-details-marker {
display: none;
}
summary {
display: inline-flex;
}
summary::-webkit-details-marker {
display: none;
}
details[open] img {
width: 75px;
height: 75px;
}
<details>
<summary><img src="https://i.sstatic.net/5FBwB.png" alt="Heart"></summary>
</details>
See the source for more examples: Create a CSS toggle button with the <details> element
Upvotes: 4
Reputation: 381
Depending on what you want to do, letting the focus maintain the change could be an option?
<button></button>
<style>
button {
width: 140px;
height: 70px;
background: url('http://www.ranklogos.com/wp-content/uploads/2015/06/Stack-Overflow-Logo.png');
background-size: cover;
}
button:focus {
width: 240px;
height: 120px;
}
</style>
https://jsfiddle.net/anm92d0r/
Note this doesnt work with the image tag. But judging by your element id, I'm assuming you're are looking for button functinality.
Upvotes: -1
Reputation: 1047
Use a pure CSS solution without being (that) hacky.
.page {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: #121519;
color: whitesmoke;
}
.controls {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
}
.arrow {
cursor: pointer;
transition: filter 0.3s ease 0.3s;
}
.arrow:active {
filter: drop-shadow(0 0 0 steelblue);
transition: filter 0s;
}
<body class="page">
<div class="controls">
<div class="arrow">
<img src="https://i.imgur.com/JGUoNfS.png" />
</div>
</div>
</body>
TylerH has a great response, but it’s a pretty complex solution. I have a solution for those of you that just want a simple "onclick" effect with pure CSS without a bunch of extra elements.
We will simply use CSS transitions. You could probably do similar with animations.
The trick is to change the delay for the transition so that it will last when the user clicks.
.arrowDownContainer:active,
.arrowDownContainer.clicked {
filter: drop-shadow(0px 0px 0px steelblue);
transition: filter 0s;
}
Here I add the "clicked" class as well, so that JavaScript can also provide the effect if it needs to. I use a zero pixel drop-shadow filter, because it will highlight the given transparent graphic blue this way for my case.
I have a filter at 0s here, so that it won’t take effect. When the effect is released, I can then add the transition with a delay, so that it will provide a nice "clicked" effect.
.arrowDownContainer {
cursor: pointer;
position: absolute;
bottom: 0px;
top: 490px;
left: 108px;
height: 222px;
width: 495px;
z-index: 3;
transition: filter 0.3s ease 0.3s;
}
This allows me to set it up so that when the user clicks the button, it highlights blue then fades out slowly (you could, of course, use other effects as well).
While you are limited here in the sense that the animation to highlight is instant, it does still provide the desired effect. You could likely use this trick with animation to produce a smoother overall transition.
Upvotes: 30
Reputation: 578
I had a problem with an element which had to be colored red on hover and be blue on click while being hovered. To achieve this with CSS you need for example:
h1:hover { color: red; }
h1:active { color: blue; }
<h1>This is a heading.</h1>
I struggled for some time until I discovered that the order of CSS selectors was the problem I was having. The problem was that I switched the places and the active selector was not working. Then I found out that :hover
to go first and then :active
.
Upvotes: 5
Reputation: 546
You can use :target
.
Or to filter by class name, use .classname:target
.
Or filter by id name using #idname:target
.
#id01:target {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.msg {
display: none;
}
.close {
color: white;
width: 2rem;
height: 2rem;
background-color: black;
text-align: center;
margin: 20px;
}
<a href="#id01">Open</a>
<div id="id01" class="msg">
<a href="" class="close">×</a>
<p>Some text. Some text. Some text.</p>
<p>Some text. Some text. Some text.</p>
</div>
Upvotes: -4
Reputation: 87191
TylerH made a really good answer, and I just had to give that last button a visual update.
.btn {
border-radius: 5px;
padding: 10px 30px;
box-shadow: 1px 1px 1px #000;
background-image: linear-gradient(to bottom, #eee, #ddd);
}
.btn:hover {
background-image: linear-gradient(to top, #adf, #8bf);
}
.btn:active {
margin: 1px 1px 0;
box-shadow: -1px -1px 1px #000;
}
#btnControl {
display: block;
visibility: hidden;
}
<input type="checkbox" id="btnControl"/>
<label class="btn" for="btnControl">Click me!</label>
Upvotes: 24
Reputation: 3205
Warning! Particularly simple answer below! :)
You actually can have a change that persists (such as a block/popup that appears and stays visible after a click) with only CSS (and without using the checkbox hack) despite what many of the (otherwise correct) answers here claim, as long as you only need persistence during the hover.
So take a look at Bojangles' and TylerH's answers if those work for you, but if you want a simple and CSS-only answer that will keep a block visible after being clicked on (and even can have the block disappear with a follow-up click), then see this solution.
I had a similar situation. I needed a popup div with onClick where I couldn't add any JavaScript or change the markup/HTML (a true CSS solution) and this is possible with some caveats. You can't use the :target trick that can create a nice popup unless you can change the HTML (to add an 'id'), so that was out.
In my case, the popup div was contained inside the other div, and I wanted the popup to appear on top of the other div, and this can be done using a combination of :active and :hover:
/* Outer div - needs to be relative so we can use absolute positioning */
.clickToShowInfo {
position: relative;
}
/* When clicking outer div, make inner div visible */
.clickToShowInfo:active .info { display: block; }
/* And hold by staying visible on hover */
.info:hover {
display: block;
}
/* General settings for popup */
.info {
position: absolute;
top: -5;
display: none;
z-index: 100;
background-color: white;
width: 200px;
height: 200px;
}
Example (as well as one that allows clicking on the popup to make it disappear) at:
CSS-Only onClick to Popup Div (no Javascript or HTML changes!)
I've also inserted a code snippet example below, but the positioning in the Stack Overflow sandbox is weird, so I had to put the 'click here' text after the innerDiv, which isn't normally needed.
/* Outer div - needs to be relative so we can use absolute positioning */
.clickToShowInfo {
position: relative;
}
/* When clicking outer div, make inner div visible */
.clickToShowInfo:active .info { visibility: visible; }
/* And hold by staying visible on hover */
.info:hover {
visibility: visible;
}
/* General settings for popup */
.info {
position: absolute;
top: -10;
visibility: hidden;
z-index: 100;
background-color: white;
box-shadow: 5px 5px 2px #aaa;
border: 1px solid grey;
padding: 8px;
width: 220px;
height: 200px;
}
/* If we want clicking on the popup to close, use this */
.info:active {
visibility: hidden; /* Doesn't work because DCEvent is :active as well */
height: 0px;
width: 0px;
left: -1000px;
top: -1000px;
}
<p />
<div class="clickToShowInfo">
<div class="info">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
</div>
Click here to show info
</div>
<p />
Upvotes: 13
Reputation: 10623
I have the below code for mouse hover and mouse click and it works:
//For Mouse Hover
.thumbnail:hover span{ /* CSS for enlarged image */
visibility: visible;
text-align: center;
vertical-align: middle;
height: 70%;
width: 80%;
top: auto;
left: 10%;
}
And this code hides the image when you click on it:
.thumbnail:active span {
visibility: hidden;
}
Upvotes: 3
Reputation: 2995
Firstly I will use focus
The reason for this is that it works nicely for the example I'm showing. If someone wants a mouse down type event then use active.
<button class="mdT mdI1" ></button>
<button class="mdT mdI2" ></button>
<button class="mdT mdI3" ></button>
<button class="mdT mdI4" ></button>
/* Change *button size, border, bg color, and align to middle* */
.mdT {
width: 96px;
height: 96px;
border: 0px;
outline: 0;
vertical-align: middle;
background-color: #AAAAAA;
}
.mdT:focus {
width: 256px;
height: 256px;
}
/* Change Images Depending On Focus */
.mdI1 { background-image: url('http://placehold.it/96x96/AAAAAA&text=img1'); }
.mdI1:focus { background-image: url('http://placehold.it/256x256/555555&text=Image+1'); }
.mdI2 { background-image: url('http://placehold.it/96x96/AAAAAA&text=img2'); }
.mdI2:focus { background-image: url('http://placehold.it/256x256/555555&text=Image+2'); }
.mdI3 { background-image: url('http://placehold.it/96x96/AAAAAA&text=img3'); }
.mdI3:focus { background-image: url('http://placehold.it/256x256/555555&text=Image+3'); }
.mdI4 { background-image: url('http://placehold.it/96x96/AAAAAA&text=img4'); }
.mdI4:focus { background-image: url('http://placehold.it/256x256/555555&text=Image+4'); }
JSFiddle link: http://jsfiddle.net/00wwkjux/
The OP only wants the effect to last during the click event. Now while this is not exact for that need, it’s close. active will animate while the mouse is down and any changes that you need to have to last longer need to be done with JavaScript.
Upvotes: 9
Reputation: 14575
The following is for an onclick similar to JavaScript's onclick, not the :active
pseudo class.
This can only be achieved with either JavaScript or the Checkbox Hack.
The checkbox hack essentially gets you to click on a label, that "checks" a checkbox, allowing you to style the label as you wish.
The demo.
Answered before OP clarified what he wanted.
Upvotes: 37
Reputation: 7287
You can use the pseudo class :target
to mimic the on click event. Let me give you an example.
#something {
display: none;
}
#something:target {
display: block;
}
<a href="#something">Show</a>
<div id="something">Bingo!</div>
Here's how it looks like: http://jsfiddle.net/TYhnb/
One thing to note is this is only limited to hyperlink, so if you need to use on another than a hyperlink, such as a button, you might want to hack it a little bit, such as styling a hyperlink to look like a button.
Upvotes: 100
Reputation: 101473
The closest you'll get is :active
:
#btnLeft:active {
width: 70px;
height: 74px;
}
However this will only apply the style when the mouse button is held down. The only way to apply a style and keep it applied onclick is to use a bit of JavaScript.
Upvotes: 499
Reputation: 7199
If you give the element a tabindex
then you can use the :focus
pseudo class to simulate a click.
#btnLeft:focus {
width: 70px;
height: 74px;
}
<img id="btnLeft" tabindex="0" src="https://picsum.photos/200"/>
Upvotes: 71