Home > Enterprise >  CSS Tabs - Slide effect / animation
CSS Tabs - Slide effect / animation

Time:12-01

I recreated simple tabs on my page through https://www.w3schools.com/howto/howto_js_tabs.asp

However, what im missing is a slide animation when clicking through the tabs.

I tried recreating these tabs: https://codepen.io/uklyumka/pen/wWWBdg

But since im working with prebuilt websites and plugins, the codepen code does not work and im not able to find an error.

The w3 tabs are working fine but as i said, im missing a slide effect / animation.

The slide effect im trying to achieve is the same as the one on codepen.

But since the w3 tabs are working perfectly fine for me and the codepen code does not even run on my site, i would like to apply the animation of codepen tabs onto my w3 tabs.

Glad for any help

function openCity(evt, cityName) {
  // Declare all variables
  var i, tabcontent, tablinks;

  // Get all elements with  and hide them
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i  ) {
    tabcontent[i].style.display = "none";
  }

  // Get all elements with  and remove the class "active"
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i  ) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }

  // Show the current tab, and add an "active" class to the button that opened the tab
  document.getElementById(cityName).style.display = "block";
  evt.currentTarget.className  = " active";
}
/* Style the tab */
.tab {
  overflow: hidden;
  border: 1px solid #ccc;
  background-color: #f1f1f1;
}

/* Style the buttons that are used to open the tab content */
.tab button {
  background-color: inherit;
  float: left;
  border: none;
  outline: none;
  cursor: pointer;
  padding: 14px 16px;
  transition: 0.3s;
}

/* Change background color of buttons on hover */
.tab button:hover {
  background-color: #ddd;
}

/* Create an active/current tablink class */
.tab button.active {
  background-color: #ccc;
}

/* Style the tab content */
.tabcontent {
  display: none;
  padding: 6px 12px;
  border: 1px solid #ccc;
  border-top: none;
}
<!-- Tab links -->
<div >
  <button  id="defaultopen" onclick="openCity(event, 'London')">London</button>
  <button  onclick="openCity(event, 'Paris')">Paris</button>
  <button  onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>

<!-- Tab content -->
<div id="London" >
  <h3>London</h3>
  <p>London is the capital city of England.</p>
</div>

<div id="Paris" >
  <h3>Paris</h3>
  <p>Paris is the capital of France.</p>
</div>

<div id="Tokyo" >
  <h3>Tokyo</h3>
  <p>Tokyo is the capital of Japan.</p>
</div>

CodePudding user response:

Compatibility

If you managed to run the W3School example on your site then you shouldn't have any problem running the Codepen example. Both examples use JavaScript, CSS, and HTML that's been stable and standard for years for all of the desktop browsers and all of the major mobile browsers as well. If your website restricted the use of the Codepen example, you should seriously consider an extensive update or better yet develop an entirely different site and abandon the old site all together. Most likely you have left something critical out when copying the code or placed it wrong within your site, etc.

Tab Component

The basic aspects of a tab component are:

  1. An interactive component that contains multiple sections of content. A reference to each section is usually stored in an array.
  2. Usually a single section is visible to the user at any given time. All sections with the exception of the current (active) section are hidden.
  3. A typical user interface comprises of a button to move to and from the sections (next and previous sections). A single click should hide the current section and show the section associated with the position within an array of sections which is determined by the user and/or interface.

Examples

  • Example A is a working version of the W3Schools and Codepen examples combined. Details are commented in the example.
  • Example B is an improved version of the Codepen example. It's fully responsive as well (desktop).

Example A

/*
|| Reference the <main>
|| Bind <main> to the "click" (e)vent, when <main> is clicked
|| invoke slide event handler (function)
*/
const main = document.querySelector("main");
main.onclick = slide;

/*
|| Event handler passes (e)vent object by default
|| Reverence the tag that the user clicked as >clicked<
|| If >clicked< is NOT "this" (<main>) AND >clicked< is a
|| <button>...
|| Collect all <button>s into a NodeList and convert it into an
|| array...
|| Collect all <article> into a NodeList and convert it into an
|| array...
|| Get the index number of >clicked<...
|| Remove .active class from each <button> and then add it to >clicked<...
|| Add the CSS property "transform: translateX()"
|| a negative value will move <section> to the left
|| a positive value will move <section to the right
|| the formula is -100 * (>index<)
|| Ex. The second <button> is >clicked< so >index< is 1
||     "transform: translateX(-100%)" will move <section>
||     to the left for the distance of the width of a 
||     <section> (100%)
|| In the example it is actually 103.33 instead of 100. I'm
|| not sure why but the 3.33% offset compensted for a pro-gressive
|| misalignment
*/
function slide(e) {
  const clicked = e.target;
  if (clicked != this && clicked.matches("button")) {
    const btnArray = Array.from(document.querySelectorAll("button"));
    const tabArray = Array.from(document.querySelectorAll("article"));
    let index = btnArray.indexOf(clicked);
    /*
    || See CSS #2
    */ // Remove .active class then add it to clicked <button>
    btnArray.forEach(btn => btn.classList.remove("active"));
    clicked.classList.add("active");
    document.querySelector("section").style.cssText = `
      transform: translateX(-${103.33 * index}%);`;
  }
}
body {
  margin: 0;
  font-family: Arial;
}

main {
  border: 1px solid #ccc;
  background-color: #fff;
  /* #1
  || Anything within <main> that extends beyond it's
  || border is hidden
  */
  overflow: hidden;
}

button {
  display: block;
  float: left;
  min-width: 120px;
  min-height: 25px;
  padding: 12px 16px;
  border: none;
  outline: none;
  font: inherit;
  font-size: 17px;
  background-color: inherit;
  cursor: pointer;
  transition: 0.3s;
}

button:hover {
  background-color: #ddd;
}

.active {
  /* #2
  || Indicates the tab that is currently visible
  */
  background-color: #ccc;
}

section {
  /* #3
  || All immediate children tags (<article>) will be side-by-side (inline)
  */
  display: flex;
  /* #3
  || <section> will be as wide as the content
  */
  min-width: max-content;
  margin: 0;
  /* #3
  || This determines the duration and pattern of animation
  */
  transition: 0.9s ease-in-out;
}

article {
  /* #4
  || Each <article> will be full width, but only one of them
  || will rver be visible since <main> obscures the rest of them
  */
  min-width: 100%;
  padding: 6px 12px;
  border: 1px solid #ccc;
  border-top: none;
}
<main>
  <!-- See CSS #1 -->
  <button >London</button>
  <button>Paris</button>
  <button>Tokyo</button>

  <section>
    <!-- See CSS #3 -->
    <article>
      <!-- See CSS #4 -->
      <h3>London</h3>
      <p>London is the capital city of England.</p>
    </article>

    <article>
      <!-- See CSS #4 -->
      <h3>Paris</h3>
      <p>Paris is the capital of France.</p>
    </article>

    <article>
      <!-- See CSS #4 -->
      <h3>Tokyo</h3>
      <p>Tokyo is the capital of Japan.</p>
    </article>
  </section>
</main>

Example B

const main = document.forms.main;

main.onsubmit = e => e.preventDefault();
main.onclick = slide;

function slide(e) {
  const io = this.elements;
  const btnArray = Array.from(io.btn);
  const clicked = e.target;

  if (clicked != this && clicked.name === "btn") {
    btnArray.forEach(btn => btn.classList.remove("active"));
    clicked.classList.add("active");
    let position = btnArray.indexOf(clicked);
    io.tabs.style.cssText = `transform: translateX(-${(100 * position)}%);`;
  }
}
*,
*::before,
*::after {
  box-sizing: border-box;
}

:root {
  font: 300 5vmin/1 "Segoe UI";
}

body {
  margin: 0;
  color: gold;
}

#main {
  width: 98%;
  margin: 0.5rem;
  padding: 0;
  overflow: hidden;
}

fieldset {
  min-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
}

#panel {
  display: flex;
}

#panel button {
  width: 4rem;
  height: 2.5rem;
  margin: 0;
  padding: 0;
  border-width: 1px 0.5px;
  border-bottom: 0;
  border-radius: 0;
  font: inherit;
  font-weight: 500;
  font-size: 1.25rem;
  font-variant: small-caps;
  cursor: pointer;
}

#panel button:first-of-type {
  border-right-width: 0.5px;
  border-top-left-radius: 6px;
}

#panel button:last-of-type {
  border-left-width: 0.5px;
  border-top-right-radius: 6px;
}

#tabs {
  display: flex;
  flex-flow: row nowrap;
  align-items: flex-start;
  position: relative;
  min-width: 100%;
  max-height: 16.5rem;
  padding: 0 0 0.75rem;
  transition: all .9s ease-in-out;
}

.content {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  position: relative;
  width: 100%;
  height: 16.75rem;
  border: 0;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.5);
}

.image {
  display: block;
  position: absolute;
  top: 0;
  max-width: 100%;
  height: 16.25rem;
}

.background {
  width: 100%;
  height: 100%;
}

legend {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  padding: 0.5rem;
  font-weight: 500;
  font-size: 2.25rem;
  line-height: 1.25;
  letter-spacing: 0.25rem;
  background: rgba(0, 0, 0, 0.5);
}

.text {
  position: absolute;
  z-index: 1;
  height: min-content;
  padding: 0.5rem 0.75rem;
  font-size: 1.25rem;
  line-height: 1.5;
  background: rgba(0, 0, 0, 0.5);
}

.caption .text {
  bottom: 0;
}

.full .text {
  top: 3.75rem;
}

legend:empty {
  display: none;
}

.full legend:empty~.text {
  top: 0;
}

.active {
  color: gold;
  background: rgba(0, 0, 0, 0.7);
}
<form id="main">
  <fieldset id="panel">
    <button name="btn" >Tab 1</button>
    <button name="btn">Tab 2</button>
    <button name="btn">Tab 3</button>
    <button name="btn">Tab 4</button>
  </fieldset>
  <fieldset id="tabs" >
    <fieldset name="tab" >
      <legend>Title I</legend>
      <object data="https://i.ibb.co/ftFqnQg/nightday.jpg" name="img" ></object>
      <output name="txt" >Text as content. The rest of this text is just filler. This filler is to test if text will successfully wrap around to the next line.</output>
    </fieldset>
    <fieldset name="tab" >
      <legend>Title II</legend>
      <object data="https://i.ibb.co/pKPKR1v/wall0.jpg" name="img" ></object>
      <output name="txt" >Caption</output>
    </fieldset>
    <fieldset name="tab" >
      <legend></legend>
      <object data="https://i.ibb.co/7tVNWLp/static.gif" name="img" ></object>
      <output name="txt" >Caption without title. Image is set to strech as background.</output>
    </fieldset>
    <fieldset name="tab" >
      <legend></legend>
      <object data="https://i.ibb.co/ZNjFRS4/matrix.gif" name="img" ></object>
      <output name="txt" >Text content without title. Image is set to strech as background.</output>
    </fieldset>
  </fieldset>
</form>

  • Related