简体   繁体   中英

Pure CSS way to unhide a drop-down menu (or any HTML element) when a certain option in a preceding drop-down menu is selected

Server-side dev here, dabbling in a bit of CSS.

I'm trying to use a selected option within a drop-down menu to display another drop-down. Whilst there are several publicly available JS solutions to such a problem, the challenge here is to do it purely in CSS, without any JS help.

Currently, I've tried to write CSS that adds display:block to a hidden element (a select element) when option with value="1" is selected within a preceding select element.

Needless to say it hasn't worked. It would be great to get expert opinion on how to accomplish this sort of a thing (with an illustrative example).

On the other hand, if it's not possible, it would be great to get an illustrative example of an alternative CSS-only solution to the problem (if it exists).


What I'm trying:

 body{ background: #f0f3f4 } .second{ display:none } select#first option[value="1"]:selected ~ .second{ display: block } 
 <select id="first" style="width:95%;padding:6px 0;border:1px solid #3cb7dd;border-radius:5px;text-align:center;color:#1f8cad" class="cm mt sp mbl" name="turl"> <option selected disabled hidden>Selector 1</option> <option value="1">Option 1</option> <option value="2">Option 2</option> <option value="3">Option 3</option> </select> <div class="second"> <select style="width:95%;padding:6px 0;border:1px solid #3cb7dd;border-radius:5px;text-align:center;color:#1f8cad" class="cm mt sp mbl" name="turl"> <option selected disabled hidden>Selector 2</option> <option value="1">Option 1</option> <option value="2">Option 2</option> <option value="3">Option 3</option> </select> </div> 

ps browser-compatibility is a consideration, so it would be great if a suggested solution adheres to well-supported CSS/HTML.

To summarize the issue with the obvious approach: <option> elements support :checked , but adjacency selectors ( a + b , a ~ b ) do not support matching subsequent elements unless they are in the same parent, therefore this cannot be used.

However , checkboxes and radiobuttons can be in a different container from their label, which can be utilized for plenty of "state" situations inside CSS - we just need to stitch together some sort of fake <select> with labels inside it, and put their <input> s outside, and then we can match via ~ as usual!

 body { font: 15px sans-serif; } /* a slightly janky custom dropdown */ .select { margin: 0.5em 0; line-height: 30px; height: 25px; width: 200px; border: 1px solid #ddd; /* it's a flexbox purely so that we can use `order` on the active element to move it to the top of the list */ display: flex; flex-direction: column; } /* restyle labels to look vaguely like options */ .select label { position: relative; display: block; line-height: 25px; height: 25px; padding: 0 0.5em; background: white; } /* hide labels in out-of-focus dropdowns [except the active one] */ .select:not(:focus) label { display: none; /* this is to prevent clicking the current item instead of activating the dropdown */ pointer-events: none; /* this is to override background from the multi-rule below */ background: white!important; } .select:focus label { z-index: 100; /* and then allow clicking them once it actually has focus */ pointer-events: all; } .select:focus label:hover { background: #08f!important; /* ditto */ color: white; } /* here's the catch: you can't just display:none the radiobuttons, as then your dropdown will not lose focus and thus will not close upon changing the active item. So we just move them somewhere far away */ input.option { position: absolute; left: -999999px; } /* this allows the correct label to be shown inside a dropdown when it is not open. please don't write these by hand */ #s1_1:checked ~ .select label[for="s1_1"], #s1_2:checked ~ .select label[for="s1_2"], #s1_3:checked ~ .select label[for="s1_3"], #s2_1:checked ~ .select label[for="s2_1"], #s2_2:checked ~ .select label[for="s2_2"]{ display: block; background: #f0f0f0; /* makes the selected element show up on the top of the options list, otherwise it's a bit disorienting */ order: -1; } /* and finally, the actual selector */ #s1_2:not(:checked) ~ #s2 { display: none }; 
 <input class="option" type="radio" name="s1" id="s1_1" checked/> <input class="option" type="radio" name="s1" id="s1_2"/> <input class="option" type="radio" name="s1" id="s1_3"/> <div class="select" tabindex="1"> <label for="s1_1">Option 1</label> <label for="s1_2">Option 2 [!]</label> <label for="s1_3">Option 3</label> </div> Some text after <input class="option" type="radio" name="s2" id="s2_1" checked/> <input class="option" type="radio" name="s2" id="s2_2"/> <div class="select" tabindex="2" id="s2"> <label for="s2_1">Option 1</label> <label for="s2_2">Option 2</label> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM