skip to Main Content

I developed an HTML code and I intend to display the text related to each link with a fade-in animation when the link is clicked.

In this code, I have a card with two columns. The first column contains 5 links, and the second column contains 5 text elements wrapped in

tags. In the second column, only one

tag should be visible at a time.

When I don’t use the display style, all the

tags remain in the DOM, and the fade-in animation works correctly. However, all the text and

tags that are not related to the active link should not be displayed. For this purpose, when I use the display style, the fade-in animation doesn’t work properly.

const links = document.querySelectorAll('.links a');
const content = document.querySelectorAll('.content p');

function showContent(index) {
  links.forEach((link, i) => {
    if (i === index - 1) {
      link.classList.add('active');
    } else {
      link.classList.remove('active');
    }
  });

  content.forEach((c, i) => {
    if (i === index - 1) {
      c.classList.add('active');
    } else {
      c.classList.remove('active');
    }
  });
}
.container {
  display: flex;
  width: 80%;
  margin: 40px auto;
}

.links {
  width: 20%;
  background-color: #f0f0f0;
  padding: 20px;
}

.links a {
  text-decoration: none;
  color: #000;
  padding: 10px;
  display: block;
  border-bottom: 1px solid #ccc;
}

.links a.active {
  background-color: #ff4444;
  color: #fff;
}

.content {
  width: 80%;
  padding: 20px;
}

.content p {
  font-size: 18px;
  color: #333;
  opacity: 0;
  transition: opacity 0.5s ease-in-out;
  display: none;
}

.content p.active {
  display: block;
  opacity: 1;
}
<div class="container">
  <div class="links">
    <a href="#" class="active" onclick="showContent(1)">Link (1)</a>
    <a href="#" onclick="showContent(2)">Link (2)</a>
    <a href="#" onclick="showContent(3)">Link (3)</a>
    <a href="#" onclick="showContent(4)">Link (4)</a>
    <a href="#" onclick="showContent(5)">Link (5)</a>
  </div>
  <div class="content">
    <p id="content-1" class="active">Text related with Link (1)</p>
    <p id="content-2">Text related with Link (2)</p>
    <p id="content-3">Text related with Link (3)</p>
    <p id="content-4">Text related with Link (4)</p>
    <p id="content-5">Text related with Link (5)</p>
  </div>
</div>

3

Answers


  1. CSS has not supported animation of the display property until quite recently. Fortunately, all the major browsers now support transition-behavior: allow-discrete and @starting-style, which are the tools you need to solve this problem.

    document.querySelector('button').addEventListener('click', evt => {
      evt.target.closest('section').classList.toggle('active')
    })
    :root {
      --box-width: 60px;
    }
    
    body, button {
      font-family: sans-serif;
      font-size: 16px;
    }
    
    button {
      color: white;
      background: blue;
      border: 0;
      border-radius: 0.5em;
      padding: 0.5em 1em;
      cursor: pointer;
    }
    
    div {
      display: flex;
      gap: 0.5em;
    }
    
    span {
      color: white;
      background: red;
      width: var(--box-width);
      aspect-ratio: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: 0.7s;
    }
    
    .x {
      display: none;
      width: 0;
      opacity: 0;
      transition-behavior: allow-discrete;  
    }
    
    .active .x {
      display: flex;
      opacity: 1;
      width: var(--box-width);
      @starting-style {
        opacity: 0;
        width: 0;
      }
    }
    <section>
      <p><button>Toggle</button></p>
      <div>
        <span>1</span>
        <span class="x">2</span>
        <span>3</span>
      </div>
    </section>
    Login or Signup to reply.
  2. If your only concern is the way they are aligned, you could put the links and the content in the same container.

    const links = document.querySelectorAll('.links a');
        const content = document.querySelectorAll('.links p');
    
        function showContent(index) {
          links.forEach((link, i) => {
            if (i === index - 1) {
              link.classList.add('active');
            } else {
              link.classList.remove('active');
            }
          });
    
          content.forEach((c, i) => {
            if (i === index - 1) {
              c.classList.add('active');
            } else {
              c.classList.remove('active');
            }
          });
        }
    .container {
          display: flex;
          width: 80%;
          margin: 40px auto;
        }
        .links {
          width: 100%;
          padding: 20px;
        }
        .links a {
          display: flex;
          align-items: center;
          text-decoration: none;
          background-color: #f0f0f0;
          color: #000;
          padding: 10px;
          border-bottom: 1px solid #ccc;
        }
        .links a.active {
          background-color: #ff4444;
          color: #fff;
        }
        .links p[id^='content'] {
          width: 80%;
          padding: 5px 10px;
        }
        .links p {
          font-size: 18px;
          color: #333;
          opacity: 0;
          transition: opacity 0.5s ease-in-out;
        }
        .links p.active {
          display: block;
          opacity: 1;
        }
        .link-wrapper {
          display: flex;
        }
    <div class="container">
        <div class="links">
          <div class="link-wrapper">
            <a href="#" class="active" onclick="showContent(1)">Link (1)</a>
            <p id="content-1" class="active">Text related with Link (1)</p>
          </div>
    
          <div class="link-wrapper">
            <a href="#" onclick="showContent(2)">Link (2)</a>
            <p id="content-2">Text related with Link (2)</p>
          </div>
    
          <div class="link-wrapper">
            <a href="#" onclick="showContent(3)">Link (3)</a>
            <p id="content-3">Text related with Link (3)</p>
          </div>
         
          <div class="link-wrapper">
            <a href="#" onclick="showContent(4)">Link (4)</a>
            <p id="content-4">Text related with Link (4)</p>
          </div>
    
          <div class="link-wrapper">
            <a href="#" onclick="showContent(5)">Link (5)</a>
            <p id="content-5">Text related with Link (5)</p>
          </div>
        </div>
      </div>
    Login or Signup to reply.
  3. Using opacity should be fine in this case. I changed the function a bit, so that it is only the anchor that gets a new class name. The content is shown using a CSS selector where I combine :has() with the next-sibling combinator.

    const links = document.querySelector('.links');
    
    links.addEventListener('click', e => {
      e.preventDefault();
      if (e.target.nodeName == 'A') {
        let id = e.target.getAttribute('href');
        showContent(id);
      }
    });
    
    function showContent(id) {
      links.querySelectorAll('a').forEach(link => link.classList.remove('active'));
      links.querySelector(`a[href="${id}"]`).classList.add('active');
    }
    .container {
      display: flex;
      width: 80%;
      margin: 40px auto;
    }
    
    .links {
      width: 20%;
      background-color: #f0f0f0;
      padding: 20px;
    }
    
    .links a {
      text-decoration: none;
      color: #000;
      padding: 10px;
      display: block;
      border-bottom: 1px solid #ccc;
    }
    
    .links a.active {
      background-color: #ff4444;
      color: #fff;
    }
    
    .content {
      width: 80%;
      padding: 20px;
      position: relative;
    }
    
    .content p {
      font-size: 18px;
      color: #333;
      transition: opacity 0.5s ease-in-out;
      position: absolute;
      top: 0;
    }
    
    div.links:has(a)+div.content>p {
      opacity: 0;
    }
    
    div.links:has(a.active[href="1"])+div.content>#content-1,
    div.links:has(a.active[href="2"])+div.content>#content-2,
    div.links:has(a.active[href="3"])+div.content>#content-3,
    div.links:has(a.active[href="4"])+div.content>#content-4,
    div.links:has(a.active[href="5"])+div.content>#content-5 {
      opacity: 1;
    }
    <div class="container">
      <div class="links">
        <a href="1" class="active">Link (1)</a>
        <a href="2">Link (2)</a>
        <a href="3">Link (3)</a>
        <a href="4">Link (4)</a>
        <a href="5">Link (5)</a>
      </div>
      <div class="content">
        <p id="content-1" class="active">Text related with Link (1)</p>
        <p id="content-2">Text related with Link (2)</p>
        <p id="content-3">Text related with Link (3)</p>
        <p id="content-4">Text related with Link (4)</p>
        <p id="content-5">Text related with Link (5)</p>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search