Div width 100% minus fixed amount of pixels
Asked Answered
B

10

361

How can I achieve the following structure without using tables or JavaScript? The white borders represent edges of divs and aren't relevant to the question.

Structure 1

The size of the area in the middle is going to vary, but it will have exact pixel values and the whole structure should scale according to those values. To simplify it, I'd need a way to set "100% - n px" width to the top-middle and bottom-middle divs.

I'd appreciate a clean cross-browser solution, but in case it's not possible, CSS hacks will do.

Here's a bonus. Another structure I've been struggling with and end up using tables or JavaScript. It's slightly different, but introduces new problems. I've been mainly using it in jQuery-based windowing system, but I'd like to keep the layout out of the script and only control the size of one element (the middle one).

Structure 2

Bashuk answered 16/3, 2009 at 17:14 Comment(1)
For the second element, you are saying you want the height of the very middle element to be fixed, but the other elements nearby to be dynamicCrescantia
D
80

You can use nested elements and padding to get a left and right edge on the toolbar. The default width of a div element is auto, which means that it uses the available width. You can then add padding to the element and it still keeps within the available width.

Here is an example that you can use for putting images as left and right rounded corners, and a center image that repeats between them.

The HTML:

<div class="Header">
   <div>
      <div>This is the dynamic center area</div>
   </div>
</div>

The CSS:

.Header {
   background: url(left.gif) no-repeat;
   padding-left: 30px;
}
.Header div {
   background: url(right.gif) top right no-repeat;
   padding-right: 30px;
}
.Header div div {
   background: url(center.gif) repeat-x;
   padding: 0;
   height: 30px;
}
Discommode answered 16/3, 2009 at 17:45 Comment(11)
Thanks for that. I had to tweak it a bit for my situation. The first nested div needed a margin-right instead of padding, and the center div also needed the same right margin.Clariceclarie
Great solution. just a little thing -> this works because ".Header div div" overrides ".Header div". It should be ".Header>div" and ".Header>div>div" instead. Indeed, ".Header div" means any div child or sub div child whereas ".Header>div" means only direct children of .HeaderPellikka
@CharlesHETIER: Yes, that works also, and is easier to use as you don't have to overide all settings of the less specific rule. The answer was written when the support for the > operator was still not good enough to be reliable.Discommode
This is outdated, see the answer below about the calc function on css.Rochdale
@delawen: You have to wait a while before it gets outdated. There is no support for calc in IE 8, or current versions of Anroid Browser or Opera. caniuse.com/#search=calcDiscommode
Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
Why the dwonvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
You say The default width of a div element is auto, which means that it uses the available width., which in my case seems to be false. My divs are only as wide as they need to be to hold whatever I put inside them.Disequilibrium
@BirgerSkogengPedersen: Then there is some other setting that changes the behaviour. If you have floated the div for example, then it behaves as you describe.Discommode
Ah, yes. You're right, display: table; was set. Sorry about that.Disequilibrium
Y
876

New way I've just stumbled upon: css calc():

.calculated-width {
    width: -webkit-calc(100% - 100px);
    width:    -moz-calc(100% - 100px);
    width:         calc(100% - 100px);
}​

Source: css width 100% minus 100px

Yoshida answered 4/2, 2013 at 11:23 Comment(11)
The best answer in 2013 IMHO. The accepted answer is outdated.Sarver
It's about time someone stumbled onto this. I am done with hacks now that I know this. +1 @lechlukaszOctavo
After 10 years of CSS struggling this answer deserves +20000! Still cant believe my eyes...Caddish
All I can say to this is... youtube.com/…Hartsell
This doesn't seem to work on mobile chrome (on my Nexus) or mobile safariQuinones
Doesn't work in Android or IE8, both targets I still wish to support :( Even when I drop IE8 support I'll still want to support Android 4.xArdyth
More compatible? -> $('#yourEl').css('width', '100%').css('width', '-=100px'); (jQuery)Uriisa
Found it: use "display: inline". It helps a lot.Chauffer
For those looking for a solution on IE 8 or earlier, you can use expression() which I believe is a Microsoft-only thing. Not quite the same but closePoriferous
There is a bug with this solution using Less, but there is a workaround: add a '~' and quotation marks around each line. For example, ~"height: calc(100% - 58px)";.Divisible
So nice / elegant ! I used this to auto-adjust the width of a thumbnail preview bar in an image gallery (in which the body width is predefined at 640px). In the CSS stylesheet I added a border of 1px to the thumbnail images, and set the width: calc(20% - 2px);Bemba
D
80

You can use nested elements and padding to get a left and right edge on the toolbar. The default width of a div element is auto, which means that it uses the available width. You can then add padding to the element and it still keeps within the available width.

Here is an example that you can use for putting images as left and right rounded corners, and a center image that repeats between them.

The HTML:

<div class="Header">
   <div>
      <div>This is the dynamic center area</div>
   </div>
</div>

The CSS:

.Header {
   background: url(left.gif) no-repeat;
   padding-left: 30px;
}
.Header div {
   background: url(right.gif) top right no-repeat;
   padding-right: 30px;
}
.Header div div {
   background: url(center.gif) repeat-x;
   padding: 0;
   height: 30px;
}
Discommode answered 16/3, 2009 at 17:45 Comment(11)
Thanks for that. I had to tweak it a bit for my situation. The first nested div needed a margin-right instead of padding, and the center div also needed the same right margin.Clariceclarie
Great solution. just a little thing -> this works because ".Header div div" overrides ".Header div". It should be ".Header>div" and ".Header>div>div" instead. Indeed, ".Header div" means any div child or sub div child whereas ".Header>div" means only direct children of .HeaderPellikka
@CharlesHETIER: Yes, that works also, and is easier to use as you don't have to overide all settings of the less specific rule. The answer was written when the support for the > operator was still not good enough to be reliable.Discommode
This is outdated, see the answer below about the calc function on css.Rochdale
@delawen: You have to wait a while before it gets outdated. There is no support for calc in IE 8, or current versions of Anroid Browser or Opera. caniuse.com/#search=calcDiscommode
Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
Why the dwonvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Discommode
You say The default width of a div element is auto, which means that it uses the available width., which in my case seems to be false. My divs are only as wide as they need to be to hold whatever I put inside them.Disequilibrium
@BirgerSkogengPedersen: Then there is some other setting that changes the behaviour. If you have floated the div for example, then it behaves as you describe.Discommode
Ah, yes. You're right, display: table; was set. Sorry about that.Disequilibrium
P
7

While Guffa's answer works in many situations, in some cases you may not want the left and/or right pieces of padding to be the parent of the center div. In these cases, you can use a block formatting context on the center and float the padding divs left and right. Here's the code

The HTML:

<div class="container">
    <div class="left"></div>
    <div class="right"></div>
    <div class="center"></div>
</div>

The CSS:

.container {
    width: 100px;
    height: 20px;
}

.left, .right {
    width: 20px;
    height: 100%;
    float: left;
    background: black;   
}

.right {
    float: right;
}

.center {
    overflow: auto;
    height: 100%;
    background: blue;
}

I feel that this element hierarchy is more natural when compared to nested nested divs, and better represents what's on the page. Because of this, borders, padding, and margin can be applied normally to all elements (ie: this 'naturality' goes beyond style and has ramifications).

Note that this only works on divs and other elements that share its 'fill 100% of the width by default' property. Inputs, tables, and possibly others will require you to wrap them in a container div and add a little more css to restore this quality. If you're unlucky enough to be in that situation, contact me and I'll dig up the css.

jsfiddle here: jsfiddle.net/RgdeQ

Enjoy!

Petrochemical answered 26/8, 2012 at 10:8 Comment(0)
P
7

You can make use of Flexbox layout. You need to set flex: 1 on the element that needs to have dynamic width or height for flex-direction: row and column respectively.

Dynamic width:

HTML

<div class="container">
  <div class="fixed-width">
    1
  </div>
  <div class="flexible-width">
    2
  </div>
  <div class="fixed-width">
    3
  </div>
</div>

CSS

.container {
  display: flex;
}
.fixed-width {
  width: 200px; /* Fixed width or flex-basis: 200px */
}
.flexible-width {
  flex: 1; /* Stretch to occupy remaining width i.e. flex-grow: 1 and flex-shrink: 1*/
}

Output:

.container {
  display: flex;
  width: 100%;
  color: #fff;
  font-family: Roboto;
}
.fixed-width {
  background: #9BCB3C;
  width: 200px; /* Fixed width */
  text-align: center;
}
.flexible-width {
  background: #88BEF5;
  flex: 1; /* Stretch to occupy remaining width */
  text-align: center;
}
<div class="container">
  <div class="fixed-width">
    1
  </div>
  <div class="flexible-width">
    2
  </div>
  <div class="fixed-width">
    3
  </div>

</div>

Dynamic height:

HTML

<div class="container">
  <div class="fixed-height">
    1
  </div>
  <div class="flexible-height">
    2
  </div>
  <div class="fixed-height">
    3
  </div>
</div>

CSS

.container {
  display: flex;
}
.fixed-height {
  height: 200px; /* Fixed height or flex-basis: 200px */
}
.flexible-height {
  flex: 1; /* Stretch to occupy remaining height i.e. flex-grow: 1 and flex-shrink: 1*/
}

Output:

.container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  color: #fff;
  font-family: Roboto;
}
.fixed-height {
  background: #9BCB3C;
  height: 50px; /* Fixed height or flex-basis: 100px */
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.flexible-height {
  background: #88BEF5;
  flex: 1; /* Stretch to occupy remaining width */
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
<div class="container">
  <div class="fixed-height">
    1
  </div>
  <div class="flexible-height">
    2
  </div>
  <div class="fixed-height">
    3
  </div>

</div>
Prithee answered 10/12, 2015 at 13:29 Comment(0)
S
3

The usual way to do it is as outlined by Guffa, nested elements. It's a bit sad having to add extra markup to get the hooks you need for this, but in practice a wrapper div here or there isn't going to hurt anyone.

If you must do it without extra elements (eg. when you don't have control of the page markup), you can use box-sizing, which has pretty decent but not complete or simple browser support. Likely more fun than having to rely on scripting though.

Schizopod answered 17/3, 2009 at 5:59 Comment(0)
S
3

Maybe I'm being dumb, but isn't table the obvious solution here?

<div class="parent">
    <div class="fixed">
    <div class="stretchToFit">
</div>

.parent{ display: table; width 100%; }
.fixed { display: table-cell; width: 150px; }
.stretchToFit{ display: table-cell; vertical-align: top}

Another way that I've figured out in chrome is even simpler, but man is it a hack!

.fixed{ 
   float: left
}
.stretchToFit{
   display: table-cell;
   width: 1%;
}

This alone should fill the rest of the line horizontally, as table-cells do. However, you get some strange issues with it going over 100% of its parent, setting the width to a percent value fixes it though.

Scrounge answered 19/7, 2015 at 13:41 Comment(0)
C
3

We can achieve this using flex-box very easily.

If we have three elements like Header, MiddleContainer and Footer. And we want to give some fixed height to Header and Footer. then we can write like this:

For React/RN(defaults are 'display' as flex and 'flexDirection' as column), in web css we'll have to specify the body container or container containing these as display: 'flex', flex-direction: 'column' like below:

    container-containing-these-elements: {
     display: flex,
     flex-direction: column
    }
    header: {
     height: 40,
    },
    middle-container: {
     flex: 1, // this will take the rest of the space available.
    },
    footer: {
     height: 100,
    }
Cliquish answered 19/9, 2017 at 4:29 Comment(0)
M
1

what if your wrapping div was 100% and you used padding for a pixel amount, then if the padding # needs to be dynamic, you can easily use jQuery to modify your padding amount when your events fire.

Mathia answered 16/3, 2009 at 17:16 Comment(0)
A
1

I had a similar issue where I wanted a banner across the top of the screen that had one image on the left and a repeating image on the right to the edge of the screen. I ended up resolving it like so:

CSS:

.banner_left {
position: absolute;
top: 0px;
left: 0px;
width: 131px;
height: 150px;
background-image: url("left_image.jpg");
background-repeat: no-repeat;
}

.banner_right {
position: absolute;
top: 0px;
left: 131px;
right: 0px;
height: 150px;
background-image: url("right_repeating_image.jpg");
background-repeat: repeat-x;
background-position: top left;
}

The key was the right tag. I'm basically specifying that I want it to repeat from 131px in from the left to 0px from the right.

Amieeamiel answered 8/2, 2011 at 4:25 Comment(0)
A
0

In some contexts, you can leverage margin settings to effectively specify "100% width minus N pixels". See the accepted answer to this question.

Alger answered 16/3, 2009 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.