Reputation: 1043
When screen size made smaller bootstrap tabs are overlapping like image.
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.
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.
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:
Upvotes: 13
Views: 8701
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
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
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
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
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
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.
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
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