Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 950
Kle Avatar asked May 17 '16 11:05

Kle


1 Answers

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)

like image 150
GramThanos Avatar answered Oct 21 '22 02:10

GramThanos