最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Scrolling a div from an outer div - Stack Overflow

programmeradmin6浏览0评论

Check out the small html structure sample below for context. Check out this fiddle for and example of the problem.

Short explanation for fiddle users:

  1. Scroll left - vertical scroll bar not visible
  2. Scroll right - vertical visible
  3. I want the vertical scroll bar always visible
  4. Requirement - The header must remain fixed (visible while scrolling)

Long explanation:

I have a table with a fixed header and a scrollable body. The plexities of that requires two tables. That's all good. In my cause I also have resizable columns. table-layout: fixed for that to work. This is were problems arise.

To make the scrolling body work I've got a div that wraps the .rows table for scrolling. This works great until the grid, specifically the .rows table, overflows in the x direction. In this case the the vertical scroll bar is only visible if the grid is scrolled all the way to the right. Because the scroll bar is on the .row-wrapper div. And that overflow is being hidden by the .grid div. I'd like the scrollbar to be on the .grid-canvas div so that it is visible even when scrolled to the left side.

<div class=grid>
    <div class=grid-canvas>
        <table class=header></table>
        <div class=row-wrapper>
            <table class=rows></table>
        </div>
    </div>
</div>

side note: If you set the table display to block then the wrapping div isn't needed unless you want to support IE8 which I do. Maybe there's a way around that but that another question for another time.

Check out the small html structure sample below for context. Check out this fiddle for and example of the problem.

Short explanation for fiddle users:

  1. Scroll left - vertical scroll bar not visible
  2. Scroll right - vertical visible
  3. I want the vertical scroll bar always visible
  4. Requirement - The header must remain fixed (visible while scrolling)

Long explanation:

I have a table with a fixed header and a scrollable body. The plexities of that requires two tables. That's all good. In my cause I also have resizable columns. table-layout: fixed for that to work. This is were problems arise.

To make the scrolling body work I've got a div that wraps the .rows table for scrolling. This works great until the grid, specifically the .rows table, overflows in the x direction. In this case the the vertical scroll bar is only visible if the grid is scrolled all the way to the right. Because the scroll bar is on the .row-wrapper div. And that overflow is being hidden by the .grid div. I'd like the scrollbar to be on the .grid-canvas div so that it is visible even when scrolled to the left side.

<div class=grid>
    <div class=grid-canvas>
        <table class=header></table>
        <div class=row-wrapper>
            <table class=rows></table>
        </div>
    </div>
</div>

side note: If you set the table display to block then the wrapping div isn't needed unless you want to support IE8 which I do. Maybe there's a way around that but that another question for another time.

Share Improve this question edited Nov 30, 2012 at 22:51 ralphinator80 asked Nov 30, 2012 at 21:17 ralphinator80ralphinator80 6535 silver badges19 bronze badges 2
  • here is a good example of how u can have it done imaputz./cssStuff/bigFourVersion.html – Breezer Commented Dec 1, 2012 at 8:30
  • This does basically the same thing as what I'm getting. The issue still persists though. Overflow is set on the tbody so the scroll is happening on the tbody. When the table width is larger than the container width you see the same issue. The vertical scroll bar is not visible unless you scroll all the way to the right. fiddle – ralphinator80 Commented Dec 3, 2012 at 17:10
Add a ment  | 

3 Answers 3

Reset to default 2

Well after hours of hacking with no luck I decided to disect some of the existing libraries to see how they were acplishing this. Unfortunately I was sorely disappointed. All of them were using javascript.

The up side to this is that the it only requires a small bit of code not that that means it will perform well. To make this perform as well as possible I'm updating the header when required in the x direction. Since this will typically be a small area in my case it should be good enough.

Hundredth times a charm!

fiddle

Here's the basic:

HTML

<div class=grid>
    <div class=grid-canvas>
        <div class=header-wrapper>
            <table class=header></table>
        </div>
        <div class=row-wrapper>
          <table class=rows></table>
        </div>
    </div>
</div>

Javascript

$headerDiv = $('.header-wrapper');
$rowDiv = $('.row-wrapper');
$rowDiv.scroll(function(e) {
    $headerDiv.css({
        left: -$rowDiv[0].scrollLeft + 'px'
    });
});​

CSS

.grid {
  height: 500px;
  width: 350px;
}

.grid-canvas {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.header-wrapper {
  position: absolute;
  top: 0;
  width: auto;
  background-color: white;
  z-index: 1;
}

.row-wrapper {
  position: absolute;
  top: 0;
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  overflow: auto;
  padding-top: 18px;
  background-color: lightgreen;
}

th, td {
  width: 80px;
  min-width: 80px;
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

What about this one, If you want to use javascript/jQuery ?

$(function(){
    $("table").stickyTableHeaders();
});

/*! Copyright (c) 2011 by Jonas Mosbech - https://github./jmosbech/StickyTableHeaders
    MIT license info: https://github./jmosbech/StickyTableHeaders/blob/master/license.txt */

;(function ($, window, undefined) {
    'use strict';

    var pluginName = 'stickyTableHeaders';
    var defaults = {
            fixedOffset: 0
        };

    function Plugin (el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;

        // Cache DOM refs for performance reasons
        base.$window = $(window);
        base.$clonedHeader = null;
        base.$originalHeader = null;

        // Keep track of state
        base.isCloneVisible = false;
        base.leftOffset = null;
        base.topOffset = null;

        base.init = function () {
            base.options = $.extend({}, defaults, options);

            base.$el.each(function () {
                var $this = $(this);

                // remove padding on <table> to fix issue #7
                $this.css('padding', 0);

                $this.wrap('<div class="divTableWithFloatingHeader"></div>');

                base.$originalHeader = $('thead:first', this);
                base.$clonedHeader = base.$originalHeader.clone();

                base.$clonedHeader.addClass('tableFloatingHeader');
                base.$clonedHeader.css({
                    'position': 'fixed',
                    'top': 0,
                    'z-index': 1, // #18: opacity bug
                    'display': 'none'
                });

                base.$originalHeader.addClass('tableFloatingHeaderOriginal');

                base.$originalHeader.after(base.$clonedHeader);

                // enabling support for jquery.tablesorter plugin
                // forward clicks on clone to original
                $('th', base.$clonedHeader).click(function (e) {
                    var index = $('th', base.$clonedHeader).index(this);
                    $('th', base.$originalHeader).eq(index).click();
                });
                $this.bind('sortEnd', base.updateWidth);
            });

            base.updateWidth();
            base.toggleHeaders();

            base.$window.scroll(base.toggleHeaders);
            base.$window.resize(base.toggleHeaders);
            base.$window.resize(base.updateWidth);
        };

        base.toggleHeaders = function () {
            base.$el.each(function () {
                var $this = $(this);

                var newTopOffset = isNaN(base.options.fixedOffset) ?
                    base.options.fixedOffset.height() : base.options.fixedOffset;

                var offset = $this.offset();
                var scrollTop = base.$window.scrollTop() + newTopOffset;
                var scrollLeft = base.$window.scrollLeft();

                if ((scrollTop > offset.top) && (scrollTop < offset.top + $this.height())) {
                    var newLeft = offset.left - scrollLeft;
                    if (base.isCloneVisible && (newLeft === base.leftOffset) && (newTopOffset === base.topOffset)) {
                        return;
                    }

                    base.$clonedHeader.css({
                        'top': newTopOffset,
                        'margin-top': 0,
                        'left': newLeft,
                        'display': 'block'
                    });
                    base.$originalHeader.css('visibility', 'hidden');
                    base.isCloneVisible = true;
                    base.leftOffset = newLeft;
                    base.topOffset = newTopOffset;
                }
                else if (base.isCloneVisible) {
                    base.$clonedHeader.css('display', 'none');
                    base.$originalHeader.css('visibility', 'visible');
                    base.isCloneVisible = false;
                }
            });
        };

        base.updateWidth = function () {
            // Copy cell widths and classes from original header
            $('th', base.$clonedHeader).each(function (index) {
                var $this = $(this);
                var $origCell = $('th', base.$originalHeader).eq(index);
                this.className = $origCell.attr('class') || '';
                $this.css('width', $origCell.width());
            });

            // Copy row width from whole table
            base.$clonedHeader.css('width', base.$originalHeader.width());
        };

        // Run initializer
        base.init();
    }

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName, new Plugin( this, options ));
            }
        });
    };

})(jQuery, window);

live demo

Sorry, i forgot from where i got it. but special thanks to him/her. And also the author i.e Jonas Mosbech. Hope, it will helps you. Thanks. !!

i edited your css and guess this is what you want:

table {
  table-layout: fixed;
}

th, td {
  width: 80px;
  min-width: 80px;
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.grid {
  height: 500px;
  width: 350px;

  overflow-x: auto;
  overflow-y: scroll;
}

.grid-canvas {
  position: relative;
  width: 100%;
  height: 100%;
}

.header {
  position: absolute;
  top: 0;
  background-color: white;
  z-index: 10;
}

.row-wrapper {
  position: absolute;
  top: 0;
  width: auto;
  height: auto;
  /* assumed height of the header */
  padding-top: 18px;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  background-color: lightgreen;
}
发布评论

评论列表(0)

  1. 暂无评论