Change background color of div on click (CSS only)

Viewed 3064

I have three divs, of which the first needs to have a set background color on page load (this is to show that this is the default choice and preselected)

I want that when the user clicks the 2nd or 3rd div that

  1. the 1st div's background color is removed / white
  2. the clicked div has the background color (grey)

Should the user click on the 1st div again, it should behave like the 2nd or 3rd div and take the background color.

I have the following code per below, but I can't remove the background color of the 1st div when any other div is clicked.

Could anyone help me please?

JSFiddle: https://jsfiddle.net/AlphaX/1zp8yehu/1/

.one {background-color: grey;}

[tabindex]:focus { background-color: grey;}
<div class="parent" tabindex="0">


<div class="one" tabindex="1">
one
</div>

<div class="two" tabindex="2">
two
</div>

<div class="three" tabindex="3">
three
</div>

</div>

3 Answers

:focus-within can help you here:

.active {
  background-color: grey;
}

.parent:focus-within * { /* rest all background when one element is focused */
  background: none;
}

.parent [tabindex]:focus { /* set the background of only the focused one */
  background-color: grey;
}
<div class="parent" tabindex="0">


  <div class="one active" tabindex="1">
    one
  </div>

  <div class="two" tabindex="2">
    two
  </div>

  <div class="three" tabindex="3">
    three
  </div>

</div>

A more tricky code if you want to have all of them transparent when clicking outside:

.active {
  position:relative;
  z-index:0;
}
.active::before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background: grey;
  animation:h 0.1s forwards paused;
}

.parent:focus-within *::before {
  animation-play-state:running;
}

.parent [tabindex]:focus { 
  background-color: grey;
}

@keyframes h {
  1%,100% {
    background:transparent;
  }
}
<div class="parent" tabindex="0">


  <div class="one active" tabindex="1">
    one
  </div>

  <div class="two" tabindex="2">
    two
  </div>

  <div class="three" tabindex="3">
    three
  </div>

</div>

And to keep the last clicked element colored

.parent [tabindex] {
  transition:999s;
  background: rgba(255,255,255,0);
}
.parent:focus-within [tabindex] {
  transition:0s;
  background: rgba(255,255,254,0); /* a little different coloration to make sure we trigger the transition */
}
.parent [tabindex]:focus,
.parent [tabindex].active:focus{ 
  background-color: rgb(128,128,128);
  transition:0s;
}

.parent .active{ 
  background-color: rgb(128,128,127); /* a little different coloration to make sure we trigger the transition */
}
<div class="parent" tabindex="0">


  <div class="one active" tabindex="1">
    one
  </div>

  <div class="two" tabindex="2">
    two
  </div>

  <div class="three" tabindex="3">
    three
  </div>

</div>

You can use the trick with invisible inputs:

input[name='_'] {
    display: none;
}

label span {
    display: block;
}

:checked + span {
    background-color: grey;
}
<label>
    <input type="radio" name="_" checked>
    <span>one</span>
</label>
<label>
    <input type="radio" name="_">
    <span>two</span>
</label>
<label>
    <input type="radio" name="_">
    <span>three</span>
</label>

Even though the radio inputs are not visible, their labels can still control them. And the :checked + span selector applies style to an element only if there's a :checked element right before it.

VoilĂ !

.one, .two. .three {background-color: white;}

.one[tabindex]:focus, .two[tabindex]:focus, .three[tabindex]:focus { background-color: grey;}
<div class="parent" tabindex="0">


<div class="one" tabindex="1">
one
</div>

<div class="two" tabindex="2">
two
</div>

<div class="three" tabindex="3">
three
</div>

</div>

Related