0

I have a HTML page containing some radiobuttons and some related fieldsets, each one with its own id. I want to hide/view the div depending on a specific radiobutton.

The attached Fiddle do the job.

Here is the HTML

<div id="FS1">External fieldset with radiobuttons

  <div class="row">
    <input checked="checked" id="R1" name="Group1" type="radio" value="1"/>
    <label for="R1">Element 1</label>
    <input id="R2" name="Group1" type="radio" value="2"/>
    <label for="R2">Element 2</label>
    <input id="R3" name="Group1" type="radio" value="3"/>
    <label for="R3">Element 3</label>
    <fieldset class="fs" id="FS1-1">
      <legend>Header element 1</legend>
      <div class="form-group">
        <input class="form-control" id="exampleInputText1" type="text"/>
        <label for="exampleInputText1">Input field in the first element</label></div>
    </fieldset>
    <fieldset class="fs" id="FS1-2">
      <legend>Header element 2</legend>
      <div class="form-group">
        <input class="form-control" id="exampleInputText2" type="text"/>
        <label for="exampleInputText2">This is the input field for the second</label>
      </div>
    </fieldset>
    <fieldset class="fs" id="FS1-3">
      <legend>Header element 3</legend>
      <div class="form-group">
        <input class="form-control" id="exampleInputText3" type="text"/>
        <label for="exampleInputText3">And this is the last input field</label>
      </div>
    </fieldset>
  </div>
</div>

and this is the CSS

#FS1 div input:not(:checked) ~ #FS1-1, #FS1-2, #FS1-3 { display: none; } /* to hide all the detail elements */
#FS1 div input[value="1"]:checked ~ #FS1-1 { display: block; } /* to show only the 1th elem */
#FS1 div input[value="2"]:checked ~ #FS1-2 { display: block; } /* to show only the 2nd */
#FS1 div input[value="3"]:checked ~ #FS1-3 { display: block; } /* to show only the 3rd */

Now, what I want to achieve, is to relocate the fieldset outside the div, at the end of the fragment, but this brokes the css references and the fragment doesn't run anymore.

The following is the desired fragment, not running. I need suggestions on how to redefine the CSS

<div id="FS1">External fieldset with radiobuttons

  <div class="row">
    <input checked="checked" id="R1" name="Group1" type="radio" value="1"/>
    <label for="R1">Element 1</label>
    <input id="R2" name="Group1" type="radio" value="2"/>
    <label for="R2">Element 2</label>
    <input id="R3" name="Group1" type="radio" value="3"/>
    <label for="R3">Element 3</label>
  </div>
  <fieldset class="fs" id="FS1-1">
    <legend>Header element 1</legend>
    <div class="form-group">
      <input class="form-control" id="exampleInputText1" type="text"/>
      <label for="exampleInputText1">Input field in the first element</label></div>
  </fieldset>
  <fieldset class="fs" id="FS1-2">
    <legend>Header element 2</legend>
    <div class="form-group">
      <input class="form-control" id="exampleInputText2" type="text"/>
      <label for="exampleInputText2">This is the input field for the second</label>
    </div>
  </fieldset>
  <fieldset class="fs" id="FS1-3">
    <legend>Header element 3</legend>
    <div class="form-group">
      <input class="form-control" id="exampleInputText3" type="text"/>
      <label for="exampleInputText3">And this is the last input field</label>
    </div>
  </fieldset>
</div>
Paolo Di Pietro
  • 517
  • 3
  • 17

1 Answers1

0

So what you're asking cannot be achieved with plain CSS, but a solution could be achieved with Javascript.

Here is why it is not possible with your current HTML structure, as your current HTML structure looks like this:

enter image description here

With corresponding (simplified) code:

#FS1 div input:not(:checked) ~ #FS1-1, #FS1-2, #FS1-3 { display: none; } /* to hide all the detail elements */
#FS1 div input[value="1"]:checked ~ #FS1-1 { display: block; } /* to show only the 1th elem */
#FS1 div input[value="2"]:checked ~ #FS1-2 { display: block; } /* to show only the 2nd */
#FS1 div input[value="3"]:checked ~ #FS1-3 { display: block; } /* to show only the 3rd */
<div id="FS1">
  <div class="row">
    <input checked="checked" id="R1" name="Group1" type="radio" value="1"/>    
    <fieldset class="fs" id="FS1-1"></fieldset>
    <fieldset class="fs" id="FS1-2"></fieldset>
    <fieldset class="fs" id="FS1-3"></fieldset>
  </div>
</div>

As a simple example, I will explain why this line of code works:

#FS1 div input[value="1"]:checked ~ #FS1-1 { display: block; }
  1. Accesses id FS1
  2. Accesses HTML entity div which is a child of FS1
  3. Accesses the HTML entity input for state :checked and internal value="1"
  4. Accesses the sibling element (~) of id FS1-1
  5. Sets the property of display: block for FS1-1

The key thing to note is that the sibling element is selected.

With your proposed changesets to the HTML (see below), you would be required to access the parent element of the HTML entity input for state :checked and internal value="1" and then from there access the sibling, as FS1-1 no longer resides in the div class="row", rather outside it.

As per Wikipedia:

Some noted limitations of the current capabilities of CSS include: Selectors are unable to ascend. CSS currently offers no way to select a parent or ancestor of an element that satisfies certain criteria.

This has also been touched on here: Is there a CSS parent selector?

There is currently no way to select the parent of an element in CSS. In the meantime, you'll have to resort to JavaScript if you need to select a parent element.

Honestly, it's probably not worth the fight, leave the fieldset inside the div class="row" if possible.

Here are the relevant resources if you wish to go ahead and convert this to a Javascript solution:

EGC
  • 1,719
  • 1
  • 9
  • 20
  • Thank you EGC for your explanation. I was looking for a different solution, using absolute references: I'd like to describe a rule similar to this (sintax is invented): ```#FS1-1 [#FS1 div input[value="1"]:checked] {display: block;}``` – Paolo Di Pietro Dec 20 '19 at 08:52