Kle
Kle

Reputation: 1043

When screen size made smaller bootstrap tabs are overlapping

When screen size made smaller bootstrap tabs are overlapping like image. enter image description here

I used col-sm and my angular HTML is like this (but any non-angular HTML solution is fine too):

<div class="col-sm-6"> <tabset> <tab>
    <tab-heading active="true">
        Tab1
        <toggle-switch ></toggle-switch>
    </tab-heading>
...
</tab>
<tab>
    <tab-heading>Tab2
        <toggle-switch ></toggle-switch></tab-heading>
    ...
</tab>
<tab>
    <tab-heading>Tab3
        <toggle-switch ></toggle-switch></tab-heading>
    ...
</tab></tabset></div>

I would like for the other tabs to stack in the background instead of the foreground.

desired screenshot

Please forgive my terrible gimp skills, but the active tab should always be up front, so if tab 3 is selected, then the other row should shift to the back.

desired active

It doesn't have to be arranged specifically like this, but the point is that the active tab should not have anything in between it and its content pane, so something like this is also fine:

enter image description here

Upvotes: 13

Views: 8701

Answers (7)

sawbeanraz
sawbeanraz

Reputation: 177

Calculate the row index add added to li. On init or active tab changes, then it sorts li position until it is at bottom row.

Hope this what you are trying to achieve.

Demo: http://codepen.io/anon/pen/GqQdyb

HTML

    <div class="col-md-12">

      <ul id="tabs" class="nav nav-tabs" role="tablist">
        <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">Tab 1</a></li>
        <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">Tab 2</a></li>
        <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">Tab 3</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 4</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 5</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 6</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 7</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 8</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 9</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Tab 10</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Profile</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Message</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Very long tab name</a></li>
        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Programming</a></li>
      </ul>

      <!-- Tab panes -->
      <div class="tab-content">
        <div role="tabpanel" class="tab-pane active" id="home">...</div>
        <div role="tabpanel" class="tab-pane" id="profile">...</div>
        <div role="tabpanel" class="tab-pane" id="messages">...</div>
        <div role="tabpanel" class="tab-pane" id="settings">...</div>
      </div>      
    </div>    
  </div>  
</div>

JS

$( function() {  
    var _max = 0;  

    var _calc = function() {
      var _w = $('#tabs').width();
      var _h = $('#tabs').height();  
      var _a = _w;  

      var _index = 0;
      $('#tabs li').each(function(i, v) {            
        var _t = $(v).outerWidth();      
        if(_a < _t) {
          _a = _w;
          _index++;
        }
        $(v).data('rowindex', _index);      
        _a -= _t;      
      });

      _max = _index;
      console.log(_max);
    };



    var _sortTab = function() {      
      var _active = $('li.active').data('rowindex');      
      var _tabs = $('#tabs');
      _tabs.find('li').sort(function(a, b) {        
        var _a = $(a).data('rowindex');
        var _b = $(b).data('rowindex');        
        return (_a == _active && _a !== _b);
      }).appendTo(_tabs);      
      _calc();

      if(_active !== _max) {
        _sortTab();
      }      
    };


  $('#tabs li').on('shown.bs.tab', function (e) {  
    _sortTab();
  });  
  _calc();
  _sortTab();  
});

Upvotes: 0

Nehemiah
Nehemiah

Reputation: 1140

I have also faced the same problem, I fixed out with a solutions for that. I think it will be help full for you.

Note: While handling the bootstrap tab it will not have a responsive tab on mobile device, so it has to be initiated with collapsible grid as mentioned below...

This was previously experienced by me.

Here is my code link.

codepen.io/nehemc/pen/RRQKZB

Here is the code, you need to add in javascript.

<script>
    var fakewaffle = (function($, fakewaffle) {
          'use strict';

          fakewaffle.responsiveTabs = function(collapseDisplayed) {

            fakewaffle.currentPosition = 'tabs';

            var tabGroups = $('.nav-tabs.responsive');
            var hidden = '';
            var visible = '';
            var activeTab = '';

            if (collapseDisplayed === undefined) {
              collapseDisplayed = ['xs', 'sm'];
            }

            $.each(collapseDisplayed, function() {
              hidden += ' hidden-' + this;
              visible += ' visible-' + this;
            });

            $.each(tabGroups, function(index) {
              var collapseDiv;
              var $tabGroup = $(this);
              var tabs = $tabGroup.find('li a');

              if ($tabGroup.attr('id') === undefined) {
                $tabGroup.attr('id', 'tabs-' + index);
              }

              collapseDiv = $('<div></div>', {
                'class': 'panel-group responsive' + visible,
                'id': 'collapse-' + $tabGroup.attr('id')
              });

              $.each(tabs, function() {
                var $this = $(this);
                var oldLinkClass = $this.attr('class') === undefined ? '' : $this.attr('class');
                var newLinkClass = 'accordion-toggle';
                var oldParentClass = $this.parent().attr('class') === undefined ? '' : $this.parent().attr('class');
                var newParentClass = 'panel panel-default';
                var newHash = $this.get(0).hash.replace('#', 'collapse-');

                if (oldLinkClass.length > 0) {
                  newLinkClass += ' ' + oldLinkClass;
                }

                if (oldParentClass.length > 0) {
                  oldParentClass = oldParentClass.replace(/\bactive\b/g, '');
                  newParentClass += ' ' + oldParentClass;
                  newParentClass = newParentClass.replace(/\s{2,}/g, ' ');
                  newParentClass = newParentClass.replace(/^\s+|\s+$/g, '');
                }

                if ($this.parent().hasClass('active')) {
                  activeTab = '#' + newHash;
                }

                collapseDiv.append(
                  $('<div>').attr('class', newParentClass).html(
                    $('<div>').attr('class', 'panel-heading').html(
                      $('<h4>').attr('class', 'panel-title').html(
                        $('<a>', {
                          'class': newLinkClass,
                          'data-toggle': 'collapse',
                          'data-parent': '#collapse-' + $tabGroup.attr('id'),
                          'href': '#' + newHash,
                          'html': $this.html()
                        })
                      )
                    )
                  ).append(
                    $('<div>', {
                      'id': newHash,
                      'class': 'panel-collapse collapse'
                    })
                  )
                );
              });

              $tabGroup.next().after(collapseDiv);
              $tabGroup.addClass(hidden);
              $('.tab-content.responsive').addClass(hidden);

              if (activeTab) {
                $(activeTab).collapse('show');
              }
            });

            fakewaffle.checkResize();
            fakewaffle.bindTabToCollapse();
          };

          fakewaffle.checkResize = function() {

            if ($('.panel-group.responsive').is(':visible') === true && fakewaffle.currentPosition === 'tabs') {
              fakewaffle.tabToPanel();
              fakewaffle.currentPosition = 'panel';
            } else if ($('.panel-group.responsive').is(':visible') === false && fakewaffle.currentPosition === 'panel') {
              fakewaffle.panelToTab();
              fakewaffle.currentPosition = 'tabs';
            }

          };

          fakewaffle.tabToPanel = function() {

            var tabGroups = $('.nav-tabs.responsive');

            $.each(tabGroups, function(index, tabGroup) {

              // Find the tab
              var tabContents = $(tabGroup).next('.tab-content').find('.tab-pane');

              $.each(tabContents, function(index, tabContent) {
                // Find the id to move the element to
                var destinationId = $(tabContent).attr('id').replace(/^/, '#collapse-');

                // Convert tab to panel and move to destination
                $(tabContent)
                  .removeClass('tab-pane')
                  .addClass('panel-body fw-previous-tab-pane')
                  .appendTo($(destinationId));

              });

            });

          };

          fakewaffle.panelToTab = function() {

            var panelGroups = $('.panel-group.responsive');

            $.each(panelGroups, function(index, panelGroup) {

              var destinationId = $(panelGroup).attr('id').replace('collapse-', '#');
              var destination = $(destinationId).next('.tab-content')[0];

              // Find the panel contents
              var panelContents = $(panelGroup).find('.panel-body.fw-previous-tab-pane');

              // Convert to tab and move to destination
              panelContents
                .removeClass('panel-body fw-previous-tab-pane')
                .addClass('tab-pane')
                .appendTo($(destination));

            });

          };

          fakewaffle.bindTabToCollapse = function() {

            var tabs = $('.nav-tabs.responsive').find('li a');
            var collapse = $('.panel-group.responsive').find('.panel-collapse');

            // Toggle the panels when the associated tab is toggled
            tabs.on('shown.bs.tab', function(e) {

              if (fakewaffle.currentPosition === 'tabs') {
                var $current = $(e.currentTarget.hash.replace(/#/, '#collapse-'));
                $current.collapse('show');

                if (e.relatedTarget) {
                  var $previous = $(e.relatedTarget.hash.replace(/#/, '#collapse-'));
                  $previous.collapse('hide');
                }
              }

            });

            // Toggle the tab when the associated panel is toggled
            collapse.on('shown.bs.collapse', function(e) {

              if (fakewaffle.currentPosition === 'panel') {
                // Activate current tabs
                var current = $(e.target).context.id.replace(/collapse-/g, '#');
                $('a[href="' + current + '"]').tab('show');

                // Update the content with active
                var panelGroup = $(e.currentTarget).closest('.panel-group.responsive');
                $(panelGroup).find('.panel-body').removeClass('active');
                $(e.currentTarget).find('.panel-body').addClass('active');
              }

            });
          };

          $(window).resize(function() {
            fakewaffle.checkResize();
          });

          return fakewaffle;
        }(window.jQuery, fakewaffle || {}));

        (function($) {
          fakewaffle.responsiveTabs(['xs', 'sm']);
        })(jQuery);
        $(document).ready(function() {
          $('.tabcontainer .accordion-toggle').click(function() {
            var divTarget = $(this).attr('href'),
              divTargetElt = $(this);

            setTimeout(function() {
              console.log(divTarget);
              $('html,body').animate({
                  scrollTop: divTargetElt.offset().top
                },
                'slow');
            }, 500);
          });
        });
    </script>

Upvotes: 1

sawbeanraz
sawbeanraz

Reputation: 177

A long list tab would not fit into fixed small screen so only way is to display the tabs in second line with is the default behavior.

Another one would be display additional tabs in dropdown menu. Something like here

Here's is a great example created in bootply. click for code

Upvotes: -1

Suraj
Suraj

Reputation: 3127

Don't use float property. I think there is no solution using float property. You can achieve this by using,
style="Position:Fixed;"
I wrote something. Hope it will help you.

CSS



    ul {
        list-style-type: none;
        margin: 0;
        padding: 0;
        background-color: #333;
        width:800px;
        height:45px; width:100%;
    }
    li a {
        position:fixed;
        color: white;
        text-align: center;
        padding: 14px 16px;
        text-decoration: none;

    }

    li a:hover:not(.active) {
        background-color: #111;
    }

    .active {
        background-color: #4CAF50;
    }


HTML

  <html>
    <body>
    <ul >
      <li><a class="active" href="#home">Tab1</a></li>
      <li><a href="#n2" style="left:80px;" >Tab2</a></li>
      <li><a href="#n3" style="left:160px;">Tab3</a></li>
      <li><a href="#n4" style="left:240px;">Tab4</a></li>
      <li><a href="#n5" style="left:320px;">Tab5</a></li>
      <li><a href="#n6" style="left:400px;">Tab6</a></li>
      <li><a href="#n7" style="left:480px;">Tab7</a></li>
      <li><a href="#n8" style="left:560px;">Tab8</a></li>
      <li><a href="#n9" style="left:640px;">Tab9</a></li>
      <li><a href="#n10" style="left:720px;" >Tab10</a></li>
    </ul>
    </body></html>

Upvotes: 0

GramThanos
GramThanos

Reputation: 3622

There is a solution combining both Css and Javascript.

But, you need to know the tab's height and width!

Because every tab has the same width and height in your pictures, this seems to not be a problem.

// Tab width
var tabWidth = 140;
// Tab height
var tabHeight = 42;

var updateAllTabs = function(){
	$('li.active a[data-toggle="tab"]').each(function(){
		updateTabs({target : this});
	});
};

var updateTabs = function(e){
	// Get elements
	var activeItem = e.target.parentNode;
	var menu = activeItem.parentNode;
	var items = menu.getElementsByTagName("li");
	
	// Reset menu
	menu.style.paddingLeft = 0;
	menu.style.paddingBottom = 0;
	
	var menuWidth = jQuery(menu).width();
	
	var otherItems = [];
	
	// Clear old changes - make new list
	for(var i=0; i < items.length; i++){
		items[i].style.marginLeft = "0px";
		items[i].style.marginTop = "0px";
		
		if(items[i] != activeItem)
			otherItems.push(items[i]);
	}
	
	// If one line return (or only one item)
	if(menuWidth >= items.length * tabWidth || items.length <= 1)
		return;
	
	// Make some calculations
	var perLine = Math.floor(menuWidth / tabWidth);
	var lines = Math.ceil(items.length / perLine);
	
	// 1 tab per line
	if(perLine == 1){
		menu.style.paddingBottom = jQuery(activeItem).height() + "px";
		return;
	} else if(perLine + 1 == items.length){
		menu.style.paddingBottom = jQuery(activeItem).height() + "px";
	}
	
	var pad = jQuery(activeItem).width();
	
	// More than one per tab
	menu.style.paddingLeft = pad + "px";
	
	// For every line exept the last
	for(var i=0; i < lines-1; i++){
		// Move first of the line
		otherItems[i*perLine].style.marginLeft = ((i+1)*pad*(-1)) + "px";
		otherItems[i*perLine].style.marginTop = (i*tabHeight) + "px";
	}
	
	return;
};

$( window ).resize(updateAllTabs);
$('a[data-toggle="tab"]').on('shown.bs.tab', updateTabs);
updateAllTabs();
.nav-tabs > li{
  width: 140px;
  height: 42px;
}

@media only screen and (max-width:  840px) {
  .nav-tabs{
    position: relative;
  }
  .nav-tabs > li.active{
    position: absolute;
    bottom: -1px;
    left: 0px;
  }
}
<link rel="stylesheet prefetch" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

<div>

  <!-- Nav tabs -->
  <ul class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#tab1" aria-controls="home" role="tab" data-toggle="tab">Tab 1</a></li>
    <li role="presentation"><a href="#tab2" aria-controls="profile" role="tab" data-toggle="tab">Tab 2</a></li>
    <li role="presentation"><a href="#tab3" aria-controls="messages" role="tab" data-toggle="tab">Tab 3</a></li>
    <li role="presentation"><a href="#tab4" aria-controls="settings" role="tab" data-toggle="tab">Tab 4</a></li>
    <li role="presentation"><a href="#tab5" aria-controls="settings" role="tab" data-toggle="tab">Tab 5</a></li>
    <li role="presentation"><a href="#tab6" aria-controls="settings" role="tab" data-toggle="tab">Tab 6</a></li>
  </ul>

  <!-- Tab panes -->
  <div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="tab1">This is the tab 1</div>
    <div role="tabpanel" class="tab-pane" id="tab2">This is the tab 2</div>
    <div role="tabpanel" class="tab-pane" id="tab3">This is the tab 3</div>
    <div role="tabpanel" class="tab-pane" id="tab4">This is the tab 4</div>
    <div role="tabpanel" class="tab-pane" id="tab5">This is the tab 5</div>
    <div role="tabpanel" class="tab-pane" id="tab6">This is the tab 6</div>
  </div>

</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

So, how does this work?

The basic idea is that every time a new tab is activated, we set the active tab as position: absolute; left: 0px; bottom: -1px; then we add on the tabs menu padding equal to the width of the tab. Lastly, we add a margin minus the width of the tabs on the first tab of each line.

Some more info:

The code works even with more than 2 lines of tabs.

It can easily be converted to match the layout of your last image by adding fake items on the otherItems array and adding margin-right on the previus item. (got it? or I have to code it for you? :P)

Upvotes: 4

Rob Monhemius
Rob Monhemius

Reputation: 5144

I'm a bit puzzled about what you actually are trying to achieve. But I made this solution to hide parts of the inactive tabs (and make them partly overlapping/stacking each other). I used the default bootstrap example. Explanation is in the code. With this technique you are basically making the tabs smaller so they fit a smaller screen properly. Note that you can wrap everything you'd like to disappear in a span.

This still won't do what you want with extreme amounts of tabs. In that case you will have to use some javascript to make some tabs disappear/reappear on the left/right side of your screen.

Example

html

<ul class="nav nav-tabs">
  <li role="presentation" class="active"><a href="#">Home <span>I m whatever was missing</span></a></li>
  <li role="presentation"><a href="#">P<span>rofile</span></a></li>
  <li role="presentation"><a href="#">M<span>essages</span></a></li>
</ul>
<div id="stuff"></div>

css

/*hide all the items after the part you want to show*/
.nav-tabs li span{
  display: none;
}
/*show the items on the parts with the bootstrap .active class*/
li.active span{
  display: inline-block;
}
#stuff{
  background-color: yellow;
  height: 200px;
}
.active a{
  background-color: yellow !important;
}

Upvotes: 0

marcin.g
marcin.g

Reputation: 365

Try this solution: https://jsfiddle.net/DTcHh/22583/

CSS

.nav-tabs { border-bottom: 2px solid #DDD; }
.nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover { border-width: 0; }
.nav-tabs > li > a { border: none; color: #666; }
.nav-tabs > li.active > a, .nav-tabs > li > a:hover { border: none; color: #4285F4 !important; background: transparent; }
.nav-tabs > li > a::after { content: ""; background: #4285F4; height: 2px; position: absolute; width: 100%; left: 0px; bottom: -1px; transition: all 250ms ease 0s; transform: scale(0); }
.nav-tabs > li.active > a::after, .nav-tabs > li:hover > a::after { transform: scale(1); }
.tab-nav > li > a::after { background: #21527d none repeat scroll 0% 0%; color: #fff; }
.tab-pane { padding: 15px 0; }
.tab-content{padding:20px}

UPDATE: I made some improvement, added some jquery. Look at fiddle now.

var active = $('.nav-tabs > li.active').html(),
    last = $('.nav-tabs > li:last-child').html();
    $('.nav-tabs > li.active').removeClass('active').html(last);
    $('.nav-tabs > li:last-child').addClass('active').html(active); 
    last = active;
    $('.nav-tabs li').on('click', function(){
        active = $(this).html();
        last = $('.nav-tabs > li:last-child').html();
        $(this).removeClass('active').html(last);
        $('.nav-tabs > li:last-child').addClass('active').html(active);      
        last = active;
    });

Upvotes: 1

Related Questions