Styling HTML
  • elements: avoiding an invalid pa
  • 2019-08-13 18:54发布

    The situation:

    I have a site with a long list of questions across multiple pages.

    Each question is within a made up of a label and an input. Groups of question divs are within an additional div to provide grouping and bordering styles, etc.

    The problem:

    I want to number my questions, but want to avoid hard coding the numbering. However, it is invalid html to place the <li> inside the divs or labels.

    In addition some question divs are conditionally hidden and revealed depending on user input. The divs therefore provide key functionality, and the number must be hidden and revealed along with these divs, (so positioning each <li> outside a divs would be problematic.

    Code:

    Here is an example of a pared down structure of my form, showing two question "blocks":

    <form id="myform" method="post" action="/destinaion/page.php">
        <div class="formfield">
            <div class="page1">
                <div class="lowerborder">
                    <div class="question">                      
                        <label for="q2">Question 1</label> 
                        <input type="number" id="q1" name="q1"/>
                    </div>
    
                    <div class="question">                      
                        <label for="q1">Question 2</label> 
                        <input type="number" id="q2" name="q2"/>
                    </div>
                </div>
            </div>
        </div>
    </form>
    

    The div class form field contains the form page, and page1 various styling particulars for page 1.

    I'd like to make an ordered list from my questions, perhaps something like

    Attempt at achieving goal:

    <form id="myform" method="post" action="/destination/page.php">
        <div class="formfield">
        <ol>
            <div class="page1">
                <div class="lowerborder">
                    <div class="question">                      
                        <label for="q2"><li>Question 1</li></label> 
                        <input type="number" id="q1" name="q1"/>
                    </div>
    
                    <div class="question">                      
                        <label for="q1"><li>Question 2</li></label> 
                        <input type="number" id="q2" name="q2"/>
                    </div>
                </div>
            </div>
        </ol>
        </div>
    </form>
    

    But as you can see I am putting the <li> inside the <label> which a) is not valid html, and b) doesn't play well with all browsers.

    How can I avoid putting <li> elements inside invalid parents, when my list items are separated by many nested divs?

    jsFiddle:

    See a fiddle of my above attempt. Including some styling and functionality I am trying to achieve (styling via nested divs, hidden questions that reveal etc)

    1条回答
    Lonely孤独者°
    2楼-- · 2019-08-13 18:57

    Please see this fiddle demonstrating how to do everything you want without interposing any other elements. I found no need for even a single div anywhere.

    Note: I initially used float:left for the question to make the answers line up properly. However, this caused IE to render the numbers just left of the answers instead of left of the questions. I switched to using display:inline-block and now everything works in IE as well.

    Comments:

    • I cleaned up the style sheet, which had some sections repeated and conflicting style rules. I removed unnecessary rules.

    • I created the lines separating groups of questions using a class, and I also made it apply to the top border of a question rather than the bottom, so that you can use it even if there are hidden questions ending a group, since a hidden question would probably never begin a group. There was no need for additional elements to have borders.

    • In my opinion the label for the "Reveal" checkbox should be the text next to it, so that you can click that text to check and uncheck the box. Thus, I added a "question" class to the items that are the question, rather than using a label. You must apply the style "question" to the questions to make them style properly. You can apply that to a label element (which is for something else or not), or you can use a span or other element to contain the text when it is not a label.

    • IE 7 stupidly puts the numbers at the bottom of the line, even though the questions are styled with vertical-align:top. I don't know how to fix that at this time, but it could be another question to those more expert than I in CSS quirks.

    • IE was not handling the "hidden" method very well, taking up extra space and then when revealing not showing the child elements, so I used absolute positioning instead (which, by taking it out of the document flow, has the same effect). See the CSS for how it works.

    • I modified the way you were applying the reveal script. Instead of manually wiring up each individual item, instead I put a data value on the checkbox itself, then at the ready event I use that to wire up the page appropriately. Now you can have checkboxes that reveal more questions just by adding an id to the revealed question (or use class instead if you need to reveal more than one at a time) and a data expando attribute like data-togglehidden="l4" to specify the id to toggle right in the checkbox element. No script changes required.

    • It looks a little like you may have "div-itis" which is the tendency to multiply divs all over the place. No need to be embarrassed, I have had div-itis too, when I was new to html development. You'll grow out of it due to experiences like this. In general, you should use normal non-div page elements and style them directly, rather than wrap things in divs and styling those. Divs are useful when you need to style a group of related functionality or provide a box for different elements. One hint that you may be using divs improperly is when they only have a single item in them (especially another div). Sometimes that is necessary, but ask yourself: can I move the style to the parent or child element instead?

    • I need to know more about how the "pages" work that you mentioned and that were in your original html markup. There are no pages in html, only when html is printed. So I'm not quite sure what that means or how to style your pages for you.

    Here is the cleaned-up html, without the need of additional elements between ol and li:

    <form id="myform" method="post" action="/destination/page.php">
        <ol class="formfield">
            <li>
                <label class="question" for="q1">What is your first name?</label>
                <input type="text" id="q1" name="q1"/>
            </li>
            <li>
                <label class="question" for="q2">A very long question 2 that is sure to run to a second line just to prove that such a thing will work properly and not mess up the layout, described in your own words?</label>
                <input type="text" id="q2" name="q2"/>
            </li>
            <li class="begingroup">
                <span class="question">Are you the type of person who likes to needlessly answer extra questions?</span>
                <input type="checkbox" id="q3" name="q3" data-togglehidden="l4"/>
                <label for="q3">Yes, yes, that's me!!!</label>
            </li>
            <li id="l4" class="hidden">
                <label class="question" for="q4">Why do you like to do extra needless work?</label>
                <input type="text" id="q4" name="q4"/>
            </li>
            <li class="begingroup">
                <label class="question" for="q5">What was your first pet's name?</label>
                <input type="text" id="q5" name="q5"/>
            </li>
        </ol>
    </form>
    

    Here's what it looks like in Firefox 16.0.2: Form in Firefox 16.0.2

    And in IE 7.0.5730.13CO: Form in IE 7.0.5730.13CO

    The CSS:

    ol.formfield {
        width: 500px;
        margin: 10px auto;
        padding: 16px 16px 16px 0;
        border: 5px groove #005E9B;
        list-style: decimal outside;
        color: black;
        background-color: #6Fc2F7;    
        font-family: 'Oxygen', sans-serif;
        font-size:15px;
    }
    
    ol.formfield li {
        clear: both;
        padding: 2px;
        margin-left: 1.7em;
    }
    
    ol.formfield li.begingroup {
        margin-top: 8px;
        padding-top: 8px;
        border-top: 1px solid #005E9B;
    }
    
    .question {
        display:inline-block;
        width:300px;
        vertical-align:top;      
    }
    
    .hidden {
        position: absolute;
        height: 0;
        width: 0;
        overflow: hidden;
    }
    
    ol.formfield input {
        border-radius:5px; /* css 3 */
        -moz-border-radius:5px; /* mozilla */
        -webkit-border-radius:5px; /* webkit */
    }
    

    And the script to wire up your hide/reveal based on data values on elements:

    $('ol.formfield input:checkbox')
        .each(function() {
            var d = $(this).data('togglehidden');
            if(d) {
                $(this).on('change', function() {
                    if ($(this).attr('checked')) {     
                        $('#' + d)
                            .removeClass('hidden')
                            .find(':input')
                            .focus();
                    } else {
                        $('#' + d).addClass('hidden');
                    }
                });
            }
        });
    
    查看更多
    登录 后发表回答