Reputation: 33
I want to create sort of tab menu. My problem is that before page is fully-loaded, tabbed content appears for a very short time (for few miliseconds or so) without CSS settings. After that, page is loading and then working correctly-tab content is appearing and disappearing just as I wanted. What can I do to avoid that?
$(function() {
$('.tabs-container').addClass('js');
$('.tabs').each(function() {
const $a = $(this).find('a');
$a.on('click', function(e) {
const $this = $(this);
const href = $this.attr('href');
const $target = $(href);
if ($target.length) {
e.preventDefault();
$this.siblings('a').removeClass('active');
$this.addClass('active');
$target.siblings('.tab-content').removeClass('active');
$target.addClass('active');
}
});
});
});
.tabs {
list-style-type: none;
margin: 5px 0 0 0;
padding: 0;
clear: both;
padding-bottom: 10px;
overflow: hidden;
}
.tabs a {
width: 20%;
display: inline-block;
height: 3em;
margin: 2px;
background: #eee;
font-size: 1em;
font-weight: bold;
line-height: 3em;
text-decoration: none;
color: #333;
text-align: center;
}
.tabs a.active {
background: #EC185D;
color: #fff;
}
.tabs-container.js .tab-content {
display: none;
padding: 1em;
font-size: 2em;
background: #eee;
border-radius: 2px;
}
.tabs-container.js .tab-content.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="container">
<div class="tabs">
<a href="#tab1" class="active">tab1</a>
<a href="#tab2">tab2</a>
<a href="#tab3">tab3</a>
<a href="#tab4">tab4</a>
</div>
<div class="tabs-container">
<article id="tab1" class="tab-content active">
<div class="tab-text">
Content1
</div>
</article>
<article id="tab2" class="tab-content">
<div class="tab-text">
Content 2
</div>
</article>
<article id="tab3" class="tab-content">
<div class="tab-text">
Content 3
</div>
</article>
<article id="tab4" class="tab-content">
<div class="tab-text">
Content4
</div>
</article>
</div>
</div>
Upvotes: 0
Views: 59
Reputation: 26370
You could hide .tabs-container
until your JS is initialized and executed. For instance, an easy way to do it is :
.tabs-container:not(.js) {
display: none;
}
So it starts off hidden, then, when your tabs are built with JS and it gets the js
class, it becomes visible, so you don't see the init blinking.
$(function() {
$('.tabs-container').addClass('js');
$('.tabs').each(function() {
const $a = $(this).find('a');
$a.on('click', function(e) {
const $this = $(this);
const href = $this.attr('href');
const $target = $(href);
if ($target.length) {
e.preventDefault();
$this.siblings('a').removeClass('active');
$this.addClass('active');
$target.siblings('.tab-content').removeClass('active');
$target.addClass('active');
}
});
});
});
.tabs-container:not(.js) {
display: none;
}
.tabs {
list-style-type: none;
margin: 5px 0 0 0;
padding: 0;
clear: both;
padding-bottom: 10px;
overflow: hidden;
}
.tabs a {
width: 20%;
display: inline-block;
height: 3em;
margin: 2px;
background: #eee;
font-size: 1em;
font-weight: bold;
line-height: 3em;
text-decoration: none;
color: #333;
text-align: center;
}
.tabs a.active {
background: #EC185D;
color: #fff;
}
.tabs-container.js .tab-content {
display: none;
padding: 1em;
font-size: 2em;
background: #eee;
border-radius: 2px;
}
.tabs-container.js .tab-content.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="container">
<div class="tabs">
<a href="#tab1" class="active">tab1</a>
<a href="#tab2">tab2</a>
<a href="#tab3">tab3</a>
<a href="#tab4">tab4</a>
</div>
<div class="tabs-container">
<article id="tab1" class="tab-content active">
<div class="tab-text">
Content1
</div>
</article>
<article id="tab2" class="tab-content">
<div class="tab-text">
Content 2
</div>
</article>
<article id="tab3" class="tab-content">
<div class="tab-text">
Content 3
</div>
</article>
<article id="tab4" class="tab-content">
<div class="tab-text">
Content4
</div>
</article>
</div>
</div>
Edit
You will always have a tiny delay, because your tabs are being built with JS. So, whatever happens, you have to load jQuery, render the DOM, wait for the document to be ready, then execute the tab building. There is no way around this, it will never be instant. As a workaround, you can hide the whole #container
or even the whole document (<body>
) tag, then switch it to visible after the tabs are built.
$(function() {
$('.tabs-container').addClass('js');
$('.tabs').each(function() {
const $a = $(this).find('a');
$a.on('click', function(e) {
const $this = $(this);
const href = $this.attr('href');
const $target = $(href);
if ($target.length) {
e.preventDefault();
$this.siblings('a').removeClass('active');
$this.addClass('active');
$target.siblings('.tab-content').removeClass('active');
$target.addClass('active');
}
});
});
$("body").show();
});
body {
display : none;
}
.tabs {
list-style-type: none;
margin: 5px 0 0 0;
padding: 0;
clear: both;
padding-bottom: 10px;
overflow: hidden;
}
.tabs a {
width: 20%;
display: inline-block;
height: 3em;
margin: 2px;
background: #eee;
font-size: 1em;
font-weight: bold;
line-height: 3em;
text-decoration: none;
color: #333;
text-align: center;
}
.tabs a.active {
background: #EC185D;
color: #fff;
}
.tabs-container.js .tab-content {
display: none;
padding: 1em;
font-size: 2em;
background: #eee;
border-radius: 2px;
}
.tabs-container.js .tab-content.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="container">
<div class="tabs">
<a href="#tab1" class="active">tab1</a>
<a href="#tab2">tab2</a>
<a href="#tab3">tab3</a>
<a href="#tab4">tab4</a>
</div>
<div class="tabs-container">
<article id="tab1" class="tab-content active">
<div class="tab-text">
Content1
</div>
</article>
<article id="tab2" class="tab-content">
<div class="tab-text">
Content 2
</div>
</article>
<article id="tab3" class="tab-content">
<div class="tab-text">
Content 3
</div>
</article>
<article id="tab4" class="tab-content">
<div class="tab-text">
Content4
</div>
</article>
</div>
</div>
Upvotes: 1
Reputation: 337560
The issue is known as a 'FOUC', or Flash of Unstyled Content. The issue is because you're adding the js
class through Javascript, which runs after the DOM has loaded. Therefore there's a slight delay between the page loading and the JS running which adds the class to hide the elements.
The best way to solve this is to add the class directly on the elements in HTML. That way they will be hidden as soon as they are loaded. Try this:
$(function() {
$('.tabs').each(function() {
const $a = $(this).find('a');
$a.on('click', function(e) {
const $this = $(this);
const href = $this.attr('href');
const $target = $(href);
if ($target.length) {
e.preventDefault();
$this.siblings('a').removeClass('active');
$this.addClass('active');
$target.siblings('.tab-content').removeClass('active');
$target.addClass('active');
}
});
});
});
.tabs {
list-style-type: none;
margin: 5px 0 0 0;
padding: 0;
clear: both;
padding-bottom: 10px;
overflow: hidden;
}
.tabs a {
width: 20%;
display: inline-block;
height: 3em;
margin: 2px;
background: #eee;
font-size: 1em;
font-weight: bold;
line-height: 3em;
text-decoration: none;
color: #333;
text-align: center;
}
.tabs a.active {
background: #EC185D;
color: #fff;
}
.tabs-container.js .tab-content {
display: none;
padding: 1em;
font-size: 2em;
background: #eee;
border-radius: 2px;
}
.tabs-container.js .tab-content.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="container">
<div class="tabs">
<a href="#tab1" class="active">tab1</a>
<a href="#tab2">tab2</a>
<a href="#tab3">tab3</a>
<a href="#tab4">tab4</a>
</div>
<div class="tabs-container js"> <!-- note the 'js' class added here -->
<article id="tab1" class="tab-content active">
<div class="tab-text">
Content1
</div>
</article>
<article id="tab2" class="tab-content">
<div class="tab-text">
Content 2
</div>
</article>
<article id="tab3" class="tab-content">
<div class="tab-text">
Content 3
</div>
</article>
<article id="tab4" class="tab-content">
<div class="tab-text">
Content4
</div>
</article>
</div>
</div>
Upvotes: 0
Reputation: 4298
You can hide the content at initial load and show when the tabs are blinded,
below is updated code
$(function() {
$('.tabs-container').addClass('js');
$('.tabs').each(function() {
const $a = $(this).find('a');
$a.on('click', function(e) {
const $this = $(this);
const href = $this.attr('href');
const $target = $(href);
if ($target.length) {
e.preventDefault();
$this.siblings('a').removeClass('active');
$this.addClass('active');
$target.siblings('.tab-content').removeClass('active');
$target.addClass('active');
}
});
});
$('#container').show();
});
.tabs {
list-style-type: none;
margin: 5px 0 0 0;
padding: 0;
clear: both;
padding-bottom: 10px;
overflow: hidden;
}
.tabs a {
width: 20%;
display: inline-block;
height: 3em;
margin: 2px;
background: #eee;
font-size: 1em;
font-weight: bold;
line-height: 3em;
text-decoration: none;
color: #333;
text-align: center;
}
.tabs a.active {
background: #EC185D;
color: #fff;
}
.tabs-container.js .tab-content {
display: none;
padding: 1em;
font-size: 2em;
background: #eee;
border-radius: 2px;
}
.tabs-container.js .tab-content.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="container" style="display:none">
<div class="tabs">
<a href="#tab1" class="active">tab1</a>
<a href="#tab2">tab2</a>
<a href="#tab3">tab3</a>
<a href="#tab4">tab4</a>
</div>
<div class="tabs-container">
<article id="tab1" class="tab-content active">
<div class="tab-text">
Content1
</div>
</article>
<article id="tab2" class="tab-content">
<div class="tab-text">
Content 2
</div>
</article>
<article id="tab3" class="tab-content">
<div class="tab-text">
Content 3
</div>
</article>
<article id="tab4" class="tab-content">
<div class="tab-text">
Content4
</div>
</article>
</div>
</div>
Upvotes: 1