Scrolling with fixed div layout and min-widths

2020-03-01 17:34发布

问题:

I've been trying to layout this page, but for the life of me, can't seem to get it to work the way I want.

Window = black
Titlebar = red
Content div = blue
Vertical scrollbar = green
Horizontal scrollbar = yellow

Min titlebar/content div width of 1024px, growing to window size.

I may be completely overthinking it and the answer may be way simpler than I'm attempting.

Basically I want to have a fixed titlebar div at the top of the page that never scrolls vertically. If it does not fit in the window horizontally, I want the horizontal scrollbar to scroll both the titlebar and content. If the content div is taller than the window height, I want it to scroll, otherwise I want it to extend to the bottom of the page.

For the most part, I'm under next to no restrictions on how these divs may be set, so imagine there is a blank slate.

Needs to work on modern browsers only on recent OSes. Ideally only a CSS/HTML fix, but will consider some JS if absolutely required. Needs visible scrollbars (some versions I tried the scrollbars were off outside the window scope, ie, not just mousewheel scroll, but click and drag scroll).

回答1:

I have to edit my answer, because after reading Lokesh Suthar's answer I finally understood your question! ;-)

There is no CSS solution! You'll find the reason in the spec (http://www.w3.org/TR/CSS2/visuren.html#fixed-positioning):

Fixed positioning is a subcategory of absolute positioning. The only difference is that for a fixed positioned box, the containing block is established by the viewport. For continuous media, fixed boxes do not move when the document is scrolled.

So you have to go with a JS solution like the one Lokesh Suthar has linked to in his answer.

A personal note:
Normally web designer try to avoid horizontal scrollbars at all costs!
They are "bad" for usability and most users hate to scroll horizontally. And instead of making a fixed positioned element wider than the viewport you should expand its height.
Remember: Using a JS solution on this will make content unreachable/ not visible if JS is disabled!



回答2:

I think this may work for you...

Working Example

JS:

$(window).scroll(function () { // on scroll
    var win = $(window);
    var title = $('.title');
    var winWidth = $(window).innerWidth();
    var titleWidth = title.width();
    if (win.scrollLeft() >= titleWidth - winWidth) { // if scrolled to the right further than .title is wide minus the window's width
        title.addClass('fixed'); // add the fixed class
        title.offset({ //keep the title bar at the top 
            top: win.scrollTop(),
        });
    } else { // if not
        title.removeClass('fixed'); // removed class fixed
        title.offset({ // keep the title bar at the top anyway
            top: win.scrollTop(),
        });
    }
});

CSS:

* {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
html, body {
    width: 1024px;
    height:100%
}
.title {
    background:red;
    position: absolute;
    z-index:2;
    min-width: 100%;
}
#content {
    background: blue;
    padding-top:50px;
    min-width:1024px;
    min-height:100%;
}
.fixed {
    position: fixed;
    right: 0;
}

API documentation:

.scroll()
.innerWidth()
.width()
.scrollLeft()
.offset()
.addClass()
.removeClass()



回答3:

Pure CSS Solution. Here's my updated answer. Please check.

Demo link below:

Fiddle

HTML

<div id="title-bar">Title Bar</div>
<div id="content">Contents</div>

CSS

html, body {
    margin:0;
    padding:0;
    height:100%;
}
#title-bar, #content {
    min-width:1024px;
    width:100%;
}
 #title-bar {
    position:fixed;
    top:0;
    background:#CC0000;
    height:50px;
    color:#fff;
}
#content {
    top:50px;
    position:relative;
    background:#9EC2E3;
    height:calc(100% - 50px);
    overflow:auto;
}

Just let me know if you have concerns.



回答4:

With CSS:

In short, it is not possible with position: fixed;.

As already mentioned by other answers, it is not possible to force a fixed div to scroll, because the div becomes positioned in relation to the viewport (thanks @Netsurfer for digging up the link), and there is no way for us to manipulate this.


Alternative 1: You could set overflow of the body to hidden (thereby hiding browser scrollbars) and add a new wrapper div that fills the entire viewport by using viewport units (vh and vw). You would then nest your titlebar and content divs within this wrapper and give it a horizontal scrollbar. Then you would absolutely position your titlebar in relation to a new titlebar wrapper div, while wrapping your content in a div with 100% (minus the titlebar) height and a vertical scrollbar.

See jsfiddle example.

This approach is rather ugly when you consider all the wrappers... also, when you apply a min-width of 1024 pixels to the content, the vertical scrollbar will move out of the viewport when viewed on smaller screens (as you mentioned in your post). You could position the scrollbar on the left side using direction: rtl;, but the scrollbar will still go out of view when scrolling to the right.

See jsfiddle example with scrollbar on left.

All in all it is not a great solution which would need to be heavily tested for cross-browser support any time anything is changed. Currently it works in Chrome 33 (which I am using) and I have also succesfully tested it in Firefox 27, Internet Explorer 11 and Opera 19. Safari 5.1 (windows) does not like it, but it should work on the newer Mac versions. For Safari 5.1 you can try changing to % heights and dropping the css calc() method, but you'll probably have problems scrolling the entire content.


Alternative 2: Wait. In the future you may be able to use position: sticky; to achieve exactly what you want (assuming this new property ever gains complete browser support). You can see it in action with chrome if you enable the "Enable experimental Web Platform features" option under "chrome://flags/".

See jsfiddle example.


With jQuery:

With jQuery this becomes a trivial task if you forget about position: fixed;, and does not require much code. All you would have to do is position the titlebar div absolutely and then tell it to move every time the window is scrolled:

$window.scroll(function() {
    $(".title").css('top', $window.scrollTop() + "px");
});

Using .css() is slightly faster than using .offset() (see benchmark tests). If JS is disabled the titlebar will simply scroll out of view.

See jsfiddle example.


Considering how easy this is with jQuery, I would suggest using that approach.



回答5:

I think this should answer your query.

CLICK ME

Basically the fellow is trying moving the fixed nav with scroll events(playing with left property as he says)



回答6:

I used position absolute to set height in percentage. like for titlebar ,

position:fixed;
    height:6%;

you can remove wrapper if you don't want to use,

Click for demo

Let me know more if it need some changes



回答7:

You have to use a combination of CSS and JavaScript. As the others stated, a fixed element does not scroll and you cannot choose that it should scroll horizontally but not vertically. So there comes the JS.

This is the shortest form I could think of. This should work on mobile devices, too. It works with a inner div in the fixed element, which is positioned absolute and reacts to the windows scroll event.

Here is the codepen example: http://codepen.io/HerrSerker/pen/AJHyf

This just works with a fixed height header. If your header is not fixed in height, you have to add some JavaScript, that measures the height of the header and adds

HTML

<div id="maker"></div>
<header><div id="header_inner">Lorem ipsum dolor sit amet.</div></header>
<main><div id="#main_inner">Lorem ipsum dolor sit amet ...</div></main>

CSS

html,body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
body {
  overflow: auto;
}
* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
#maker {
  width: 1024px;
  height: 1px;
  margin-top: -1px;
  background: red;
}
header {
  position: fixed;
  min-width: 1024px;
  background: black;
  color:white;
  width: 100%;
  height: 50px;
}
#header_inner {
  padding: 10px;
}
main {
  padding: 0px;
  padding-top: 50px;
  min-height: 100%;
  min-width: 1024px;
  background: gold;
  color: brown;
}
#main_inner {
  padding: 20px;
}

JavaScript

(function() {
  var headerInner = document.getElementById('header_inner');
  headerInner.style.position = 'absolute';
  var scrollReact = function() {          
    headerInner.style.left = '-'+self.pageXOffset+'px';
  }
  if ('addEventListener' in self) {
    self.addEventListener('scroll', scrollReact);
  } else if (typeof self.attachEvent == 'function') {
      self.attachEvent('scroll', scrollReact );
  }
}())