suryanaga
suryanaga

Reputation: 4002

Responsive elements with dynamic content - Making just one element scroll

I'm trying to create a fluid, scrollable element in the middle of 2 other fluid elements. The whole site is supposed to be completely responsive.

My markup is basically this:

<h1>Title</h1>
<nav>Changeable Menu Items In A List</nav>
<section>
   Lots of items which are changing all the time.
</section>
<footer>Footer</footer>

The only element I want to scroll is the <section> element.

I'm kind of out of ideas now... Any help much appreciated.

Upvotes: 5

Views: 5224

Answers (6)

Danield
Danield

Reputation: 125473

Approach #1: Flexbox

The Flexbox Layout (Flexible Box) module (currently a W3C Candidate Recommandation) aims at providing a more efficient way to lay out, align and distribute space among items in a container, even when their size is unknown and/or dynamic (thus the word "flex"). -- from css-tricks

So using the flex box I came up with this FIDDLE

Markup:

<div class="container">
<div class="header">
    <h1>Title</h1>
    <nav>
    </nav>
</div>
<div class="content">content</div>
<footer>footer</footer>
</div>

Relevant CSS:

.content
{
    flex: 1;
    overflow: auto;
}

* {
  margin: 0;
  padding: 0;
}
html,
body {
  height: 100%;
}
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.header,
.content,
footer {
  width: 100%;
}
.header {
  background: yellow;
}
.content {
  background: pink;
  flex: 1;
  overflow: auto;
}
footer {
  background: gray;
  height: 80px;
}
<div class="container">
  <div class="header">
    <h1>Title</h1>
    <nav>
      <ul>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>
        <li><a href="#">Btn</a>
        </li>

      </ul>
    </nav>
  </div>
  <div class="content">
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex
    ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit
    augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem.
    Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit
    litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
    ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie
    consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue
    nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est
    etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi,
    qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

  </div>
  <footer>footer</footer>
</div>

A few points to mention:

1) I only apply flex:1 (ie flex: 1 1 auto) to the scrollable content; the other items can have a fixed or dynamic height.

2) Support for flexbox is surprisingly good in modern browsers (see here) but you will need to add some browser specific css to get this working for some older browsers.

3) For older versions of firefox additional CSS was necessary for this to work. I have since edited them out of the answer, but you can see all that in the history of this answer.

Approach #2 CSS-tables (not cross-browser)

Because you need the header to be dynamic, I initially thought of css tables to do the job.

FIDDLE1 FIDDLE2

So the first row will contain the h1 and nav,

and the second row will take up the rest of the window.

The footer has a fixed height and has position fixed.

...The only problem with this is that I don't think there is a way to do this cross-browser. So as far as I know this approach only works on Chrome and the new opera. The problem is getting scrollbars within the table row. (See this post)

Upvotes: 5

Doug
Doug

Reputation: 1028

Yoda says: A problem which only JavaScript can solve, you have.

http://jsfiddle.net/6MCLN/7/

css:

body {
    background-color: #ff0000;
    background: -ms-linear-gradient(top left, #d00 0%, #f33 50%, #611 100%);
    background: linear-gradient(top left, #d00 0%, #f33 50%, #611 100%);
    margin: 0;
    overflow: hidden;
}

h1, nav, footer {
    background-color: rgba(40, 40, 40, 0.4);
    margin: 0;
    padding: 10px;
}

section {
    overflow-y: scroll;
    padding: 10px;
}

The aforementioned JavaScript:

$(function () {

    var thereIsNoTry = function () {

        $('section').css({ height:
            $(window).height() - 
            $('h1').height() -        
            $('nav').height() -      
            $('footer').height() -                             
            parseInt($('h1').css('padding-top')) -          
            parseInt($('h1').css('padding-bottom')) -    
            parseInt($('nav').css('padding-top')) -          
            parseInt($('nav').css('padding-bottom')) -  
            parseInt($('footer').css('padding-top')) -          
            parseInt($('footer').css('padding-bottom'))  -
            parseInt($('section').css('padding-top')) -          
            parseInt($('section').css('padding-bottom'))
        });

    };

    $(window).resize(thereIsNoTry);

    thereIsNoTry();

});

EDIT

The big caveat to using javascript for this kind of thing is that if the DOM in the header changes without resizing the window, your 'section' has to be resized manually. The following additional JavaScript, however, will keep it up to date in most scenarios:

$(function () {

    var thereIsNoTry = function () {

        $('section').css({ height:
            $(window).height() - 
            $('h1').height() -        
            $('nav').height() -      
            $('footer').height() -                             
            parseInt($('h1').css('padding-top')) -          
            parseInt($('h1').css('padding-bottom')) -    
            parseInt($('nav').css('padding-top')) -          
            parseInt($('nav').css('padding-bottom')) -  
            parseInt($('footer').css('padding-top')) -          
            parseInt($('footer').css('padding-bottom'))  -
            parseInt($('section').css('padding-top')) -          
            parseInt($('section').css('padding-bottom'))
        });

    };

    $(window).resize(thereIsNoTry);

    thereIsNoTry();

    //In case you're updating the DOM
    $(document).ajaxSuccess(thereIsNoTry);

    var oldAnimate = jQuery.fn.animate;

    //In case the header can be animated
    jQuery.fn.animate = function (properties, duration, 
                                  animation, easing) {

        if (arguments.length == 4) {
            return oldAnimate.call(this, properties, 
                                   duration, animation, easing);
        }

        if (arguments.length == 3) {
            return oldAnimate.call(this, properties,
                                   duration, animation);
        }

        if (arguments.length == 2 && typeof duration === 'object') {

            var options = {
                progress: function (animation, progress, remainingMs) {

                    if (duration.progress) {
                        duration.progress.call(this, animation, 
                                               progress, remainingMs);
                    }

                    thereIsNoTry();

                }
            }

            var option = $.extend({}, duration, options);

            return oldAnimate.call(this, properties, option);

        }

        if (arguments.length == 2) {
            return oldAnimate.call(this, properties, {
                duration: duration,
                progress: thereIsNoTry
            });
        }

        return oldAnimate.call(this, properties);

    };

    $('nav').animate({ height: '100px' }, { duration: 'slow' });

}); 

EDIT

Added overflow: hidden to BODY to prevent 'flickering' vertical scrollbar

Upvotes: 0

Dom Day
Dom Day

Reputation: 2562

If your only problem with using the position:fixed option is a scrolling background image, place the background image in an absolutely positioned object with a negative z-index ?

( I would have made this a comment on the original question rather than as an answer, but I couldn't figure out how. hah. )

Upvotes: 1

G-Cyrillus
G-Cyrillus

Reputation: 105903

are you looking for something like this ? (not too clear to me)

http://codepen.io/gcyrillus/pen/gHDud http://codepen.io/gcyrillus/full/gHDud
it uses javascript to reset bg position in header/footer when page is scrolling.

function scrollit() {
if(!window.pageYOffset) {
     var pageScroll = document.body.screeny;  
     }

else {
    var pageScroll = window.pageYOffset;
      }
var mybg= document.body;
  mybg.style.backgroundPosition=" center -"+pageScroll+"px ";


}
window.onload     = scrollit ;
window.onresize   = scrollit;
window.onscroll   = scrollit;

and css to wich it's applyed

   body:before, body:after {
      content:'';
      background: inherit  ;
      position:fixed;
      z-index:2;
      width:100%;
      left:0;
    }
    body:before {
      height:120px; 
      top:0;
    }
    body:after {
      bottom:0;
      height:60px;
    }
    body {
      margin:0;
      background:url('http://lorempixel.com/1920/1500/nature/10')  center 0 fixed;
      background-size: 150% 300%;
    }

Some fiddle or even a screenshot of what it is suppose to look, may help us to help you

Upvotes: 3

Shikayaru
Shikayaru

Reputation: 109

This is kind of a crazy answer, but you could try placing a dummy element above <section> and use CSS to style it as visibility: hidden. Visibility: hidden will cause the dummy element to still take up space, but you wont see anything in it.

Now if the content of your <nav> is dynamically supplied, are you able to use the same code that supplies the content for your <nav> to supply content for the dummy element? This way, you would pretty much have a margin set for the same size as your <nav>, but wouldn't need to use additional javascript to change the height.

Finally, you set the <nav>'s position to fixed and this sounds like it would solve the problem. Hope this helps.

Upvotes: 1

ponysmith
ponysmith

Reputation: 427

Use fixed positioning for the nav and footer and set the height of the center section using JS.

CSS

nav { position: fixed; top: 0; left: 0; }
footer { position: fixed; bottom: 0; left: 0; }
section { overflow: auto; }

JS (assumes jQuery)

$(document).ready(function() {
  function setHeight() {
    var nav_h = $('nav').outerHeight();
    var footer_h = $('footer').outerHeight();
    var window_h = $(window).height();
    $('section').css({ 
      'height': window_h - nav_h - footer_h + 'px',
      'margin-top': nav_h + 'px',
      'margin-bottom': footer_h + 'px'
    });
  }

  $(window).on('resize', function() { setHeight(); });
  setHeight();
});

Upvotes: 3

Related Questions