12

I have a 3 column layout that should fill the whole screen so on my columns I am using:

width: calc(100% / 3);

So lets say for example my screen is 782px wide:

782 / 3 = 260.66̅

However the problem I have is in Internet Explorer, where it rounds the pixels to two decimal places (260.67)

260.67 * 3 = 782.01

So at certain widths, I lose a 1/3 of my page as it wraps underneath.

Here's an example:

function onResize() {
    $('ul').each(function() {
        var H = eval($(this).height() / $(this).children('li').length);
        $(this).children('li').outerHeight(H);
        $(this).children('li').css('line-height', H + 'px');
        $(this).children('li').outerWidth($(this).width());
    });
}

var timer;
$(window).resize( function() {
    timer && clearTimeout(timer);
    timer = setTimeout(onResize, 100);
});
onResize();
html {
    height:100%;
}
body {
    background:black;
    margin:0;
    padding:0;
    overflow:hidden;
    height:100%;
}
ul {
    width: calc(100% / 3);
    display: inline-block;
    overflow:hidden;
    margin:0;
    padding:0;
    float:left;
    height:100%;
    list-style: outside none none;
}
ul li {
    background: rgb(230,240,163);
    background: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(230,240,163,1)), color-stop(0.5, rgba(210,230,56,1)), color-stop(0.51, rgba(195,216,37,1)), to(rgba(219,240,67,1)));
    background: -webkit-linear-gradient(rgba(230,240,163,1) 0%, rgba(210,230,56,1) 50%, rgba(195,216,37,1) 51%, rgba(219,240,67,1) 100%);
    background: -moz-linear-gradient(rgba(230,240,163,1) 0%, rgba(210,230,56,1) 50%, rgba(195,216,37,1) 51%, rgba(219,240,67,1) 100%);
    background: -o-linear-gradient(rgba(230,240,163,1) 0%, rgba(210,230,56,1) 50%, rgba(195,216,37,1) 51%, rgba(219,240,67,1) 100%);
    background: linear-gradient(rgba(230,240,163,1) 0%, rgba(210,230,56,1) 50%, rgba(195,216,37,1) 51%, rgba(219,240,67,1) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e6f0a3', endColorstr='#dbf043',GradientType=0 );
    text-align:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="ul1">
    <li>Test 1</li>
    <li>Test 2</li>
</ul>
<ul id="ul2">
    <li>Test 3</li>
    <li>Test 4</li>
</ul>
<ul id="ul3">
    <li>Test 5</li>
    <li>Test 6</li>
</ul>

Does anyone know of an elegant way of solving this problem?

I know I could use width: 33.33%, however there's a small part of me inside that cries knowing that it's not 100% bang on.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Jamie Barker
  • 8,145
  • 3
  • 29
  • 64
  • 1
    why not use `width: 33.33%` instead of the calc function? – web-tiki May 27 '15 at 10:57
  • @web-tiki because 33.33 * 3 = 99.99, not 100 – Jamie Barker May 27 '15 at 11:00
  • @web-tiki Firefox does, AFAIK. – Jamie Barker May 27 '15 at 11:05
  • @web-tiki Also, this web page is sometimes being loaded into an iframe within another screen, so it can have these small widths. – Jamie Barker May 27 '15 at 11:08
  • What I mean is that even on wide displays the calculation with `33.33%` has and error lower than 1pixel (`1920 * 33.33% =639.936` and `639.936 * 3 = 1919.808`) which also prevents the last element from breaking on a new line and solve your issue. But you can always make the calculations more presice with `width:33.333333333%`. – web-tiki May 27 '15 at 11:17
  • @web-tiki `width:33.333333333%` gets rounded down to `width:33.33%` ;). Can you put these comments into an answer please? :) – Jamie Barker May 27 '15 at 11:20
  • I just tested in my browser (chrome latest) and it does change the calculation up to the third decimal. I won't add an answer as it is basicaly the same as the one here. I was just curious as to why using a property with less browser support producng issues over a simple although not mathematicaly perfect one. – web-tiki May 27 '15 at 11:31
  • @web-tiki Yes it is _similar_, but not identical. You've given more information (to do with error margins, etc.) and I want to +1 it. I shall probably add a bounty to the question in 2 days and then decide after that which answer to accept. – Jamie Barker May 27 '15 at 11:34

3 Answers3

13

Try width: calc(100% * 0.33333); to make sure float rounding errors err on the side of caution or width: calc((100% / 3) - 0.1px);.

Niklas Brunberg
  • 769
  • 7
  • 17
  • Doing this makes the width generated to be `260.64px` (using the above example). The fact it's not `.66` really bugs me :P. It's also basically the same as what @web-tiki suggested in a comment (`width: 33.33%`) – Jamie Barker May 27 '15 at 11:06
  • Are you looking for mathematical perfection or a working solution? :) There is currently no screen available to consumers (to my knowledge) which will care about anything smaller than 0.3px. It will be rounded by the browser, only in a later stage? – Niklas Brunberg May 27 '15 at 11:10
  • The best of both worlds ideally. Of course I'll take working over perfection but I'm going to hold off for the moment in case someone has a solution I'm looking for. – Jamie Barker May 27 '15 at 11:13
  • Just for sake of fiddling around, try this one (http://jsfiddle.net/NiklasBr/6wo3q40e/2/) which does not require JS. I know it is likely not a complete solution, but still… – Niklas Brunberg May 27 '15 at 11:24
  • Thanks, but my JS was dumbed down and I added the line-height thing just to make me feel better :P. The number of LI's are dynamic so the height has to be generated using JS, also it would appear `calc(100vw / 3)` produces the same outcome as `calc(100% / 3)` :(. Nice idea though! – Jamie Barker May 27 '15 at 11:31
10

2020 Answer

Use flexbox:

.container {
   width: 242px; /* /3 = 80.66̅  */
   height: 100px;
   
   display: flex;
}

.col {
  flex: 1 0 0; /* Set flex basis to 0 to force equal widths */
}

.col1 {
  background-color: red;
}
.col2 {
  background-color: green;
}
.col3 {
  background-color: blue;
}
<div class="container">
  <div class="col col1"></div>
  <div class="col col2"></div>
  <div class="col col3"></div>
<div>

Old Answer

It would seem that the suggestion by @web-tiki with:

width:33.33%;

is the best option.

Community
  • 1
  • 1
Jamie Barker
  • 8,145
  • 3
  • 29
  • 64
  • Flex only works if you want just one line of elements. If you want something like bootstrap's col-4, where the fourth element will go to a new line, this 2020 solution is not the answer. The old one is the best answer. – Thiago Santos Dec 16 '20 at 22:33
0

Better option:

li {
    &:last-child {
        margin-right: -1px;
    }
}

And you can use: width: calc(100% / 3)

avanember
  • 1
  • 1