Treehouse

Remove Whitespace Between Inline-Block Elements

By on  

I remember being a young developer during the Internet Explorer 6 days and desperately wanting IE to adopt display: inline-block.  The inline-block value is incredibly useful when wanting to control margin and padding on "inline" elements without the need to `block and float` them.  One problem that arrises when you use inline-block is that whitespace in HTML becomes visual space on screen.  Gross.  There are a few ways to remove that space;  some of them are just as gross, one is reasonably nicer.

Solution 0: No Space Between Elements

The only 100% solution to this issue is to not put whitespace between those elements in the HTML source code:

<ul><li>Item content</li><li>Item content</li><li>Item content</li></ul>

Of course this is a mess to maintain but it's practical, logical, and most importantly...reliable.

Solution 1:  font-size: 0 on Parent

The best white-space solution is to set a font-size of 0 on the parent to the inline block elements.  So if you had a <UL> with inline-block <LI>'s, you'd do this:

.inline-block-list { /* ul or ol with this class */
	font-size: 0;
}

.inline-block-list li {
	font-size: 14px; /* put the font-size back */
}

To counteract the parent font-size setting, you must set a font-size for the list items, but that's usually fairly simple.   The only time it wouldn't be simple is if you're in a wicked cascade of relative units you can't easily calculate.  In most cases, however, this will be exactly what you need. Update: unless you care to support Android WebKit.

Solution 2:  HTML Comments

This solution is a bit gangsta but also works.  Using HTML comments as spacers between the elements works just as placing no space between elements would:

<ul>
	<li>Item content</li><!--
 --><li>Item content</li><!--
 --><li>Item content</li>
</ul>

In a word...gross.  In two words...really gross.  In three words...well, you get it.  But it works!

Solution 3:  Negative Margin

Much like solution two, this is regrettable.  You can take advantage of inline-block's flexibility to use a negative margin to negate the space:

.inline-block-list li {
	margin-left: -4px;
}

This is the worst solution because you have to account for variable, sometimes unpredictable spacing.  Avoid at all costs.

Solution 4:  Dropping Closing Angle

Another HTML-based hack solution is to simply place the closing > next to the start of the next tag:

<ul>
	<li>Item content</li
 ><li>Item content</li
 ><li>Item content</li>
</ul>

Not as ugly as the HTML comment hack but I know I'd probably remove that whitespace and not think about why it was there originally.

None of these solutions are ideal but the only alternative is not spacing/indenting your HTML which is also a crap solution.  This isn't a "be careful what you wish for scenario" because inline-block is still incredibly useful, but it is important that developers know how to deal with the space that comes with using it.

ydkjs-4.png

Recent Features

  • 9 Mind-Blowing Canvas&nbsp;Demos

    The <canvas> element has been a revelation for the visual experts among our ranks.  Canvas provides the means for incredible and efficient animations with the added bonus of no Flash; these developers can flash their awesome JavaScript skills instead.  Here are nine unbelievable canvas demos that...

  • CSS&nbsp;Filters

    CSS filter support recently landed within WebKit nightlies. CSS filters provide a method for modifying the rendering of a basic DOM element, image, or video. CSS filters allow for blurring, warping, and modifying the color intensity of elements. Let's have...

Incredible Demos

  • jQuery Countdown&nbsp;Plugin

    You've probably been to sites like RapidShare and MegaUpload that allow you to download files but make you wait a specified number of seconds before giving you the download link. I've created a similar script but my script allows you to animate the CSS font-size...

  • Introducing LazyLoad&nbsp;2.0

    While improvements in browsers means more cool APIs for us to play with, it also means we need to maintain existing code.  With Firefox 4's release came news that my MooTools LazyLoad plugin was not intercepting image loading -- the images were loading regardless of...

Discussion

  1. Pavel Linhart

    Solution 4: Don’t close LI tags + put opening UL and first LI on the same line
    Solution 5: Use a templating engine that collapses the whitespaces/linebreaks for you (eg. Smarty has a modifier for that)

    The 5th one is IMHO the best if you can use it, which is not always :)

    • I started with 4 but it’s a mess to maintain.

    • #5 is certainly the most elegant solution, but #1 is most accessible.

  2. The font-size:0 hack doesn’t work cross browser. It’s as unreliable as the negative margin hack. Many mobile browsers override the font-size value with a minimum one to improve readability.

    There is no reliable and cross browser pure CSS solution. The only hacks that work are the ones involving the HTML itself (comments, leaving LI open, removing white space manually or at build time).

  3. For me Solution 1 is only valid if you don’t size your fonts with ems – which I do.

    And solution 2 could be troublesome when used in an agency setting. If another co-developer didn’t know that there must be html comments between list-items, things could go tits up.

    Even though Solution 3 is your least favourite (and I agree the spacing is sometimes inconsistent – usually 3 or 4 pixels) – this is the solution that I found my using in my work. If I pass my code onto another developer, there’s very little that could go wrong.

  4. agree with Pavel Linhart.
    And i used:

    Solution 6:
    put everything in one line.

  5. Note that the font-size:0 approach doesn’t work on Android browser according to Matt Stow.”>http://codepen.io/stowball/details/LsICH” rel=”nofollow”>Matt Stow.

    Matt Stow." data-user="stowball">

    Also worth a look, the YUI3 grids, where they chose for this mess:

    .yui3-g {
        letter-spacing: -0.31em; /* Webkit: collapse white-space between units */
        *letter-spacing: normal; /* reset IE < 8 */
        *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */
        text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */
    }
    
    /* Opera as of 12 on Windows needs word-spacing.
       The ".opera-only" selector is used to prevent actual prefocus styling
       and is not required in markup.
    */
    .opera-only :-o-prefocus,
    .yui3-g {
        word-spacing: -0.43em;
    }
    
    .yui3-u {
        display: inline-block;
        zoom: 1; *display: inline; /* IE < 8: fake inline-block */
        letter-spacing: normal;
        word-spacing: normal;
        vertical-align: top;
        text-rendering: auto;
    }
    • Thank you for this code sample — incredibly useful! Cheers Geert!

  6. Pavel Linhart

    Once there was this in the spec draft:
    http://www.w3.org/TR/2007/WD-css3-text-20070306/#white-space-collapse

    …and it got moved to CSS4 text :)
    http://dev.w3.org/csswg/css-text-4/#white-space-collapsing

    Sadly it looks like it has still a long way to go before getting implemented (or even finalized).

  7. Solution 2 is the only one that could stand up. It may be ugly but it works. Problem is that if you just take out the spaces like solution 0 then someone may put them back in. Using comments may look gross but they can mean something. Just write something in the comments so people know not to read them like:

    <ul>
    <li>Item content</li><!-- INLINE WHITESPACE DO NOT REMOVE
    --><li>Item content</li><!-- INLINE WHITESPACE DO NOT REMOVE
    --><li>Item content</li>
    </ul>

  8. I can’t wait to start using inline-block more boldly. I still have that awkward feeling whenever i use it, like it’s not really a legit property lol.

    I think Geert De Deckere’s answer is most suitable.

    • Inline-block is a close-enough representation of the self-contained “replaced element” like images, objects, videos, form controls, etc. that I would not feel bad for using it, or feel that it was not legit. There only time I would call into question whether it is legitimate to use inline-block is if the element to which you apply it is not some self-contained structure.

      As to the topic of the article, I think using the margin with an em unit matching the parent font size is best. Perhaps a :before pseudo-element can be used to pull the item into line? Hmm.

  9. Tom

    Wouldn’t flexbox help? (in case you could use it for your project of course)

  10. I’m seeing this working for default 16px = 1em font size without gaps at all standard text zoom levels (ctrl + and ctrl -):

          .ib-parent {
            display: block;
            background-color: white;
            color: black;
          }
          .ib-child {
            display: inline-block;
            background-color: green;
            color: white;
            margin-left: -.33em;
          }
          .not-ib {
            display: inline;
            background-color: red;
            color: black;
          }
    
  11. PM5544

    We switched to using Haml for exactly this.
    It has an elegant way of keeping a clear structure and remove whitespace with the > and < characters.
    Highly recommend it.

  12. I prefer this solution:

    Item content
    Item content
    Item content

  13. I prefer this solution:

    Item content
    Item content
    Item content

    (sorry don’t understand how to put coude in a comment…)

  14. Great post David!

    Personnaly I really hate #0, #2, #3, #4, mostly because I hate ugly code.
    We use #1 but we set the font-size to 1rem on child elements and work our way from there…

    Rem Unit support: http://caniuse.com/#search=rem

    Thanks.

  15. Hamid

    Thanks, i think #1 is best, too
    i used float, something like this:
    ul>li {
    float: left;
    display: block;
    }
    ul {
    height: 30px;
    }
    now i will use your solution

  16. This is what I usually do: http://cdpn.io/rjbBo

    In short margin-left/right: -0.25em and then some nice styles to compensate, if needed. I don’t usually work with “fancy” fonts so I don’t know if it’s always compatible.
    Give me feedbacks if you want!

    • I’ll rectify my comment: I use this technique usually yes, but just in my HTML demos! For most of the “production” code I still rely on a good use of floats and clearfixes (sadly).

  17. I saw on one project we maintain, html was in php string and then it was preg_replace’d, lol.

  18. Sam

    Should solution 4 be this instead?

    Item contentItem contentItem content

  19. Sam

    Damn formatting. pre tag not working :(

    I was saying that “–” before closing “>” is probably wrong.

  20. David, I’m surprised you didn’t mention a JavaScript solution:

    var n = document.getElementById('nodeWithWhiteSpace').firstChild;
    while(n){
        console.log('N', n.nodeType, n);
    	next = n.nextSibling;
    	if(n.nodeType === 3 && !n.nodeValue.trim()){
    		console.log('remove');
    		n.parentNode.removeChild(n);
    	}
    	n = next;
    }
    
  21. Sik

    I use a variant of #4 that looks somewhat more consistent:
    <ul
    ><li>…</li
    ><li>…</li
    ><li>…</li
    ></ul>
    At least every li looks the same!

  22. Thanks for the tip, font-size: 0 on Parent seems to be work just fine

  23. float: left or margin-(left|right): -4px

    • Jacob

      I’m sorry to say that, but you totally missed the point.

      inline-block has many advantages over float, and the negative 4px is too arbitrary bceuase it depends on the font used and how it’s rendered by the browser.

  24. Tobias Aberg

    Yahoo recently updated their letter-spacing solution. Apparently it relied on the good old web safe fonts that is installed on every single computer world wide, except for some weird linux hipster distro in beta that only has the monospaced powerline fonts.

    Their solution:
    “The solution that we ended up shipping is two-fold — it takes advantage of CSS3 Flexbox in modern browsers that support the spec, and sets a specific font stack on pure-g and pure-g-r for older browsers that don’t.” – http://blog.purecss.io/post/60789414532/how-we-improved-grids-in-pure-0-3-0

    The comments in the CSS makes it a bit unclear though.
    “The following font stack makes Pure Grids work on all known environments.

    Use flexbox when possible to avoid letter-spacing side-effects.”
    Sounds promising until then they mention side-effects, no details.

    I like this solution, it’s pretty simple to understand. So if someone thinks this is a really bad idea to use, speak now or I will spam the interwebs with cat sites using this from top to bottom!

  25. Simon

    How about ‘white-space: nowrap;’ on the container. Seems to work on FF, Chrome and Safari.

  26. Adrian Harris

    You better to use block element for such purposes, here is the difference between them: http://basicuse.net/articles/pl/textile/html_css/how_to_display_inline_elements_as_block_elements_and_visa_versa

  27. Jason P. Cochrane

    There’s actually a really clean way to remove whitespace that’s both easy and semantic. It’s called a custom font with zero-width spaces. You just change the font on the container to the linked font, the children back again, and voila. Here’s a download to the font I just cooked up in font-forge with the css @font-face declaration included. Suit to taste. (This link is to Google Drive; click File > Download to save to your computer)

    https://drive.google.com/file/d/0B8W6UmdG-DTVbThfWkI5M1NYRVE/edit?usp=sharing

  28. I remember a solution involving a rarely-used CSS property, something like white-space-collapse:collapse; but I might be tripping…

  29. I tried Jason P. Cochrane’s solution, seems to be working fine but it would be good to know if anyone has found any draw backs, apart from the need to download a small font.

  30. Rick Finster

    After floating doesn’t serve the ability to avoid auto-wrapping the content (even with defined overflow-behaviour), I nearly got to use #1 with the font-size. But then I thought of a more attractive method, which isn’t mentioned here yet but works perfectly: using a table.

    Just a instead of the inline-block, wrapped by

    and setting margin / padding / border of the td to 0. When CSS doesn’t serve enough, I think it’s ok to go back to the root and use tables for layout.

    Comments or shifte linebreaks were no possibility for me, because I had no 100% controll of the markup which was rendered serverside in last instance.

  31. Rick Finster

    Important note:
    Table-Element must be set as inline-block for this solution.

  32. Thanks a lot David!

  33. Ralph

    Here’s a nice example of how to use negative word-spacing to remove the inline-block spaces. It works back to IE6: http://cdpn.io/BfIun

    • Gitlost

      Thanks Ralph, that works really well, gets my vote! Explicitly:

      parent: { display: table; word-spacing: -1em; }
      child: { display: inline-block; word-spacing: 0; }
      
  34. HTML5 doesn’t specify a closing tag as necessary for list elements, so inline block with list items is free of hacks!

  35. Alexander

    In a nutshell: It’s amazing how incredibly inept CSS2 is at creating the most obvious thing in the world – grid-based layouts.

  36. Philippe

    I’m using twig templates which has a function that removes whitespaces.

    {% spaceless %}
        
            foo bar
        
    {% endspaceless %}
    {# output will be foo bar #}
    

    Making solution 0 cross-browser and maintainable.

  37. jason weng
    ul{
        padding: 0;
        border: solid 1px #000;
        letter-spacing  :-4px; /*Remove the letter spacing*/
    }
    li{
        display:inline-block;
        padding: 10px;
        width: 114px;
        border: solid 1px #f00;
        margin: 0;
        letter-spacing  :0px; /*Put back the letter spacing*/ 
    
    }
    

    This works fine for me

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!