Question

I have a two column layout, one column is the document content and the other is the navigation. I've set this up using a Bootstrap row, one column is 8 units wide and the other is 3 units wide with an offset of 1 unit. I've set the navigation content to fixed so that it stays on the page.

On some of the pages I want to have an image at the top of the navigation column. I want this image to be responsive and stay within the 3 unit column and be fixed along with the navigation. However, when you set the content to fixed the image is no longer constrained within the 3 unit column.

I've set up a jsfiddle of the problem at http://jsfiddle.net/yKUZW/3/.

Here is the example html:

<div class="container">
    <div class="row">
        <div class="col-xs-8 content">Content goes here...</div>
        <div class="col-xs-3 col-xs-offset-1">
            <div class="fixed">
                <img class="img-responsive" src="http://placekitten.com/300/200">
                Some links go here.
            </div>
        </div>
    </div>
</div>

And the relevant css:

.fixed {
    position: fixed;
    top: 150px;
}

Notice that when the page is resized horizontally the image stretches outside of the light grey container area. What I want is for the right hand side of the image to always align exactly with the right hand edge of the container, resizing the image as needed.

How would I go about accomplishing this?

Was it helpful?

Solution

The Problem

Ignore the image for a second... .img-responsive just makes the image take up 100% of the available space in the parent container.

Then the question becomes, can I add position: fixed to a div and still have it take up the same width as it's parent which has .col-xs-3 (width: 25%)? Once we resolve that, the image should fall into line.

As you may already know about fixed positioning:

for a fixed positioned box, the containing block is established by the viewport

Meaning Fixed is always relative to the parent window, never an element.

Simple Solution

If the viewport is the same width as the parent div, this can be resolved trivially:

HTML:

<div class="row">
    <div class="col-xs-9" id="content">C</div> 
    <div class="col-xs-3">
        <div id="navbar">Navbar</div>
    </div>
</div>

Relative - div takes up 100% of width of parent (.col-xs-3):

#navbar {
    background: yellow;
    position: relative;
}

Fixed - div takes up 100% of screen - apply .col-xs-3 width ourselves:

#navbar {
    background: yellow;
    position: fixed;
    width: 25%;
}

Demo in Fiddle

screenshot fixed vs relative

Better Solution

However, that solution isn't much help to us because the the .container class applies variable widths at different breakpoints to the row. This causes 25% of the parent div and 25% of the viewport to get out of sync.

So how can we get them to sync up again?

To answer that, let's look at exactly what .container is doing:

.container {
    @media (min-width: @screen-sm-min) {
      width: @container-sm;
    }
    @media (min-width: @screen-md-min) {
      width: @container-md;
    }
    @media (min-width: @screen-lg-min) {
      width: @container-lg;
    }
}

So instead of trivially being able to apply a 25% width, we now have to mimic the width applied by .container. Here's how:

Here's some sample markup:

<div class="container">
    <div class="row">
        <div class="col-xs-8 content">Content</div> 
        <div class="col-xs-3 col-xs-offset-1" id="sidebar-outer">
            <div id="sidebar">
                Width: <span id="width-placeholder"></span>px
            </div>
        </div>
    </div>
</div>

Now we can apply a width at all breakpoints with the following CSS:

#sidebar {
   background: yellow;
   position: fixed;
   width: 25%;
}
@media (min-width: 768px) {
  #sidebar {
    width: 158px; /* 632 * .25 */
  }
}
@media (min-width: 992px) {
  #sidebar {
    width: 213px; /* 852 * .25 */
  }
}
@media (min-width: 1200px) {
  #sidebar {
    width: 263px; /* 1052 * .25 */
  }
} 

Here's a side by side comparison of using relative vs fixed position with styling:

Demo in Fiddle

screenshot container

Back to our problem at hand:

Just take the demo from above and add back in our responsive image:

Solution Demo in Fiddle


As a note: most sites opt to use a fixed width side navbar when using position:fixed in order to sidestep these kinds of issues.

OTHER TIPS

After messing with it a bit I believe the best way would be to remove the the fixed div from the bootstrap column, and place it higher up in the dom, or at least outside of the row. There is a lot of negative margin and strange padding stuff going on to get the BS cols to work properly and it is pushing your fixed div around. If it were me and this was going to be a main feature on the site I would make a div with width 100%, abs pos, top left right bottom all at 0, and then place the fixed div inside of that. For a fixed pos div you want it to live in a relative pos parent with right set to 0 and top set to 150 in your case. If the parent is 100% of the windows width then you have pretty good control over where it goes using either px or %.

Thanks Kyle for the amazing solution you described at the top. Here is a solution for 8/4 situation in a normal container (not fluid)

<div class='container'>
   <div class='row'>
      <div class='col-xs-8> something here </div>
      <div class='col-xs-4>
         <div id='sidebar'> content 
         </div>
      </div>
   </div>
</div>

and here the css

#sidebar {
   background: blue;
   position: fixed;
   width: 33.3333%;
}

@media (min-width: 768px) {
  #sidebar {
    width: 235px; 
  }
}
@media (min-width: 992px) {
  #sidebar {
    width: 309px; 
  }
}
@media (min-width: 1200px) {
  #sidebar {
    width: 375px; 
  }
} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top