skip to Main Content

So I know all this can be done in Javascript without much difficulty, but wondered if, in the end it could all be done with CSS. I tried looking at a number of entries on here, many say ‘no’– but they are also quite old (circa 2014) so I don’t know if the CSS standard has been updated significantly since then.

I’ve two classes .arrow and .slide. I’ve done the checkbox hack to be able to activate .slide on a click by #test:checked + .slide.

In part I am wondering if it is possible to chain more than one CSS Selector together, or does that not work ? I.e. something like #test:checked + .slide + .arrow2 + etc..

The specific ‘second’ action I wish to occur has presently been stuffed away in .arrow:active, because I wasn’t sure how else to demonstrate it.
Go over to the right to the arrows, do a long hold click and you will see the state change I want to happen. I mean if you click the arrows twice, .slide goes in and out just fine.

I’m just not sure how to achieve the same state change with .arrow, or if it is possible to pull both into one event without resorting to JS.

Outta ideas…

.arrow {
  width: 19px;
  height: 32px;
  float: right; 
  padding-left: 20px;
  background-image: url("http://www.allpointsbulletin.info/assets/img/ArrowDown.png"); 
  transition: background-image 0.5s ease-in-out;
}

.arrow:active {
  background-image: url("https://www.allpointsbulletin.info/assets/img/ArrowUp.png");
}

.slide {
  clear:both;
  width:10%;
  height:0px;
  overflow: hidden;
  text-align: center;
  transition: height 1.5s ease;
  list-style-type: none;
}

.slide li {
  padding : 30px;
}

#test {
  position: absolute; 
  opacity: 0; 
  height: 0px;}    

#test:checked + .slide {height: 500px;} 
<label for="test"><h4>See more info<div class="arrow"></div></h4></label>
<input type="checkbox" id="test">
<ul class="slide">
  <li><a href="#">Lorem Ipsum</a></li> 
  <li><a href="#">Lorem Ipsum</a></li>
  <li><a href="#">Lorem Ipsum</a></li>
  <li><a href="#">Lorem Ipsum</a></li>
</ul>

2

Answers


  1. It is possible using CSS. You need to use :has() pseudo selector for that and also use a parent container. The changes:

    .parent:has(#test:checked) .arrow{
      background-image: url("https://www.allpointsbulletin.info/assets/img/ArrowUp.png");
    }
    

    And you don’t need .arrow:active pseudo selector anymore.
    Note: This :has() pseudo selector has limited browser support.

    .arrow {
      width: 19px;
      height: 32px;
      float: right; 
      padding-left: 20px;
      background-image: url("http://www.allpointsbulletin.info/assets/img/ArrowDown.png"); 
      transition: background-image 0.5s ease-in-out;
    }
    
    /* .arrow:active {
      background-image: url("https://www.allpointsbulletin.info/assets/img/ArrowUp.png");
    } */
    
    .slide {
      clear:both;
      width:10%;
      height:0px;
      overflow: hidden;
      text-align: center;
      transition: height 1.5s ease;
      list-style-type: none;
    }
    
    .slide li {
      padding : 30px;
    }
    
    #test {
      position: absolute; 
      opacity: 0; 
      height: 0px;}    
    
    #test:checked + .slide {height: 500px;} 
    
    .parent:has(#test:checked) .arrow{
      background-image: url("https://www.allpointsbulletin.info/assets/img/ArrowUp.png");
    }
    <div class="parent">
      <label for="test"><h4>See more info<div class="arrow"></div></h4></label>
      <input type="checkbox" id="test">
      <ul class="slide">
        <li><a href="#">Lorem Ipsum</a></li> 
        <li><a href="#">Lorem Ipsum</a></li>
        <li><a href="#">Lorem Ipsum</a></li>
        <li><a href="#">Lorem Ipsum</a></li>
      </ul>
    </div>
    Login or Signup to reply.
  2. Place the checkbox before everything because the flow of an adjacent sibling combinator is left to right on the CSS selector syntax and HTML element directly ahead of the previous HTML element.

    Details are commented in example

    :root {
      font: 3ch/1.15 "Segoe UI";
    }
    
    body {
      overflow-y: scroll;
    }
    
    #switch {
      opacity: 0;
      height: 0;
    }
    
    .button {
      display: flex;
      justify-content: space-between;
      align-items: center;
      min-width: 90vw;
      height: max-content;
      padding: 0.25rem 0.75rem;
      border-bottom: 2px ridge grey;
      font-weight: 700;
      font-size: 1.25rem;
      letter-spacing: 1px;
      font-variant: small-caps;
      cursor: pointer;
    }
    
    .arrow {
      display: block;
      width: 1.25rem;
      aspect-ratio: 1/1;
      background: url(https://www.allpointsbulletin.info/assets/img/ArrowUp.png) no-repeat center;
      background-size: cover;
      /* Default is 0deg */
      transform: rotate(0deg);
      /* Assign a transition for all animatable properties */
      transition: all 0.5s ease;
    }
    
    /* When the checkbox is (:checked), go to the (+) .button
    directly ahead of it then go to the .arrow inside of 
    .button. Rotate .arrow 180deg. */
    #switch:checked +.button .arrow {
      transform: rotate(180deg);
    }
    
    .slide {
      list-style: none;
      width: 10rem;
      /* Default height is 0 */
      height: 0;
      /* Hides content when height: 0 */
      overflow: hidden;  
      /* Assign a transition for all animatable properties */
      transition: all 0.5s ease-in-out;
    }
    
    .slide a {
      display: block;
      padding: 0.25rem 0.5rem;
    }
    
    /* When checkbox is (:checked), go to (+) .button directly ahead of
    it, then go to (+) .slide directly ahead of .button. Change .slide
    height to 500px. */
    #switch:checked +.button +.slide {
      height: 500px;
    }
    <input id="switch" type="checkbox">
    <label for="switch" class="button">Sections<b class="arrow"></b></label>
    <ul class="slide">
      <li><a href="#">Section I</a></li>
      <li><a href="#">Section II</a></li>
      <li><a href="#">Section III</a></li>
      <li><a href="#">Section IV</a></li>
    </ul>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search