1

Using the following markup

<ul>
    <li>
        <label class="field">
            Some Stuff 1
        </label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 2</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 3</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 4</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 5</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 6</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 7</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 8</label>
        <input class="value" type="text" />
    </li>
</ul>

With the following CSS

html, body {
    width: 100%;
}

* {
    margin: 0;
    padding: 0;
    border: 0;

    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

input {
    border: 1px solid;
}

ul {
    list-style: none;
    width: 100%;
}

ul > li {
    display: inline-block;
    width: 25%;

    padding: 3px 8px;
}

.field,
.value {
    display: block;
    width: 100%;
}

Please don't mind how terrible this is its only to demonstrate the problem.

You would expect that there would be 4 li in a row as there is no margin padding or border to take up any of the space available to them and each is sized to 25% of the parent ul.

But because we all like to make our markup readable and not just have it all in one line we add extra breaks and tabs/spaces for indenting ect... but this ends up in the DOM as empty text nodes these are of course completely natural and should be there, but since they take up space 4px to be exact they ruin a good fluid layout making use of inline-block.

I don't like to float elements when doing a fluid layout I like to use the display: inline-block instead there's just this nagging problem with the empty text nodes.

Now I have a fiddle with the solution I use witch is to remove them with javascript you can check it out here or at http://jsfiddle.net/Tt9zn/5/

$(function() {
    function tirmSpecial(str) {
        // Trim \r Carriage Return, \n Linefeed, \t Tab, \v Vertical Tab, \f Form-Feed, \u0020 Space
        // Do Not Trim (u00A0 = &nbsp)
        return str.replace(/^[\r\n\t\v\f\u0020]+|[\r\n\t\v\f\u0020]+$/g, ''); 
    }

    function getTextNodesIn(node, includeWhitespaceNodes) {
        var textNodes = [], whitespace = /^\s*$/;

        function getTextNodes(node) {
            if (node.nodeType == 3) {
                if (includeWhitespaceNodes || !whitespace.test(node.nodeValue)) {
                    textNodes.push(node);
                }
            } else {
                for (var i = 0, len = node.childNodes.length; i < len; ++i) {
                    getTextNodes(node.childNodes[i]);
                }
            }
        }
        getTextNodes(node);
        return textNodes;
    }

    function removeEmptyTextNodes() {
        var el, trimVal, nodeList = getTextNodesIn(document, true);

        if(Object.prototype.toString.call(nodeList) !== '[object Array]') { return; }

        while (el = nodeList.pop()) {
            trimVal = tirmSpecial(el.nodeValue);
            if (trimVal.length > 0) {
                el.nodeValue = trimVal;
                continue;
            }
            el.parentNode.removeChild(el);
        }
    }

    $("#remEmpty").click(removeEmptyTextNodes);
});

To demonstrate what I mean by empty text nodes use IE's developer window and look at the code in my Fiddle before I remove them with javascript.

Now my solution works so far I tested it but I hate how I need to edit the entire DOM just to do this I also found some other solutions on the web some might even be from stackoverflow I just can't remember where but these are all ugly hacks just like mine I will post them below.

Please guys help me out there just has to be a better solution out there.

Someone suggested changing your markup to this

<ul
    ><li
        ><label class="field">Some Stuff 1</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 2</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 3</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 4</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 5</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 6</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 7</label
        ><input class="value" type="text"
    /></li
    ><li
        ><label class="field">Some Stuff 8</label
        ><input class="value" type="text"
    /></li
></ul>

This works and it gets readable after a while but this has the drawback of everyone in the team remembering to do this awful hack not to mention that auto code indentation is completely broken meaning less productivity for everyone.

Another CSS Hack is to do the following

ul {
    list-style: none;
    width: 100%;

    /* Hack to keep "Text - Empty Text Node" elements from taking up space. */
    letter-spacing: -4px;
    word-spacing: -4px;
}

ul > li {
    display: inline-block;
    width: 25%;

    padding: 3px 8px;

    /* Reverse the Needed Hack to keep "Text - Empty Text Node" elements from taking up space. */
    letter-spacing: normal;
    word-spacing: normal;
}

This also works but you have to remember to apply and undo the word-spacing hack everywhere you use it also it makes some problems if you actually have text in a section with other inline-block elements that need this hack you will then have to add a <span></span> or other wrapping element just so you can reverse the hack.

DeMeNteD
  • 385
  • 4
  • 11
  • 1
    http://css-tricks.com/fighting-the-space-between-inline-block-elements/ – CBroe May 29 '13 at 12:50
  • `lable` needs to be changed to `label`. – James Donnelly May 29 '13 at 12:53
  • Yes `flexbox` is the holy grail for all my problems but there is little support for it right now and the boss would freak if I told him we could only use Chrome. The other solutions on http://css-tricks.com/fighting-the-space-between-inline-block-elements/ all have their own little quirks but thanks for the info its usefull to have, even if I can't find a perfect solution – DeMeNteD May 29 '13 at 13:00

2 Answers2

2

Here's a fairly simple fix:

ul {
    list-style: none;
    margin-left: 4px;
    width: 100%;
}

ul > li {
    display: inline-block;
    margin-left: -4px;
    padding: 3px 8px;
    width: 25%;
}

No JavaScript required!

Edit:

FWIW, I think you'd be a lot better off just accepting the fact that floating the li elements is the simplest way to achieve what you want:

ul {
    clear: both;
    list-style: none;
    width: 100%;
}

ul > li {
    float: left;
    padding: 3px 8px;
    width: 25%;
}

This works in Chrome, FF, Safari, Opera, & IE 8+. It fails in IE 7, but I believe that's because IE 7 doesn't support box-sizing.

ic3b3rg
  • 14,629
  • 4
  • 30
  • 53
  • This is basically the same as the `letter-spacing: -4px; word-spacing: -4px;` hack and its mentioned on [css-tricks](http://css-tricks.com/fighting-the-space-between-inline-block-elements/) – DeMeNteD May 29 '13 at 13:19
  • I know you wanted to avoid floating the elements, but it's the simple solution! See my edit. – ic3b3rg May 29 '13 at 13:52
  • Thanks I know its simple but I try to never use floats its just a personal preference thing I don't like how they remove the content form the flow making markup and styling further down the line more difficult. – DeMeNteD May 29 '13 at 14:05
1

There's a really nice, cross-browser solution to this here, which I've adapted in the code below: http://codepen.io/pageaffairs/pen/LkaIt

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">

<style media="all">

html, body {
    width: 100%;
}

* {
    margin: 0;
    padding: 0;
    border: 0;

    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

input {
    border: 1px solid;
}

ul {
    list-style: none;
    width: 100%;
}

ul > li {
    display: inline-block;
    width: 25%;

    padding: 3px 8px;
}

.field,
.value {
    display: block;
    width: 100%;
}

ul {
    display:table;/* Webkit Fix */
    width:100%;/* set width to stop FF from wrapping li's*/
    text-align:center; /* center list items*/   
    word-spacing:-.25em; /* hide whitespace nodes in all modern browsers (not for webkit)*/
    margin:0;
    padding:.25em 0;
    list-style:none;
}

ul li {
    display:-moz-inline-box; /* FF2 and K-Meleon */
    display:inline-block;
    vertical-align:bottom; 
    word-spacing:0; /* reset from parent ul*/
    /*margin:0 .25em; /*now you can set side margins without node conflict */
    padding:0 .5em;
}

* html ul li { display:inline;} /*IE6*/
*+html ul li { display:inline;} /*IE7*/

</style>

</head>
<body>

<ul>
    <li>
        <label class="field">
            Some Stuff 1
        </label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 2</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 3</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 4</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 5</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 6</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 7</label>
        <input class="value" type="text" />
    </li>
    <li>
        <label class="field">Some Stuff 8</label>
        <input class="value" type="text" />
    </li>
</ul>

</body>
</html>
ralph.m
  • 13,468
  • 3
  • 23
  • 30