JavaScript and CSS tabs with smooth transition effect

I want to create tabs that smoothly fade between each other when switching. The code I have works, but there's a slight issue. When transitioning from one tab to the previous one, there is a momentary glitch where the last tab briefly changes state before fading.

The HTML:

function openSvc(evt, svc) {
  var i, x, tablinks, opacitys;
  x = document.getElementsByClassName("svc");
  for (i = 0; i < x.length; i++) {
    x[i].classList.remove('display-yes');
  }
  tablinks = document.getElementsByClassName("tablink");
  for (i = 0; i < x.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(svc).classList.add('display-yes');
  evt.currentTarget.className += " active";
}
.svc {
  opacity: 0;
  position: absolute;
  transition: .3s;
}

.display-yes {
  opacity: 1;
  position: relative;
}
<div class="tab">
  <button class="tablink" onclick="openSvc(event,'dev')"> Software Development </button>
  <button class="tablink active" onclick="openSvc(event,'it')"> IT Infrastructures </button>
  <button class="tablink" onclick="openSvc(event,'design')"> UX / UI Design </button>
  <button class="tablink" onclick="openSvc(event,'consult')"> Consultancy </button>
</div>

<div id="dev" class="svc display-yes">
  <p>lorem ipsum1

</div>

<div id="it" class="svc">
  <p>lorem ipsum2
</div>
<div id="design" class="svc">
  <p>lorem ipsum3

</div>

<div id="consult" class="svc">
  <p>lorem ipsum4

</div>

View the example here: https://jsfiddle.net/4fz01c2o/

Your assistance is greatly appreciated!

Answer №1

It's not entirely clear what type of effect you're aiming for in this scenario. While G-Cyrillus' solution does work, it appears that some of the fade effect is lost.

To maintain that effect, you should eliminate the position: relative rule that was assigned to .display-yes.

This rule was causing issues with the div's positioning. Therefore, you'll need to introduce a container with position: relative; to ensure the .svc divs stay in their designated places.

function openSvc(evt, svc) {
  var i, x, tablinks, opacitys;
  x = document.getElementsByClassName("svc");
  for (i = 0; i < x.length; i++) {
    x[i].classList.remove('display-yes');
  }
  tablinks = document.getElementsByClassName("tablink");
  for (i = 0; i < x.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(svc).classList.add('display-yes');
  evt.currentTarget.className += " active";
}
.svc-container {
  position: relative;
  width: 500px;
  height: 200px;
  margin-top: 1rem;
  background-color: lightblue;
}

.svc {
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
  transition: .3s;
}

.svc p {
  margin: 0; /* To be consistent with the next block*/
}

.display-yes {
  opacity: 1;
}

.tablink {
  background-color: blue;
}

.active {
  background-color: red;
}
<div class="tab">
  <button class="tablink active" onclick="openSvc(event,'dev')"> Desenvolvimento de software </button>
  <button class="tablink" onclick="openSvc(event,'it')"> Infraestruturas IT </button>
  <button class="tablink" onclick="openSvc(event,'design')"> UX / UI Design </button>
  <button class="tablink" onclick="openSvc(event,'consult')"> Consultoria </button>
</div>
<div class="svc-container">
  <div id="dev" class="svc display-yes">
  <p>lorem ipsum1</p>
  </div>
  <div id="it" class="svc">
    <p>lorem ipsum2</p>
  </div>
  <div id="design" class="svc">
    <p>lorem ipsum3</p>
  </div>
  <div id="consult" class="svc">
    <p>lorem ipsum4</p>
  </div>
</div>

<div style="width:500px; height:200px; background-color:#c2c2c2;">
  <p>
    lorem ipsum lorem ipsum
  </p>

</div>

Answer №2

There are various issues with your current approach: using position absolute for hidden elements can lead to display problems. I recommend creating a parent div with consistent size and color, where each tab is positioned absolutely inside.

Your question is somewhat unclear, but it seems like you want the next tab to fade in only after the previous one has finished fading out. To achieve this, you can use a transitionend event to detect when the fade-out animation completes.

I also suggest implementing event delegation for all tab buttons using data attributes in HTML, which can make your code more robust and reduce the amount of JavaScript required.

To test this code (with a one-second transition), consider:

const tabButtons = document.querySelector('div.tab')
  ,   buttonTabs = document.querySelectorAll('div.tab > button.tablink')
  ,   tabData    = [...document.querySelectorAll('div.svc')].reduce((res,eTab)=>
        {
        res.push( { id:eTab.id, disp:eTab.classList.contains('display-yes'), elm: eTab} )
        return res
        },[])

tabButtons.onclick =e=>
  {
  if (!e.target.matches('button.tablink'))   return // ignore other clicks outside 

  let currentTab = tabData.find(tb=>tb.disp)
    , newTab     = tabData.find(tb=>tb.id===e.target.dataset.tabId)   

  if (newTab.id != currentTab.id )
    {
    currentTab.elm.addEventListener('transitionend',setNewTab)
    currentTab.elm.classList.remove('display-yes')
    currentTab.disp = false

    buttonTabs.forEach(bt=>bt.classList.remove('active'))
    e.target.classList.add('active')
    }
  function setNewTab()
    {
    currentTab.elm.removeEventListener('transitionend',setNewTab)
    newTab.elm.classList.add('display-yes')
    newTab.disp = true
    }
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Pictures in Windows 7 have shifted to the left

After a recent migration to the Windows 7 operating system at my company, I encountered an issue. While using the same Visual Studio 2010 master file that was working fine on my Windows XP machine, I noticed that all the images below were now shifted to t ...

Error displaying component with react-router v5 not found

Currently, I am immersed in developing interactive dashboard web applications using ReactJS. I am utilizing React Routing to seamlessly navigate through the website's content. Here is a snapshot of my web application: https://i.sstatic.net/Ye8bH.png ...

Dealing with a jQuery/JavaScript issue involving thumbnail images

I am facing an issue with smooth transitions between thumbnail images in HTML list tags. I have Jquery listeners set up for mouseenter and mouseleave events that update a parent image when a thumbnail is hovered over. The problem arises when scrolling fro ...

"Encountered an issue with submitting the nodejs form

edit 2 After attempting to implement the following code snippet in my nodejs application, I encountered an issue where the form data was not being successfully posted to the database: router.get('/dashboard/users/forms/competition-form/:id', en ...

Please ensure to refresh the page after confirming the alert box by clicking OK

Is it possible to clear certain inputs on my Magento store's checkout page when an alert box is displayed and the user clicks OK? Unfortunately, I do not have control over the JavaScript alert. Therefore, I thought of implementing a script that can d ...

What is the best way to center align my button using CSS?

I'm struggling with aligning this button in CSS to the center: .btn { background-color: #44c767; -moz-border-radius: 28px; -webkit-border-radius: 28px; border-radius: 28px; border: 1px solid #18ab29; display: inline-block; cursor: poi ...

Issue with Heroku deployment: unable to locate JavaScript file

I encountered an issue while deploying my node.js app. Everything seemed to be working fine but it couldn't locate the JavaScript files. The error message displayed was: proove.herokuapp.com/:16 GET 404 (Not Found) Here is the server.js code snip ...

How to selectively disable buttons in a group using React

I am working with an array of data const projectTypeValues = [ { name: 'Hour', value: 'hour'}, { name: 'Day', value: 'day'}, { name: 'Session', value: 'session'}, { name: 'project', valu ...

Inscribe latitude from marker onto input field

Currently, I am working on a feature where markers are added to Google Maps API v3 by clicking on the map. Each marker then displays its coordinates in an info window. However, I am facing an issue with picking up the latitude and longitude values and inse ...

What is the process for implementing a component in antdesign when using vue-cli and vue 3?

I followed the instructions provided in the documentation here. These are the steps I took: vue create example-app cd example-app I selected the vue 3 preset. Then, I made changes to the script in main.js import Vue from 'vue'; import Button f ...

Using a zoom background image in an HTML document without any accompanying text

I am trying to create a zoom effect on a background image without affecting the text overlaying it. Here is the CSS code: .page1-box { width: 1200px; height:800px; overflow:hidden; } .page1 { width: 100%; height: 100%; background: ...

Methods for verifying if a file is included in another file, while disregarding any whitespace adjustments

Let's say I have multiple CSS files (a.css, b.css, ..., e.css) and after concatenating and compressing them, I get a new file called compressed.css. Now, I need to verify if each of the original CSS files is included in the compressed.css file. Are th ...

Troubleshooting: Why Your Angular Data Binding is Failing

I am integrating a WCF REST service with an AngularJS application. My goal is to retrieve account information based on the account number provided, however, I am encountering an issue where the text "Account_Type" is displayed three times before showing th ...

Traversing through data stored in a variable (JSON object)

Does anyone know how to loop through JSON data inside a variable? For example: var data = { $.each(data, function(i, item) { console.log(data[i].PageName); });​ ...

The TS2583 error in TypeScript occurs when it cannot locate the name 'Set' within the code

Just started my Typescript journey today and encountered 11 errors when running tsc app.ts. Decided to tackle them one by one, starting with the first. I tried updating tsconfig.json but it seems like the issue lies within node_modules directory. Any help ...

Developing and integrating views within a node-webkit desktop application

For my file copier desktop application built with node webkit, I aim to create a seamless flow where the initial check for existing profile data determines the first page displayed. The header with static links/buttons to various views remains consistent ...

Extract JSON data from a zipped file using adm-zip

Trying to extract and parse a JSON file named manifest.json from the root of a zip archive has been my current challenge. Regardless of the specific zip file being processed, the JSON file will always be named manifest.json. Presently, this function is w ...

I am working on customizing my WordPress website using three.js to add a background with a wireframe effect. However, I am facing difficulties in placing a sphere at the end of each line

I have a beautiful turquoise diamond and I want to incorporate a directional camera view in the background of a WordPress section. However, I am unsure how to achieve this. The issue I'm facing is that I created a wireframe over the diamond, but when ...

What is the best way to create an L shape using CSS?

I am currently working on achieving a unique style using CSS. https://i.sstatic.net/bJlok.png My progress so far: .file { width: 279px; height: 326px; background: linear-gradient(-135deg, transparent 66px, #A1A1A4 40px); position: relative; } ...

What is the best way to add content to a box once it has been hovered over?

Looking to create a sticky note-style design, but struggling with displaying the content inside the box only when hovered. In my code example below, can you help me achieve this effect? body { margin: 45px; } .box { display:inline-block; backgrou ...