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;
}
<a href="#fade-out">Fade out</a>
<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);
}
<a href="#rotate0" id="rotate0">0°</a>
<a href="#rotate90" id="rotate90">90°</a>
<a href="#rotate180" id="rotate180">180°</a>
<a href="#rotate270" id="rotate270">270°</a>
<a href="#rotate360" id="rotate360">360°</a>
<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>
<a href="#circle" class="doer">Circle</a>
<a href="#square" class="undoer">Circle</a>
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>
<a href="#red" id="red">Red</a>
<a href="#cancel" class="red">Red</a>
<a href="#orange" id="orange">Orange</a>
<a href="#cancel" class="orange">Orange</a>
<a href="#yellow" id="yellow">Yellow</a>
<a href="#cancel" class="yellow">Yellow</a>
<a href="#green" id="green">Green</a>
<a href="#cancel" class="green">Green</a>
<a href="#blue" id="blue">Blue</a>
<a href="#cancel" class="blue">Blue</a>
<a href="#indigo" id="indigo">Indigo</a>
<a href="#cancel" class="indigo">Indigo</a>
<a href="#violet" id="violet">Violet</a>
<a href="#cancel" class="violet">Violet</a>
<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;
}
<a href="#on" title="Turn on the light" id="on"><img src="https://i.stack.imgur.com/nuKgJ.png" alt="Light on"></a>
<a href="#off" title="Turn off the light" class="undoer"><img src="https://i.stack.imgur.com/3DLVM.png" alt="Light off"></a>
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;
}
<a href="#start" id="start">OFF</a>
<a href="#stop" class="undoer">ON</a>
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>
<a href="#open" id="open">☰</a>
<a href="#close" class="undoer">✕</a>
<h1> Music School</h1>
<nav>
<a href="#" id="current">Home</a>
<a href="#">Instruments</a>
<a href="#">Online Lessons</a>
<a href="#">Register</a>
<a href="#">Contact</a>
</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>
<a href="#open1" id="open1">How do we get more energy from the sun?</a>
<a href="#close">How do we get more energy from the sun?</a>
<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>
<a href="#open2" id="open2">What's so weird about prime numbers?</a>
<a href="#close">What's so weird about prime numbers?</a>
<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>
<a href="#open3" id="open3">Can computers keep getting faster?</a>
<a href="#close">Can computers keep getting faster?</a>
<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>
<a href="#open4" id="open4">When can I have a robot butler?</a>
<a href="#close">When can I have a robot butler?</a>
<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>
<a href="#open5" id="open5">What's at the bottom of the ocean?</a>
<a href="#close">What's at the bottom of the ocean?</a>
<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>
<a href="#open6" id="open6">What's at the bottom of a black hole?</a>
<a href="#close">What's at the bottom of a black hole?</a>
<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>
<a href="#open7" id="open7">How do we solve the population problem?</a>
<a href="#close">How do we solve the population problem?</a>
<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">
<a href="#dark" title="Dark mode" class="doer"></a>
<a href="#light" title="Light mode" class="undoer">☀️</a>
<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>
Any features missing from the list of possibilities and fun things you can do with the :target selector? Please share in the comments below.