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)?
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.
Basic demo of the checkbox hack (the basic code structure for what you're asking):
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.
Demo for re-sizing an image on click, which is what you're asking:
#btnControl {
display: none;
}
#btnControl:checked + label > img {
width: 70px;
height: 74px;
}
<input type="checkbox" id="btnControl"/>
<label class="btn" for="btnControl"><img src="https://placekitten.com/200/140" 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.
Demo for imitating a button click effect, above and beyond what you're asking:
#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.
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.
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;
}
Show
<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.
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"/>
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.
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>
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.
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 />
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.
The HTML code:
<button class="mdT mdI1" ></button>
<button class="mdT mdI2" ></button>
<button class="mdT mdI3" ></button>
<button class="mdT mdI4" ></button>
The CSS code
/* 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.
Before we go to the heart of the matter, let’s get it right for future reference — You should handle a click event with JavaScript.
document.querySelector('img').addEventListener('click', function() {
this.classList.toggle('large');
});
.large {
width: 75px;
height: 75px;
}
<img src="https://i.stack.imgur.com/5FBwB.png" alt="Heart">
However, if for some reason you can’t use JavaScript, there are two common approaches to mimic a click event and create a toggle button with CSS.
Checkbox hack 👎
The checkbox hack is not a good practice:
It’s not semantically correct, and that’s why it’s called a hack.
It causes accessibility issues for keyboard users and screen readers.
It restricts you in the structure of your HTML as the checkbox needs to be a previous sibling of the element you want to control.
You can’t control the <html> and <body> elements.
:target selector 👍
The :target CSS pseudo-class represents a unique element (the target element) with an id matching the URL's fragment. As you see in the following example, the doer’s href value, #fade-out, matches the target element’s id.
a {
display: inline-block;
padding: 8px 12px;
border-radius: 5px;
background: linear-gradient(#eee, #ddd);
color: #333;
font: bold 12px Verdana;
text-shadow: 0 1px white;
text-decoration: none;
}
p {
font: 13px/1.5 Arial;
padding: 1em;
background: aqua;
transition: 1s linear;
}
:target {
opacity: 0;
}
Fade out
<p id="fade-out">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
The :target selector can be used to style the current active target element. That means it works like a radio button: Only one in a given group can be selected at the same time.
body {
display: inline-grid;
font: 16px "Times New Roman";
}
a {
padding-left: 24px;
margin: 0 2em 1em 0;
justify-self: start;
background: radial-gradient(circle 7px at 8px, #dedede 7px, transparent 8px);
color: #333;
text-decoration: none;
}
a:hover {
background: radial-gradient(circle 7px at 8px, #ccc 7px, transparent 8px);
}
a:target {
background: radial-gradient(circle 7px at 8px, dodgerBlue 4px, white 5px 6px, dodgerBlue 7px, transparent 8px);
}
div {
grid-area: 1 / 2 / 7;
width: 154px;
height: 154px;
text-align: center;
background: aqua;
color: black;
border-radius: 50%;
transition: 0.3s linear;
}
#rotate90:target ~ div {
transform: rotate(90deg);
}
#rotate180:target ~ div {
transform: rotate(180deg);
}
#rotate270:target ~ div {
transform: rotate(270deg);
}
#rotate360:target ~ div {
transform: rotate(360deg);
}
0°
90°
180°
270°
360°
<div>•</div>
Q. How can you create a toggle button?
A. Basically, this is how it works: You use two hyperlinks, a “doer” and an “undoer”. The doer points to the target element, and the undoer, which points to nowhere, reverses the effect.
The following demos show the :target selector's potential and give you an idea of how to use it.
Style a previous sibling
div {
width: 200px;
height: 200px;
background: #dedede;
transition: 0.3s ease-in-out;
}
a {
display: inline-flex;
align-items: center;
column-gap: 1ch;
margin-top: 1em;
font: 16px Arial;
color: #333;
text-decoration: none;
}
a::before {
content: "✔";
font-size: 13px;
width: 1.2em;
line-height: 1.2em;
text-align: center;
background: #dedede;
color: transparent;
}
.undoer::before {
background: dodgerBlue;
color: white;
text-shadow: 0 2px black;
}
.doer:hover::before {
background: #ccc;
}
:target {
border-radius: 50%;
}
.undoer,
:target ~ .doer {
display: none;
}
:target ~ .undoer {
display: inline-flex;
}
<div id="circle"></div>
Circle
Circle
Style a next sibling
A link can target even the very same anchor element.
body {
text-align: center;
}
h1 {
font-size: 24px;
}
a {
display: inline-block;
padding: 8px 12px;
border-radius: 5px;
margin-bottom: 1em;
background: linear-gradient(#eee, #ddd);
color: #333;
font: bold 12px Verdana;
text-shadow: 0 1px white;
text-decoration: none;
}
[class]:not(.yellow) {
color: white;
text-shadow: 0 1px black;
}
.red {
background: red;
}
.orange {
background: orange;
}
.yellow {
background: yellow;
}
.green {
background: green;
}
.blue {
background: blue;
}
.indigo {
background: indigo;
}
.violet {
background: violet;
}
div {
width: 600px;
height: 400px;
margin: 0 auto;
background: #eee;
transition: 0.3s ease-in-out;
}
[class],
:target {
display: none;
}
:target + a {
display: inline-block;
}
#red:target ~ div {
background: red;
}
#orange:target ~ div {
background: orange;
}
#yellow:target ~ div {
background: yellow;
}
#green:target ~ div {
background: green;
}
#blue:target ~ div {
background: blue;
}
#indigo:target ~ div {
background: indigo;
}
#violet:target ~ div {
background: violet;
}
<h1>🌈</h1>
Red
Red
Orange
Orange
Yellow
Yellow
Green
Green
Blue
Blue
Indigo
Indigo
Violet
Violet
<div></div>
Replace an element
As you may have noticed, you can entirely replace an element with another one.
.undoer,
:target {
display: none;
}
:target + .undoer {
display: inline;
}
<img src="https://i.stack.imgur.com/nuKgJ.png" alt="Light on">
<img src="https://i.stack.imgur.com/3DLVM.png" alt="Light off">
You may even nest block-level elements inside your anchors.
If you wish to have a transition effect when you switch from the doer to the undoer, use position: absolute on the first and visibility: hidden on the second.
a {
display: block;
box-sizing: border-box;
width: 64px;
padding-left: 33px;
border-radius: 16px;
background: radial-gradient(circle 12px, white 100%, transparent calc(100% + 1px)) #ccc -16px;
font: bold 12px/32px Verdana;
color: white;
text-shadow: 0 1px black;
text-decoration: none;
transition: 0.3s ease-in-out;
transition-property: padding-left, background-color, background-position;
}
#start {
position: absolute;
}
:target,
:target + .undoer {
padding-left: 8px;
background-color: dodgerBlue;
background-position: 16px;
}
.undoer,
:target {
visibility: hidden;
}
:target + .undoer {
visibility: visible;
}
OFF
ON
Hide and show content
Here's a navigation menu.
html,
body {
margin: 0;
padding: 0;
}
header {
display: flex;
line-height: 50px;
background: linear-gradient(#999, #333);
color: white;
}
a {
color: inherit;
text-decoration: none;
}
header > a,
header h1 {
font-size: 26px;
font-family: 'Times New Roman';
text-shadow: 0 3px black;
}
header > a {
width: 50px;
text-align: center;
}
header h1 {
margin: 0;
letter-spacing: 1px;
}
nav {
position: absolute;
top: 50px;
background: #333;
visibility: hidden;
transform: translateX(-100%);
transition: 280ms ease-out 120ms;
}
nav a {
display: block;
padding: 1em;
font: bold 12px Verdana;
transition: inherit;
}
nav a:not(:last-child) {
border-bottom: 1px solid black;
}
nav a:hover,
#current {
background: #A00;
}
.undoer,
:target {
display: none;
}
:target + .undoer {
display: block;
}
:target ~ nav {
visibility: visible;
transform: none;
}
main {
padding: 16px;
font: 13px Arial;
color: #333;
}
main h1 {
font-size: 1.5em;
}
p {
line-height: 1.5;
}
<header>
☰
✕
<h1>🎹 Music School</h1>
<nav>
Home
Instruments
Online Lessons
Register
Contact
</nav>
</header>
<main>
<h1>Home</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
And here's an FAQ page.
body {
font: 16px Arial;
color: #333;
max-width: 600px;
margin: 1em auto;
}
h1 {
text-align: center;
font-family: "Times New Roman";
}
p {
display: none;
padding: 12px;
border: 2px solid #dedede;
border-top: 0;
margin: 0;
font-size: 13px;
line-height: 1.5;
}
a {
display: flex;
align-items: center;
column-gap: 12px;
padding: 12px;
margin-top: 1em;
background: #dedede;
color: inherit;
font-weight: bold;
line-height: 1.5;
text-shadow: 0 1px white;
text-decoration: none;
}
a::before {
content: "➕";
padding: 3px;
background: #eee;
font-weight: initial;
}
a[href="#close"]::before {
content: "➖";
}
a:hover::before {
background: #fff;
}
a[href="#close"],
a:target {
display: none;
}
a:target + a {
display: flex;
}
a:target + a + p {
display: block;
}
<h1>Frequently Asked Questions</h1>
How do we get more energy from the sun?
How do we get more energy from the sun?
<p>Dwindling supplies of fossil fuels mean we’re in need of a new way to power our planet. Our nearest star offers more than one possible solution. We’re already harnessing the sun’s energy to produce solar power. Another idea is to use the energy in sunlight to split water into its component parts: oxygen, and hydrogen, which could provide a clean fuel for cars of the future. Scientists are also working on an energy solution that depends on recreating the processes going on inside stars themselves – they’re building a nuclear fusion machine. The hope is that these solutions can meet our energy needs.</p>
What's so weird about prime numbers?
What's so weird about prime numbers?
<p>The fact you can shop safely on the internet is thanks to prime numbers – those digits that can only be divided by themselves and one. Public key encryption – the heartbeat of internet commerce – uses prime numbers to fashion keys capable of locking away your sensitive information from prying eyes. And yet, despite their fundamental importance to our everyday lives, the primes remain an enigma. An apparent pattern within them – the Riemann hypothesis – has tantalised some of the brightest minds in mathematics for centuries. However, as yet, no one has been able to tame their weirdness. Doing so might just break the internet.</p>
Can computers keep getting faster?
Can computers keep getting faster?
<p>Our tablets and smartphones are mini-computers that contain more computing power than astronauts took to the moon in 1969. But if we want to keep on increasing the amount of computing power we carry around in our pockets, how are we going to do it? There are only so many components you can cram on to a computer chip. Has the limit been reached, or is there another way to make a computer? Scientists are considering new materials, such as atomically thin carbon – graphene – as well as new systems, such as quantum computing.</p>
When can I have a robot butler?
When can I have a robot butler?
<p>Robots can already serve drinks and carry suitcases. Modern robotics can offer us a “staff” of individually specialised robots: they ready your Amazon orders for delivery, milk your cows, sort your email and ferry you between airport terminals. But a truly “intelligent” robot requires us to crack artificial intelligence. The real question is whether you’d leave a robotic butler alone in the house with your granny. And with Japan aiming to have robotic aides caring for its elderly by 2025, we’re thinking hard about it now.</p>
What's at the bottom of the ocean?
What's at the bottom of the ocean?
<p>Ninety-five per cent of the ocean is unexplored. What’s down there? In 1960, Don Walsh and Jacques Piccard travelled seven miles down, to the deepest part of the ocean, in search of answers. Their voyage pushed the boundaries of human endeavour but gave them only a glimpse of life on the seafloor. It’s so difficult getting to the bottom of the ocean that for the most part we have to resort to sending unmanned vehicles as scouts. The discoveries we’ve made so far – from bizarre fish such as the barreleye, with its transparent head, to a potential treatment for Alzheimer’s made by crustaceans – are a tiny fraction of the strange world hidden below the waves.</p>
What's at the bottom of a black hole?
What's at the bottom of a black hole?
<p>It’s a question we don’t yet have the tools to answer. Einstein’s general relativity says that when a black hole is created by a dying, collapsing massive star, it continues caving in until it forms an infinitely small, infinitely dense point called a singularity. But on such scales quantum physics probably has something to say too. Except that general relativity and quantum physics have never been the happiest of bedfellows – for decades they have withstood all attempts to unify them. However, a recent idea – called M-Theory – may one day explain the unseen centre of one of the universe’s most extreme creations.</p>
How do we solve the population problem?
How do we solve the population problem?
<p>The number of people on our planet has doubled to more than 7 billion since the 1960s and it is expected that by 2050 there will be at least 9 billion of us. Where are we all going to live and how are we going to make enough food and fuel for our ever-growing population? Maybe we can ship everyone off to Mars or start building apartment blocks underground. We could even start feeding ourselves with lab-grown meat. These may sound like sci-fi solutions, but we might have to start taking them more seriously.</p>
Switch to a whole new stylesheet
You can target and style an element as well as all its descendants. For example, let’s target the <body> element and toggle dark/light mode.
body,
a,
h2 {
transition: 0.3s linear;
}
body {
font: 13px Arial;
background: white;
color: #333;
}
a {
font-size: 16px;
text-decoration: none;
}
main {
column-count: 3;
column-gap: 2em;
padding: 0 1em;
}
h1 {
column-span: all;
text-align: center;
}
h2:nth-of-type(1) {
margin-top: 0;
}
p {
line-height: 1.5;
}
:target {
background: #333;
color: white;
}
.doer {
position: absolute;
}
.undoer,
:target .doer {
visibility: hidden;
opacity: 0;
}
:target .undoer {
visibility: visible;
opacity: 1;
}
:target h2:nth-of-type(1) {
color: red;
}
:target h2:nth-of-type(2) {
color: green;
}
:target h2:nth-of-type(3) {
color: blue;
}
<body id="dark">
🌙
☀️
<main>
<h1>Primary Colors</h1>
<h2>Red</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<h2>Green</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<h2>Blue</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</main>
</body>
🎯🎯🎯
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.
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;
}
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.
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;
}
Open
<div id="id01" class="msg">
×
<p>Some text. Some text. Some text.</p>
<p>Some text. Some text. Some text.</p>
</div>
I am using jQuery 3.x. I am trying to append a dynamically created element before and after an element using insertBefore() and insertAfter(). However, only insertBefore() is working, and another one is ignored. When I am commenting one then other is working. why?
p = $("<p></p>").text("This is a dynamicly created element");
p.insertAfter($('nav'));
p.insertBefore($('nav'));
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 20px;
}
header,
nav,
main,
aside,
footer {
padding: 10px 15px;
border: 1px solid mediumseagreen;
text-align: center;
}
header {
background: dodgerBlue;
}
nav {
background: mediumSeaGreen;
}
main {
background: #d3d3d3;
}
main,
aside {
height: 1200px;
}
main {
width: 80%;
float: left;
}
aside {
width: 20%;
float: right;
}
div::after {
content: " ";
float: none;
clear: both;
display: table;
}
main {
text-align: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
This is header
</header>
<nav>
This is navbar
</nav>
<main>
<article>
<h2>This is heading</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum atque fuga, eos neque ipsum enim id inventore necessitatibus laboriosam quo nobis, repellendus maxime veritatis error ut expedita, velit aspernatur asperiores!
</p>
</article>
</main>
<aside>
This is side bar
</aside>
<div></div>
<footer>
This is footer
</footer>
The issue is because the p references only a single element. You insert it in to the DOM in the insertAfter() call, then move the same element to a new location using insertBefore().
To do what you require you can clone() the element before the second insertion. Also note that you don't need to create an entire jQuery object to select nav, you can just pass the selector as a string. Try this:
let p = $("<p />", {
text: "This is a dynamicly created element"
});
p.insertAfter('nav');
p.clone().insertBefore('nav');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 20px;
}
header,
nav,
main,
aside,
footer {
padding: 10px 15px;
border: 1px solid mediumseagreen;
text-align: center;
}
header {
background: dodgerBlue;
}
nav {
background: mediumSeaGreen;
}
main {
background: #d3d3d3;
}
main,
aside {
height: 1200px;
}
main {
width: 80%;
float: left;
}
aside {
width: 20%;
float: right;
}
div::after {
content: " ";
float: none;
clear: both;
display: table;
}
main {
text-align: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>This is header</header>
<nav>This is navbar</nav>
<main>
<article>
<h2>This is heading</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum atque fuga, eos neque ipsum enim id inventore necessitatibus laboriosam quo nobis, repellendus maxime veritatis error ut expedita, velit aspernatur asperiores!
</p>
</article>
</main>
<aside>This is side bar</aside>
<div></div>
<footer>This is footer</footer>
One other thing to mention, I would suggest researching flexbox layouts. They're a much more modern and extensible technique than forcing display: table on a div to create a multi-column layout.
I have written my own modal classes using css and have used it in my application successfully. However the issue i'm facing is when the overlay is open i can still scroll the background contents. How can i stop scrolling background contents when my modal/overlay is open?
This is my modal which opens on top of the overlay
<div>
<div className="overlay"></div>
{this.props.openModal ?
<div>
<div className="polaroid sixten allcmnt_bg_clr horiz_center2">
{}
<div className="mobile_header">
<PostHeader/>
</div>
<div className="mobile_renderPost">
{ this.renderPostType() }
</div>
<div className="mobile_post_bottom"></div>
</div>
</div> : null}
</div>
my overlay css
.overlay {
background-color: rgba(0, 0, 0, .70);
position: fixed;
width: 100%;
height: 100%;
opacity: 1;
left: 0;
right: 0;
-webkit-transition: opacity .25s ease;
z-index: 1001;
margin: 0 auto;
}
One approach is hidden the overflow of the body element.
like this:
body.modal-open{
overflow:hidden;
}
so in this case when you popup the modal you add a class to body and then when you close it you remove that class.
another approach is using a javascript to disable the scroll like this:
document.documentElement.style.overflow = 'hidden';
document.body.scroll = "no";
and then return it with
document.documentElement.style.overflow = 'scroll';
document.body.scroll = "yes";
When you open the modal, you can add overflow: hidden; to the body's style.
Or,
body.modal-opened {
overflow: hidden;
}
And add modal-opened class to the body when opening and remove when you close the dialog.
Using JavaScript to add a class to the body with
overflow:hidden;
will work in most cases, but I beleive Safari on iPhone will still scroll slightly with jitter due to Touch Move and something like this will be needed.
function handleTouchMove(e)
{
e.preventDefault();
}
function lockscreen()
{
var body = document.getElementById("body");
body.className += " lock-screen";
body.addEventListener('touchmove', handleTouchMove, false);
}
function unlock()
{
var body = document.getElementById("body");
body.classList.remove("lock-screen");
body.removeEventListener('touchmove', handleTouchMove);
}
to stop the user from still scrolling
I had this problem too and tried every answer from setting the height on the body element to 100% or 100vh and overflow: hidden. This caused a few issues for me, starting with that using the hidden overflow with the 100vh made the page jump to the top whenever clicking the hamburger menu button.
The solution: adding the overflow:hidden property to the html tag. This worked perfectly where the menu would open, prevent the page from scrolling, and remain where the user is on the page without it jumping.
Since it looks like you're using React, here is an example of how I used it:
.lock-scroll {
overflow: hidden;
}
const [open, setOpen] = useState(false)
useEffect(() => {
const html = document.getElementsByTagName('html')[0]
if (open) {
html.classList.add('lock-scroll')
} else {
html.classList.remove('lock-scroll')
}
return (): void => {
html.classList.remove('lock-scroll')
}
}, [open])
When the modal opens, hide the x/y scroll bars on the body.
.no-scroll {
overflow: hidden;
}
Using JavaScript add the class to the body:
<body class="no-scroll">
</body>
Once you close the modal remove the class.
Combining the overflow: hidden solution with modern technique works perfectly
html:has(dialog[open]) {
/* remove the main scrollbar when dialog is open */
overflow: hidden;
}
All the answers so far (Oct. 2022) suggest to add overflow: hidden dynamically to either 'body' or 'html' when you open the modal/pop-up. This works if 'html' or 'body' are actually your scrolling elements and fixes the somewhat counterintuitive over-scroll behavior of position: fixed elements.
I've tried to use overscroll-behavior instead to fix the issue and this can work, but requires scrollable elements (with actual overflow) inside your modal and is not very reliable if the user simply decides to touch your overlay outside of the "locked" elements.
Depending on your page design there is another option that requires you to split content and overlay and set the 'html' and 'body' height explicitly to 100%. Here is a complete example:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
body {
position: relative;
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 16px;
}
.content {
padding: 32px;
border: 1px solid #000;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, .5);
backdrop-filter: blur(5px);
display: flex;
justify-content: center;
align-items: center;
z-index: 1001;
}
.info-box {
background: #000;
color: #eee;
border-radius: 5px;
width: 240px;
height: 240px;
padding: 16px;
}
/* scroll fix */
html, body {
height: 100%;
}
.content {
max-height: 100%;
overflow-y: auto;
}
</style>
</head>
<body>
<div class="content">
<h2>Overlay Background Scroll Test</h2>
<p>Use a window size of around 320x480 for optimal testing (e.g. via device-toolbar).</p>
<h3>Scrollable Page</h3>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<button onclick="document.querySelector('.overlay').style.display='flex';">open</button>
</div>
<div class="overlay">
<div class="scroll-fix">
<div class="info-box">
<h3>Pop-Up Message</h3>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<button onclick="document.querySelector('.overlay').style.display='none';">close</button>
</div>
</div>
</div>
</body>
The important section is the last CSS entry. This will make your .content element the main scroll element:
html, body {
height: 100%;
}
.content {
max-height: 100%;
overflow-y: auto;
}
There is a disadvantage to this approach though. Most mobile browsers will not be able to automatically hide their URL-bar through scrolling anymore, because this seems to depend on html or body element scrolling :-(.
I started learning javascript this week and I'm getting my head round the basics. I've started building what will be a "FAQ" section for a page that uses a toggle switch to open and close target divs.
However, by default the div's display is set to visible. I've put a function in that will set this to hidden, so that the dropdown's are collapsed on page load. I've tried stacking them (the toggle function, and display functions), separating them with a semi-colon within "onLoad" in the body tag.
Now, before I applied these functions to run "onLoad" both worked fine. However now only the 2nd function works that toggles the divs, but the function stating to have the divs collapsed onLoad is not.
Where am I going wrong here?
Also, seeing as I'm new to this, if there's a better way, or more shorthand version of this feel free to let me know :)
function toggleOnLoad() {
document.getElementById('dropdown01').style.display = 'none';
}
function toggleFunction() {
var dropDown = document.getElementById('dropdown01');
var dropDownCollapse = document.getElementById('toggle-image').src = "Images/banner_toggle_collapse.png";
var dropDownExpand = document.getElementById('toggle-image').src = "Images/banner_toggle_expand.png";
if (dropDown.style.display != 'none') {
dropDown.style.display = 'none';
document.getElementById('toggle-image').src = dropDownExpand;
} else {
dropDown.style.display = '';
document.getElementById('toggle-image').src = dropDownCollapse;
}
}
css: body {
background-color: #cccccc;
padding: 0;
margin: 0;
}
.container {
margin-left: 20%;
margin-right: 20%;
background-color: white;
padding: 1em 3em 1em 3em;
}
.toggle-header {
padding: 0.5em;
background-color: #0067b1;
overflow: auto;
}
#toggle {
border: none;
width: 300;
height: 3em;
background-color: #0067b1;
outline: 0;
}
.button-container {
float: right;
margin-right: 0.5em;
display: inline-block;
}
.dropdowns {
padding: 2em;
background-color: #eeeeee;
}
HTML & Javascript:
<body onLoad="toggleOnLoad(); toggleFunction()">
<div class="container">
<div class="toggle-header">
<div class="button-container" title="">
<button id="toggle" onClick="toggleFunction()">
<img id="toggle-image" src="" alt="toggle" style="max-height: 100%; max-width: 100%">
</button>
</div>
</div>
<div id="dropdown01" class="dropdowns">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</span>
</div>
</div>
</body>
Do create an init function manually.
window.addEventListener("load", myInit, true); function myInit(){ // call your functions here.... };
By doing this you can call that set of functions anytime.
The better way to do it i believe is to call your functions inside window.load instead of the body as follows:
window.onload=function(){
toggleOnLoad();
toggleFunction();
}
Your idea is correct. Probably we can simplify the implementation.
First, let's define a new class hidden to remove elements.
.hidden {
display: none;
}
Now we just can toggle this class to show and hide the content.
function toggleFunction() {
...
content.classList.toggle('hidden')
...
}
Also remove toggleOnLoad function from the body and add hidden to the content div
<body onLoad="toggleFunction()">
...
<div id="dropdown01" class="dropdowns hidden">
...
</body>
Finally, the toggleFunction must add the right class based on the hidden class of the content.
function toggleFunction() {
dropDown.classList.remove(expand, collapse)
...
const state = content.classList.contains('hidden') ? collapse : expand
dropDown.classList.add(state)
}
This is functional snipped:
const content = document.getElementById('dropdown01')
const dropDown = document.querySelector('#toggle-image')
const collapse = 'fa-plus-square'
const expand = 'fa-minus-square'
function toggleFunction() {
dropDown.classList.remove(expand, collapse)
content.classList.toggle('hidden')
const state = content.classList.contains('hidden') ? collapse : expand
dropDown.classList.add(state)
}
body {
background-color: #cccccc;
padding: 0;
margin: 0;
}
.container {
margin-left: 20%;
margin-right: 20%;
background-color: white;
padding: 1em 2em 1em 2em;
}
.toggle-header {
padding: 0.5em;
background-color: #0067b1;
overflow: auto;
}
#toggle {
border: none;
width: 300px;
height: 2em;
background-color: #0067b1;
outline: 0;
}
.button-container {
float: right;
margin-right: 0.5em;
display: inline-block;
}
.dropdowns {
padding: 1em;
background-color: #eeeeee;
}
.hidden {
display: none;
}
<script src="https://kit.fontawesome.com/0c7c27ff53.js" crossorigin="anonymous"></script>
<body onLoad="toggleFunction()">
<div class="container">
<div class="toggle-header">
<div class="button-container" title="">
<i id="toggle-image" class="fas fa-plus-square" onClick="toggleFunction()"></i>
</div>
</div>
<div id="dropdown01" class="dropdowns hidden">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</span>
</div>
</div>
</body>