user31782
user31782

Reputation: 7589

Why doesn't any css transtion work if elemnt is made display block from none?

Consider the following scenario:

$(".tab").click(function() {
  var position = $(this).index(".tabs .tab");  
  $(".content > div").removeClass("showing").removeClass("active");
  $(".content > div").eq(position).addClass("active");
  // active class makes display bock then without any delay opacity is changed by showing class
  $(".content > div").eq(position).addClass("showing");
});
.tabs {
  float: left;
  background: #ccc;
  margin-bottom: 10px;
}

.tab {
  float: left;
  border-right: 2px solid white;
  padding: 15px;
}

.content {
  float: left;
  width: 100%;
}

.content > div {
  padding: 15px;
  background: #999;
  transition: opacity 2s ease-out;
  opacity: 0;
  display: none;
}

.content > .active {
 display: block;
}

.content .showing {
  opacity: 1;
   
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tabs">
  <div class="tab1 tab">Tab1</div>
  <div class="tab2 tab">Tab2</div>
  <div class="tab3 tab">Tab3</div>
</div>

<div class="content">

  <div class="content1">
    Content 1
  </div>
  <div class="content2">
    content 2
  </div>
  <div class="content3">
    content 3
  </div>

</div>

Now when I click on any tab opacity is not transitioned. But if put a little delay between adding active and showing classes Then the tabs are transitioned well as:

$(".tab").click(function() {
  var position = $(this).index(".tabs .tab");  
  $(".content > div").removeClass("showing").removeClass("active");
  $(".content > div").eq(position).addClass("active").delay(10).queue(function(){
  	$(".content > div").eq(position).addClass("showing");
  });
  
  
});
.tabs {
  float: left;
  background: #ccc;
  margin-bottom: 10px;
}

.tab {
  float: left;
  border-right: 2px solid white;
  padding: 15px;
}

.content {
  float: left;
  width: 100%;
}

.content > div {
  padding: 15px;
  background: #999;
  transition: opacity 2s ease-out;
  opacity: 0;
  display: none;
}

.content > .active {
 display: block;
}

.content .showing {
  opacity: 1;
   
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tabs">
  <div class="tab1 tab">Tab1</div>
  <div class="tab2 tab">Tab2</div>
  <div class="tab3 tab">Tab3</div>
</div>

<div class="content">

  <div class="content1">
    Content 1
  </div>
  <div class="content2">
    content 2
  </div>
  <div class="content3">
    content 3
  </div>

</div>

Now after adding a delay from the point where content is displayed block the transitions work well. My questions are:

  1. Why don't transition work when opacity is changed directly with display propert? Why does transtion work when there is some delay between display block and opacity:1?
  2. If I put a delay of 0 seconds even then transition works correctly. why?

  3. In my second example if I quickly click tabs then the showing class no longer adds. why? And why does adding dequeue to $(".content > div").eq(position).addClass("showing"); solve this problem?

Upvotes: 1

Views: 91

Answers (1)

Rounin
Rounin

Reputation: 29453

To answer your headline question, not all CSS properties are animatable.

  • display is not animatable
  • opacity is animatable

Further Reading:

CSS Animated Properties by Mozilla Developer Network


For the sake of demonstration, here is an example of tabbed content fade-in and fade-out just using the CSS pseudo-class :target (obviating the need for any scripting in jQuery or javascript):

.tabbed-content {
position: relative;
}

a[class^="tab"] {
display: inline-block;
float: left;
height: 60px;
line-height: 60px;
margin-bottom: 10px;
padding: 0 15px;
color: #000;
background-color: #ccc;
border-right: 2px solid white;
text-decoration: none;
transition: background-color 1s ease-out;
}

div[id^="content"] {
position: absolute;
top: 62px;
left: 0;
width: 100%;
padding: 15px;
text-align: center;
font-size: 72px;
opacity: 0;
box-sizing: border-box;
transition: opacity 2s ease-out;
}

.tab1:hover,
#content1 {
color: rgb(255,255,255);
background-color: rgb(255,0,0);
}

.tab2:hover,
#content2 {
color: rgb(255,255,255);
background-color: rgb(0,127,0);
}

.tab3:hover,
#content3 {
color: rgb(0,0,0);
background-color: rgb(255,255,0);
}

div[id^="content"]:target {
opacity: 1; 
}
<div class="tabbed-content">
<a href="#content1" class="tab1">Tab1</a>
<a href="#content2" class="tab2">Tab2</a>
<a href="#content3" class="tab3">Tab3</a>

<div id="content1">
Content 1
</div>

<div id="content2">
Content 2
</div>

<div id="content3">
Content 3
</div>

</div>

Upvotes: 2

Related Questions