74

I am trying to dynamicly change the width of a div using CSS and no jquery. The following code will work in the following browsers: http://caniuse.com/calc

/* Firefox */
width: -moz-calc(100% - 500px);
/* WebKit */
width: -webkit-calc(100% - 500px);
/* Opera */
width: -o-calc(100% - 500px);
/* Standard */
width: calc(100% - 500px);

I want also support IE 5.5 and higher, i found the following: expression. Is this the correct usage:

/* IE-OLD */
width: expression(100% - 500px);

Can I also support Opera and the Android browser?

dippas
  • 58,591
  • 15
  • 114
  • 126
H3AP
  • 1,058
  • 1
  • 10
  • 16
  • 69
    Wow, IE 5.5? Are you distributing this to the Ark or something? – BenM Apr 16 '13 at 10:17
  • 1
    How did you knew that! Well i am trying at least to get it working on 6 or 7. – H3AP Apr 16 '13 at 10:23
  • 3
    IE6-7 are close to dead, and IE8 doesn't support `expression` - ["Dynamic properties (also called "CSS expressions") are no longer supported in Internet Explorer 8 and later, in IE8 Standards mode and higher. "](http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx). – Rob W Apr 16 '13 at 10:26
  • You won't be able to support the browsers you're talking about with using some JavaScript I'm afraid. – Billy Moat Apr 16 '13 at 10:28
  • 3
    Are you sure you're not having an [XY-problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)? *Why* are you trying to do this? Perhaps something simple like margins/paddings and/or a wrapper element may solve your layout issue? – Jeroen Apr 16 '13 at 10:29
  • Thanks for the information. Time to upgrade everyone to IE 10 ;) – H3AP Apr 16 '13 at 10:38
  • 1
    If I were you, I'd rethink my support for IE5.5. IE6 is officially pronounced dead by Microsoft. I suspect (hope) IE7 to follow soon too. Not to get the old discussion back, but do you really want this? If the answer is yes, then by all means go for it. – Marijke Luttekes Apr 16 '13 at 10:39
  • I'm not so sure if this really is a direct alternative to calc(). There's still an advantage to using calc() for dynamic height. Say sidebar is gonna get longer than content then that would not expand the page in length. – Jomar Sevillejo May 28 '15 at 23:46
  • Since padding is scrollable, you may want to use transparent `border` instead. Just replace `padding-left: 300px;` with `border-left: 300px solid transparent`. – Juribiyan Nov 23 '16 at 10:13

6 Answers6

120

Almost always box-sizing: border-box can replace a calc rule such as calc(100% - 500px) used for layout.

For example:

If I have the following markup:

<div class="sideBar">sideBar</div>
<div class="content">content</div>

Instead of doing this: (Assuming that the sidebar is 300px wide)

.content {
  width: calc(100% - 300px);
}

Do this:

.sideBar {
     position: absolute; 
     top:0;
     left:0;
     width: 300px;
}
.content {
    padding-left: 300px;
    width: 100%;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}
html,
body,
div {
  height: 100%;
}
.sideBar {
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  background: orange;
}
.content {
  padding-left: 300px;
  width: 100%;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  background: wheat;
}
<div class="sideBar">sideBar</div>
<div class="content">content</div>

PS: I won't work in IE 5.5 (hahahaha) , but it will work in IE8+ , all mobile, and all modern browsers (caniuse)

Width Demo

Height Demo

I just found this post from Paul Irish's blog where he also shows off box-sizing as a possible alternative for simple calc() expressions: (bold is mine)

One of my favorite use-cases that border-box solves well is columns. I might want to divide up my grid with 50% or 20% columns, but want to add padding via px or em. Without CSS’s upcoming calc() this is impossible… unless you use border-box.

NB: The above technique does indeed look the same as would a corresponding calc() statement. There is a difference though. When using a calc() rule the value of the width of the content div will actually be 100% - width of fixed div, however with the above technique, the actual width of the content div is the full 100% width, yet it has the appearance of 'filling up' the remaining width. (which is probably good enough for want most people need here)

That said, if it is important that the content div's width is actually 100% - fixed div width then a different technique - which makes use of block formatting contexts - may be used (see here and here for the gory details):

1) float the fixed width div

2) set overflow:hidden or overflow:auto on the content div

Demo

Community
  • 1
  • 1
Danield
  • 121,619
  • 37
  • 226
  • 255
  • 1
    Why are these 2 needed? `-moz-box-sizing: border-box;` & `box-sizing: border-box;`. Can't I just specify padding & width – user May 28 '14 at 04:47
  • 2
    @buffer - No, because the default box-model uses `box-sizing-content-box` which means that if you add padding - the width of your element increases. With `box-sizing:border-box` the padding is an inner padding and the width of the element remains according to what you set it to be. – Danield May 28 '14 at 05:51
  • What to do if it's the height that's a combination of px and % and the % should take up the remaining height? – miyalys Aug 05 '14 at 12:22
  • 2
    How would this change if it was with height instead of width? – streetlight Jan 20 '15 at 15:12
  • @streetlight - I added a demo for height as well in the post – Danield Dec 16 '15 at 15:02
  • 2
    Knew it, but didn't think of it. Old android is still common, supports box sizing but not calc. a simple absolute and padding saves the day. – Mathijs Segers Jan 18 '16 at 09:17
  • Is there anyway to do it using a border becuase the way I tried, the border was still before the padding which doesn't help. If you can use inner padding, is there a way to do an inner border? – Richard Young Mar 23 '16 at 16:15
  • http://jsfiddle.net/T92Fk/376/ A part of a scrollbar is hidden under the Header block – Ivan Rave Sep 20 '16 at 08:26
  • @IvanRave Use position relative instead of absolute in that case: http://jsfiddle.net/danield770/8fv1a2ob/ (I also made a few other modifications :) ) – Danield Sep 20 '16 at 08:33
  • In this case it can be done without `border-box` simply by omitting `width: 100%`: https://stackoverflow.com/a/45626311/822138 – sam Aug 11 '17 at 03:06
36

Just have a fallback before the calc will do the trick.

width: 98%;               /* fallback for browsers without support for calc() */
width: calc(100% - 1em);

See more here https://developer.mozilla.org/en-US/docs/Web/CSS/calc

Tommy Bjerregaard
  • 1,089
  • 11
  • 24
18

use this

    .content
{
    width: 100%;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    padding-right: 500px;
    margin-right: -500px;
}
Mohamed Malik
  • 181
  • 1
  • 3
  • 4
    Isn't this the same thing Danield proposed in his answer? – skmasq Jan 03 '14 at 23:38
  • 3
    No, it isn't.. If you have an image of 500px and if you want to display a flanked text of (100%-500px), the only way I've found to show them correctly in IE8 is to add a negative margin to text. Otherwise text is displayed as a block. – Giorgio Mar 13 '14 at 08:12
  • 1
    margin-right: -500px got mine working for text. Don't know if it overrode something I missed, I don't care. Life saver. – myol Jun 05 '14 at 16:57
0

Just spent the best part of 3 hours trying to workaround this for a specific case on andriod devices, couldnt get box sizing to work so i've linked it into my JS as a dirty workaround... no jQuery required though! :)

Taken on working code on andriod 2.3.

<div class="sessionDiv" style="width:auto;">
<img> <!-- image to resize -->
</div>
<div class="sessionDiv" style="width:auto;">
<img> <!-- image to resize -->
</div>

JS with event listeners

var orient =
{
    orientation:window.orientation,
    width: window.innerWidth,
    check: function()
    {
        // if orientation does not match stored value, update
        if(window.orientation !== this.orientation)  
        {
            this.orientation = window.orientation; //set new orientation
            this.width = window.innerWidth; //set new width
            this.adjustIrritatingCSS(this.width); //change ui to current value
        }
        //if width does not match stored value, update
        if(window.innerWidth !== this.width)
        {
            this.width = window.innerWidth; //set new width
            this.adjustIrritatingCSS(this.width); //change ui to current value
        }
    },
    adjustIrritatingCSS: function(screenWidth)
    {   
    //disgusting workaround function
        var titleBoxes = document.getElementsByClassName('sessionDiv'); 
        var i = titleBoxes.length;
        var sessWidth = screenWidth - 300; // calc(100% - 300px); -> equivalent
        while(i--)
        {
            titleBoxes[i].style.width = String( sessWidth + "px"); 
            //resize image in auto sized div
        }
        sessWidth = null; //clear width
        titleBoxes = null; //clear nodelist
        i = null; // clear index int
    }
};

window.onload = function()
{
    window.addEventListener('resize', function(){orient.check();}); 
    //on resize, check our values for updates and if theres changes run functions
    window.addEventListener('orientationchange', function(){orient.check();});
    //on rotate, check our values for updates and if theres changes run functions
    setInterval(function(){orient.check();}, 2000);
    //occasionally check our values for updates and if theres changes run functions(just incase!!)
    orient.adjustIrritatingCSS(orient.width); 
    //sets value on first run
};

Hope this helps anyone who cant get the box-sizing working! PS I have experienced problems with ios using this...

bhiqa
  • 1
0

Change #menuLog width with % or px and you will see magic. Works with every device even < 2.3

*{
 -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
#menuLog{
  width:30%;
  /*width:300px;*/
 height: 60px;
 padding: 5px;
 background-color: #ddd;
}
#menuLog > div[inline-log="1"]{
 display: inline-block;
 vertical-align: top;
 width: 100%;
 height: 100%;
 margin-right: -60px;
}
#menuLog > div[inline-log="1"] > div[inline-log="1.1"]{
 margin-right: 60px;
 height: 100%;
 background-color: red;
}
#menuLog > div[inline-log="2"]{
 display: inline-block;
 vertical-align: top;
 width: 60px;
 height: 100%;
}
#menuLog > div[inline-log="2"] > div[inline-log="2.1"]{
 display: inline-block;
 vertical-align: top;
 width: 55px;
 height: 100%;
 background-color: yellow;
 margin-left:5px;
}
<div id="menuLog">
  <div inline-log="1">
    <div inline-log="1.1">
      One
    </div>
  </div><div inline-log="2">
     <div inline-log="2.1">
      Two
     </div>
  </div>
</div>
0

I wanted to add the no-calc, no-border-box (i.e., CSS2) alternative.

Normal-flow block elements initially have width: auto, which is effectively the width of the containing block minus the margin, border, and padding widths.

The example above can be done, without border-box, simply as

.content {
    padding-left: 300px;
}

Similarly, with

.content {
  margin-left: 1px;
  border-left: 1em solid;
  padding-left: 1rem;
}

the effective width is 100% - 1px - 1em - 1rem.

For absolutely positioned elements, height: auto has similar properties:

.content {
  position: absolute;
  top: 0;
  bottom: 0;
  margin-bottom: 1px;
  border-bottom: 1em solid;
  padding-bottom: 1rem;
}

Here the effective height is 100% - 1px - 1em - 1rem.

sam
  • 40,318
  • 2
  • 41
  • 37