Search code examples
jqueryhtml-tablewidth

jQuery width() returning incorrect values on table cells


In a plugin I'm writing I'm having terrible trouble with widths of table cells. All I do is get the width of the table cell using jQuery's .width() function, then set that same cell to be the width returned. Basically, this:

$table.find('> thead > tr > th').each( function() {
    var $th = $(this);
    $th.css({width: $th.width()});
} );

However, in many instances the width returned is incorrect and setting it changes the width of the cells. At first it just seemed like it was off by 1px so I added 1px to the returned width. But with thicker borders it's off by more - however it doesn't seem to be a case of simply adding the border width. For starters, there are obviously 2 borders but it's only off by the width of 1 border. And with varying border widths it seems almost random which value you need to add.

Here's an example with my code - the width-setting part runs 1 second after page load so you can see the change. Is there a reliable way to get/set the width of table cells in Javascript?


Solution

  • demo: https://so.lucafilosofi.com/jquery-width-returning-incorrect-values-on-table-cells/

    this is your plugin almost rewrited... tested on IE7-10, Chrome, Firefox

        (function($) {
            $.fn.stickyHeader = function() {
                return this.each(function() {
    
                    // apply to tables only
                    if (this.tagName.toUpperCase() !== 'TABLE')
                        return;
    
                    var $table = $(this).addClass('jq-stickyHeader-table');
                    var $wrapper = $table.wrap('<div/>').parent().addClass('jq-stickyHeader-wrapper');
    
                    // set each TH to its own width
                    $table.find('thead th').each(function() {
                        $(this).html('<div>' + $(this).text() + '</div>');
                        $(this).width($(this).find('div').width());
                    });
    
                    $wrapper.width($table.width()).height($table.height());
    
                    // clone entire table and remove tbody (performance seems fine)
                    var $stickyheader = $table.find('thead').clone().wrap('<table/>').parent().addClass('jq-stickyHeader');
    
                    // hack for IE7
                    if ($.browser.msie && parseInt($.browser.version, 10) == 7) {
                        $table.find('tr:first-child td').css('border-top', 0);
                    }
    
                    $stickyheader.css({
                        'width' : $table.width(),
                    }).insertAfter($table);
    
                    $(window).scroll(function() {
                        // while over the table, show sticky header
                        var currTop = ($(this).scrollTop() - $table.offset().top);
    
                        $stickyheader.stop(true, true).animate({
                            top : currTop
                        }, 100);
    
                        var scrollLimit = $table.offset().top + ($table.height() - $stickyheader.height());
                        var isVisible = (currTop > $table.offset().top && currTop < scrollLimit) ? 'block' : 'none';
                        $stickyheader.css({
                            display : isVisible
                        });
                    });
    
                });
            };
    
        })(jQuery);
    
        $(function() {
            $('table').stickyHeader();
        });
    

    css inside demo source!